/*
 * Copyright (c) 2003-2005  Tom Wu
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
 *
 * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
 * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 * In addition, the following condition applies:
 *
 * All redistributions must retain an intact copy of this copyright notice
 * and disclaimer.
 */


// Depends on jsbn.js and rng.js

// Hex String in BigInteger umwandeln

function parseBigInt( hexStringValue, radix ) 
{
	return ( new BigInteger( hexStringValue, radix ) );
}

// Konstruktor fuer ein leeres RSA Objekt

function RSAKey() 
{
	this.n     = null;
	this.e     = 0;
	this.d     = null;
	this.p     = null;
	this.q     = null;
	this.dmp1  = null;
	this.dmq1  = null;
	this.coeff = null;
	
	this.setPublicKeyValues = setPublicKeyValues;
	this.doEncrypt          = doEncrypt;
	this.encrypt            = encrypt;
}

// RSA Funktionen

// Setzen von n und e (oeffentlicher Schluessel) in hex

function setPublicKeyValues( n_value, e_value ) 
{
	if ( ( n_value != null ) && ( e_value != null ) && 
	     ( n_value.length > 0 ) && ( e_value.length > 0 ) ) 
	{
		this.n = parseBigInt( n_value, 16 );
		this.e = parseInt( e_value, 16 );
	}
	else
	{
		alert( "Invalid public key values n: " + n_value + ", e: " + e_value );
	}
}

// Verschluesseln eines Textes mit dem derzeitigen Schluessel

function encrypt( text ) 
{
	var encryptedMessage = null;
		
	var message = pkcs1pad2( text, ( this.n.bitLength() + 7 ) >> 3 );
		
	if( message != null ) 
	{ 
		var cipher = this.doEncrypt( message );
				
		if( cipher != null ) 
		{
			var hexCipher = cipher.toString(16);
			
			if( ( hexCipher.length & 1) == 0 ) 
			{
				encryptedMessage = hexCipher;
			}
			else 
			{
				encryptedMessage = "0" + hexCipher;
			}
		}
	}
	
	return ( encryptedMessage );
}

// Basisoperation zum Verschluesseln: x^e (mod n)

function doEncrypt( x ) 
{
	return ( x.modPowInt( this.e, this.n ) );
}

// PKCS#1 (type 2, random) pad input string s to n bytes, and return a bigint

function pkcs1pad2(inputString, n_bytes) 
{
	var returnValue = null;
	
	if( n_bytes < inputString.length + 11 )
	{
		alert("Message too long for RSA");
	}
	else
	{
		var byteArray = new Array();
		
		var index = inputString.length - 1;
		
		while( ( index >= 0 ) && ( n_bytes > 0 ) ) 
		{
			byteArray[--n_bytes] = inputString.charCodeAt( index-- );
		}
		
		byteArray[--n_bytes] = 0;
		
		var secureRandom = new SecureRandom();
		
		var tempArray = new Array();
		
		while( n_bytes > 2 ) 
		{ 
			tempArray[0] = 0; // random non-zero pad
		
			while( tempArray[0] == 0 )
			{
				 secureRandom.nextBytes( tempArray );
			}
		
			byteArray[--n_bytes] = tempArray[0];
		}
		
		byteArray[--n_bytes] = 2;
		byteArray[--n_bytes] = 0;
		
		returnValue = new BigInteger( byteArray );
	}
	
	return ( returnValue );
}