// This script is (c) copyright 2006 Jim Tucek under the
// GNU General Public License (http://www.gnu.org/licenses/gpl.html)
// For more information, visit www.jracademy.com/~jtucek/email/ 
// Leave the above comments alone!

var decryption_cache = new Array();

function decrypt_string(crypted_string,n,decryption_key,just_email_address) {
	var cache_index = "'"+crypted_string+","+just_email_address+"'";

	if(decryption_cache[cache_index])					// If this string has already been decrypted, just
		return decryption_cache[cache_index];				// return the cached version.

	if(addresses[crypted_string])						// Is crypted_string an index into the addresses array
		var crypted_string = addresses[crypted_string];			// or an actual string of numbers?

	if(!crypted_string.length)						// Make sure the string is actually a string
		return "Error, not a valid index.";

	if(n == 0 || decryption_key == 0) {					// If the decryption key and n are not passed to the
		var numbers = crypted_string.split(' ');			// function, assume they are stored as the first two
		n = numbers[0];	decryption_key = numbers[1];			// numbers in crypted string.
		numbers[0] = ""; numbers[1] = "";				// Remove them from the crypted string and continue
		crypted_string = numbers.join(" ").substr(2);
	}

	var decrypted_string = '';
	var crypted_characters = crypted_string.split(' ');

	for(var i in crypted_characters) {
		var current_character = crypted_characters[i];
		var decrypted_character = exponentialModulo(current_character,n,decryption_key);
		if(just_email_address && i < 7)				// Skip 'mailto:' part
			continue;
		if(just_email_address && decrypted_character == 63)	// Stop at '?subject=....'
			break;
		decrypted_string += String.fromCharCode(decrypted_character);
	}
	
	decryption_cache[cache_index] = decrypted_string;			// Cache this string for any future calls

	return decrypted_string;
}

function decrypt_and_email(crypted_string,n,decryption_key) {
	if(!n || !decryption_key) { n = 0; decryption_key = 0; }
	if(!crypted_string) crypted_string = 0;

	var decrypted_string = decrypt_string(crypted_string,n,decryption_key,false);
	parent.location = decrypted_string;
}

function decrypt_and_echo(crypted_string,n,decryption_key) {
	if(!n || !decryption_key) { n = 0; decryption_key = 0; }
	if(!crypted_string) crypted_string = 0;

	var decrypted_string = decrypt_string(crypted_string,n,decryption_key,true);
	document.write(decrypted_string);
	return true;
}

// Finds base^exponent % y for large values of (base^exponent)
function exponentialModulo(base,exponent,y) {
	if (y % 2 == 0) {
		answer = 1;
		for(var i = 1; i <= y/2; i++) {
			temp = (base*base) % exponent;
			answer = (temp*answer) % exponent;
		}
	} else {
		answer = base;
		for(var i = 1; i <= y/2; i++) {
			temp = (base*base) % exponent;
			answer = (temp*answer) % exponent;
		}
	}
	return answer;
}
// -->


// <!-- Quick! Hide the java!

// Speaking of Java, this particular script is (C) Copyright 2006 Jim Tucek
// This script is NOT for public use.  I'm working on a general RSA encryption
// script, so be patient!  This is not the script that decrypts an email so that
// spam bots can't find it.  This is the script that makes that script!
// (Wow, code that writes code.  Not that big of a deal really)

// Visit www.jracademy.com/~jtucek/email/ for script information or 
// www.jracademy.com/~jtucek/email/contact.php for contact information.

// A brief history of this script can be found (and it's rather entertaining)
// at www.jracademy.com/~jtucek/email/

var primes = new Array();
var i = 0; primes[i++] = 2; primes[i++] = 3; primes[i++] = 5; primes[i++] = 7; 
primes[i++] = 11; primes[i++] = 13; primes[i++] = 17; primes[i++] = 19; primes[i++] = 23; 
primes[i++] = 29; primes[i++] = 31; primes[i++] = 37; primes[i++] = 41; primes[i++] = 43; 
primes[i++] = 47; primes[i++] = 53; primes[i++] = 59; primes[i++] = 61; primes[i++] = 67; 
primes[i++] = 71; primes[i++] = 73; primes[i++] = 79; primes[i++] = 83; primes[i++] = 89; 
primes[i++] = 97; primes[i++] = 101; primes[i++] = 103; primes[i++] = 107; primes[i++] = 109; 
primes[i++] = 113; primes[i++] = 127; primes[i++] = 131; primes[i++] = 137; primes[i++] = 139; 
primes[i++] = 149; primes[i++] = 151; primes[i++] = 157; primes[i++] = 163; primes[i++] = 167; 
primes[i++] = 173; primes[i++] = 179; primes[i++] = 181; primes[i++] = 191; primes[i++] = 193; 
primes[i++] = 197; primes[i++] = 199; 

// Pick some primes for the user
function lazyBum() {
	var size = primes.length;
	var p;	var q;	var qI;	var pI;

	do {
		qI = Math.round(Math.random() * size);
		pI = Math.round(Math.random() * size);
		p = primes[pI];
		q = primes[qI];
	} while(p == q || p*q < 255);

	document.form.Q.selectedIndex = qI;
	document.form.P.selectedIndex = pI;

	document.form.N.value = p * q;
	document.form.P2.value = p;
	document.form.Q2.value = q;
}

// Debugging code, to double check the script
function testAll() {
	var size = primes.length;
	window.alert("Testing for " + size + " prime numbers...  Please wait.");

	var allCharacters = "";
	for(var c = 33; c <= 126; c++)
		allCharacters = allCharacters + String.fromCharCode(c);

	document.form.Message.value = allCharacters;

	for(var i = 0; i < size - 1; i++) {
		for(var j = i + 1; j < size; j++) {
			var p = primes[i];
			var q = primes[j];
			if(p*q < 255)
				break;
			makeKey(p,q);
			var encrypted = document.form.encrypted.value;
			document.form.P2.value = p;
			document.form.Q2.value = q;
			var d = document.form.D.value;
			var decrypted = goForth(encrypted,p*q,d);
			document.form.decrypted.value  = decrypted;
			if(decrypted != allCharacters) {
				window.alert("Encryption/Decryption error when (p,q) = ("+p+","+q+")");
				return;
			}
		}
	}
	window.alert("Done, no errors detected.");
}

var addresses = new Array();

function makeKey(p,q) {
	// Make sure the user didn't do anything stupid:
	//document.form.decrypted.value = "";
	addresses = new Array();

	if(p * q < 255)
		window.alert("P*Q must be greater than 255! P*Q = " + p*q);
	else if(p == q)
		window.alert("P cannot be equal to Q!");
	else if(document.form.Message.value == "") 
		window.alert("You must enter an address to encrypt!");
	else {
		// Make the key
		var c = 0;
		var z = (p-1)*(q-1);
		var e = 0;
		var n = p*q;
		var d;

		do {
			e++;
			d = getKey(primes[e],z);
		} while(d==1);
		e = primes[e];
	
		// Split up each line of email addresses
		var lines = document.form.Message.value.split('\n');
		
		// Turn each string into an array of numbers < 255
		for(lineNumber in lines) {
			if(!lines[lineNumber].length || lines[lineNumber].length < 2)
				continue;

			var m = "mailto:" + lines[lineNumber];
			var emailLength = m.length;
		
			if(document.form.Subject.value != "")
				m = m + "?subject=" + document.form.Subject.value;

			var length = m.length;
			theString = new Array(length);
			for(var i = 0; i < length; i++)
				theString[i] = m.charCodeAt(i);
	
			// Encrypt each of the numbers
			c = "";
			for(i = 0; i < length; i++) {
				if(i != 0)
					c+= " ";
				c += myMod(theString[i],e,n);
			}

			// Save this line
			addresses.push(c);
		}
		c = "";
		for(i in addresses) {
			c += addresses[i];
			if(i < addresses.length - 1)
				c += "\n";
		}

		document.form.N.value = n;
		document.form.D.value = d;
		document.form.E.value = e;
		document.form.C.value = c;
		document.form.encrypted.value = 'javascript:decrypt_and_email(\'' + n + ' ' + d + ' ' + c + '\');'
	}
}

// Finds x^e % y for large values of (x^e)
function myMod(x,e,y) {
	if (e % 2 == 0) {
		var answer = 1;
		for(var i = 1; i <= e/2; i++) {
			var temp = (x*x) % y;
			answer = (temp*answer) % y;
		}
	} else {
		var answer = x;
		for(var i = 1; i <= e/2; i++) {
			var temp = (x*x) % y;
			answer = (temp*answer) % y;
		}
	}
	return answer;
}


function goForth(c,n,d) {
	document.form.HTMLCode.value = "No code generated yet!";
	document.form.decrypted.value = "Working...";

	var lines = c.split("\n");
	var answer = "";
	for(i in lines) {
		answer += decrypt_string(lines[i],n,d,true);
		if(i < lines.length - 1)
			answer += "\n";
	}

	return answer;
}



// Euclid's Algorithm for finding a good key
function getKey(e,z) {
	A = 1;B = 0;C = z;F = 0;G = 1;bar = e;    
	while (bar != 0) {
		 foo = Math.floor(C/bar);
		 K = A - foo * F;
		 L = B - foo * G;
		 M = C - foo * bar;
		 A = F;B = G;C = bar;
		 F = K;G = L;bar = M;
	}
	if (B < 0)
		return (B + z);
	else
		  return (B);
}


function writeOptions() {
	var size = primes.length;
	for(i = 0; i < size; i++)
		document.write("<option value=\""+primes[i]+"\">"+primes[i]+"</option>");
}

// Stop hiding script -->
