function makeHash()
{
	//Create an SHA-1 hash as a digital signature for the text
	var plaintext = document.getElementById("inputtext").value;
	//Check to see if this text was hashed before.
	var beforepos = plaintext.indexOf("\n---SHA-1 signature---\n");
	if (beforepos > 0) {
		var beforetext = plaintext.slice(0,beforepos);
		var hash = hex_sha1(beforetext);
		document.getElementById("outputtext").value = plaintext + "\n" + hash +"\n Compare above signatures for evidence of tampering"
	} else {
		//Plain text - just sign it.
		var hash = hex_sha1(plaintext);
		document.getElementById("outputtext").value = plaintext + "\n---SHA-1 signature---\n"+ hash;
	}
}

function makeKey()
{
	//Create a random AES key. It must be 32 Hex chars long
	var key = '';
	for (i=0,33;i<33;i++)
	{
		var randomnumber=Math.floor(Math.random()*16);
		if (randomnumber <= 9 ) {
			key = key + randomnumber;
		} else if (randomnumber == 10) {
			key = key + 'A';
		} else if (randomnumber == 11) {
			key = key + 'B';
		} else if (randomnumber == 12) {
			key = key + 'C';
		} else if (randomnumber == 13) {
			key = key + 'D';
		} else if (randomnumber == 14) {
			key = key + 'E';
		} else {
			key = key + 'F';
		}
	}
	return key;
}

function RSAEncrypt()
{

	var plainmsg = document.getElementById("inputtext").value;

	var bb = '10'; //bigint base;

	//Generate a key for the AES encryption process
	var AESkey = makeKey();
	//GM_log("Plain AES key " + AESkey);
	//Encrypt the email
	var aes_text = aes_encrypt(AESkey, plainmsg);

	//Encrypt the key using RSA
	var plaintext = AESkey;

	//Grab the public key 
	var keyspot = document.getElementById("pubkeytext");
	var key = keyspot.value;
	var keys = key.split(":");

	var keymax = keys.length;
	keymax = keymax - 1;
	var keyE = keys[keymax];
	keymax = keymax - 1;
	var keyN = keys[keymax];


	//make the keys "big"
	var bigkeyN = int2bigInt(keyN,20);
	var bigkeyE = int2bigInt(keyE,20);

	//Encrypt the text
	var etext = '';
	while (plaintext.length > 0) 
	{
		var plainnum = getpnum(plaintext,5);

	
		//Check to see if this number is too large to encrypt
		if (greater(plainnum, bigkeyN)) {
			alert("This text cannot be encrypted using keys this small");
			return;
		}	

		var ciphernum = str2bigInt('0',bb,0);
		ciphernum = powMod(plainnum, bigkeyE, bigkeyN);

		if (etext == '') {
			etext = bigInt2str(ciphernum,bb);
		} else {
			etext = etext.concat(';', bigInt2str(ciphernum,bb));
		}
		
		//Cut off the first 5 chars of the string
		plaintext = plaintext.slice(5);
	}

	//GM_log("RSA key " + etext);

	//Combine the RSA encrypted key with the AES encryption
	etext = etext + ':' + aes_text;

	//Mark the text as encrypted so that we know were to start and end with the
	//decryption process
	etext = "--- Start of mailencrypt --- " + etext + " --- End of mailencrypt ---";

	//Return the encrypted text 
	//GM_log("Fully encrypted email " + etext);
	document.getElementById("outputtext").value = etext;
	return etext;

}

function RSAdecryptText() {
	//This is called by the decrypt button and gets all the pieces
	//of the process together to call the RSA decryption process

	var bb = '10'; //bigint base;

	//Find the place where the text is stored
	var plaintext = document.getElementById("inputtext").value;

	//Grab the private key 
	var keyspot = document.getElementById("privkeytext");
	var key = keyspot.value;
	//Split this key into the various components
	var keys = key.split(":");
	var keymax = keys.length;

	//The last value is the D component
	keymax = keymax - 1;
	var keyD = keys[keymax];
	//Second last part is the N component
	keymax = keymax - 1;
	var keyN = keys[keymax];

	//Make the keys big
	var bigkeyN = str2bigInt(keyN,bb,0);
	var bigkeyD = str2bigInt(keyD,bb,0);

	// Strip out all the "> " indendation characters from the message
	//Only strip the chars for plaintext messages
	var beforepos = 1;
	beforepos = plaintext.indexOf("<div>"); //check for html
	if (beforepos <= 0 ) {
		beforepos = 1;
		while ( beforepos > 0 ) {
			beforepos = plaintext.indexOf(">");
			if ( beforepos > 0 ) {
				var afterpos = beforepos + 1;
				plaintext = plaintext.slice(0,beforepos) + plaintext.slice(afterpos);
			} 
		}
	}


	//find the encrypted part of the email
	var beforepos = plaintext.indexOf("--- Start of mailencrypt ---");
	var afterpos = plaintext.indexOf(" --- End of mailencrypt ---");
	if ( beforepos > 0 ) {
		var beforetext = plaintext.slice(0,beforepos);
	} else {
		var beforetext = "";
	}
	if ( afterpos > 0 ) {
		var aftertext = plaintext.slice(afterpos + 27);
	} else {
		var aftertext = "";
	}
	plaintext = plaintext.slice(beforepos + 29, afterpos);

	//split the encrypted email into the key and the AES encrypted portion
	var etexts = plaintext.split(":");

	//the first text is the key which we need to decrypt using RSA
	var ptexts = etexts[0].split(";");

	
	var i = 0;
	var dtext = '';
	var tmptext = '';
	while ( i < ptexts.length )
	{
		//Turn the ciphertext number into a plaintext number
		var ciphernum = str2bigInt(ptexts[i],bb,0); 
		if (greater(ciphernum, bigkeyN)) {
			addmsg(ptexts[i]);
			addmsg(bigInt2str(bigkeyN,bb));
			alert("This text cannot be decrypted using keys this small");
			return;
		}	


		var plainnum = powMod(ciphernum, bigkeyD, bigkeyN); 
		tmptext = bigInt2str(plainnum,'16'); //use base 16 to convert to hex
		tmptext = pad(tmptext,5);
		if (dtext == '') {
			dtext = tmptext;
		} else {
			dtext = dtext.concat(tmptext);
		}

		i = i + 1;
	}

	//chop off the padding at the end of the string
	dtext = dtext.slice(0,dtext.length-3);

	//Now decrypt the email body using AES
	var finaltxt = aes_decrypt(dtext, etexts[1]);
	//Place the other parts of the text back around it again
	finaltxt = beforetext + finaltxt + aftertext;
	document.getElementById("outputtext").value = finaltxt;
	return finaltxt;
	//GM_log("Decrypted email " + finaltxt);
} //RSAdecrypttext

function aes_encrypt(key, plainmsg)
{
   var w = new Array( 44 );			// subkey information
   var state = new Array( 16 );			// working state
   var round;
   var finalstr = "";
   var msg = "";

	//Grab the text to encrypt
	var longmsg = plainmsg;
	//GM_log("AES Unencrypted " + longmsg);

	//check the key
	if ( key[0] < 0 )
	{
		alert("There is a problem with the key");
		return;
	}

	// expand the key
	key = hexTo16(key);
	w = key_expand( key );

	while (longmsg.length > 0 )
	{
		msg = longmsg.slice(0,16);
		longmsg = longmsg.slice(16);

		while (msg.length < 16) {
			msg += " ";
		}
		
		msg = ascTo16(msg);

		// problems??
		if ( msg[0] < 0 )
		{
			alert("There is a problem with the message");
			return;
		}


		// initial state = message in columns (transposed from what we input)
		state = transpose( msg );

		state = AddRoundKey(state, w, 0);

		for( round=1; round<10; round++ )
		{
			state = SubBytes(state, S_enc);
			state = ShiftRows(state);
			state = MixColumns(state);
			// note here the spec uses 32-bit words, we are using bytes, so an extra *4
			state = AddRoundKey(state, w, round*4*4);
		}

		SubBytes(state, S_enc);
		ShiftRows(state);
		AddRoundKey(state, w, 10*4*4);

		// process output
		AES_output = transpose( state );
		var tmpstr = format_AES_output(AES_output, "hex");
		if (finalstr == "") {
			finalstr = tmpstr;
		} else {
			finalstr = finalstr + "$" + tmpstr;
		}
	}

	//GM_log("AES Encrypted " + finalstr);

	return finalstr;

}//aes_encrypt

// do AES decryption
function aes_decrypt(key, bodytext)
{
   var w = new Array( 44 );			// subkey information
   var state = new Array( 16 );			// working state
   var round;
   var finalstr = "";
   var msg = "";

   // get the message from the user
	if (bodytext == '') {
		var longmsg = document.getElementById(loc).contentWindow.document.body.innerHTML;
	} else {
		var longmsg = bodytext;
	}

	//check the key
	if ( key[0] < 0 )
	{
		alert("There is a problem with the key");
		return;
	}

	// expand the key
	key = hexTo16(key);
	w = key_expand( key );

	var multmsg = longmsg.split("$");

	var i = 0;
	while (i < multmsg.length)
	{
		msg = hexTo16(multmsg[i]);

		// problems??
		if ( msg[0] < 0 )
		{
			alert("There is a problem with the message")
			return;
		}

		// initial state = message
		state = transpose( msg );

		state = AddRoundKey(state, w, 10*4*4);

		for( round=9; round>=1; round-- )
		{
			state = InvShiftRows(state);
			state = SubBytes(state, S_dec);
			// note here the spec uses 32-bit words, we are using bytes, so an extra *4
			state = AddRoundKey(state, w, round*4*4);
			state = InvMixColumns(state);
		}

		InvShiftRows(state);
		SubBytes(state, S_dec);
		AddRoundKey(state, w, 0);

		// process output
		AES_output = transpose( state );
		var tmpstr = format_AES_output(AES_output, "asc");
		if (finalstr == "") {
			finalstr = tmpstr;
		} else {
			finalstr = finalstr + tmpstr;
		}

		i += 1;
	}

	//GM_log("AES Decrypted " + finalstr);

	return finalstr;
}//aes_decrypt


function mypow(base, exp)
{
	//I didn't find a regular exponentiation function in bigInt
	//so I had to put together this homegrown version
	//This function is missing some error checks, etc, but
	//it works for this purpose

	//Special checks
	if (exp < 1) {
		return str2bigInt('1','10',0);
	}
	if (exp == 1){
		return base;
	}

	var orig = base;
	var origexp = exp;

	//Precalculate some values to cut down on the number of loops
	var val2 = mult(base, base);
	var val4 = mult(val2, val2);
	var val16 = mult(val4, val4);

	var myval = val2;
	var expcount = 2;
	
	while (1>0)
	{
		//prevent long processes from killing the system
		if (exp > 512) {
			alert("Exponent count " + expcount + " -> original " + origexp);
		}
		if (expcount * 2 <= origexp)
		{
			myval = mult(myval, myval);
			expcount = expcount * 2;
		} else {
			var diff = origexp - expcount;
			if (diff>=16) {
				myval = mult(myval,val16);
				expcount = expcount + 16;
				continue;
			}
			if (diff>=4) {
				myval = mult(myval,val4);
				expcount = expcount + 4;
				continue;
			}
			if (diff>=2) {
				myval = mult(myval,val2);
				expcount = expcount + 2;
				continue;
			}
			if (diff==1) {
				myval = mult(myval,orig);
				expcount = expcount + 1;
				continue;
			}
			if (diff<1) {
				return myval;
			}

		}
	}

}

function getpnum(ptext,n)
{
	//convert the plain text into a number
	var bb = '10'; //bigInt base
	var thenum = str2bigInt('0',bb,0);
	var hexbase = str2bigInt('16',bb,0);
	var cval, expval;
	//Grab "n" number of chars from the string to encrypt
	while (ptext.length < n) {
		ptext = ptext.concat('0');
	}

	for (i=0,n;i<n;i++)
	{
		expval = n - (i + 1);
		//Adjust the ASCII codes down so that 0 has
		//a value of 2
		var ccode = ptext.charCodeAt(i);
		//0 has an ASCII value of 48
		//9 = 57, A = 65, F = 70
		if (ccode >=48 && ccode <= 57) {
			ccode = ccode - 48;
		} else {
			ccode = ccode - 55;
		}

		cval = int2bigInt(ccode,0);
		var power = mypow(hexbase, expval );
		cval = mult(cval, power);
		thenum = add(thenum, cval);
	}

	return thenum;
}  //getpnum

function pad(ustr, n) {
	//Pad the ustr to make sure it is "n" chars long
	//this will catch numbers with leading zeroes
	while (ustr.length < n) {
		ustr = '0' + ustr;
	}
	return ustr;
} //pad


function clearmsg() {
  document.getElementById("msgtext").innerHTML = "";
}

function addmsg(ntext) {
  var xtext = document.getElementById("msgtext").innerHTML;
  xtext = xtext + "\n" + ntext;
  document.getElementById("msgtext").innerHTML = xtext;

}

