/*(c) 2006 - 2008 AllenPort Co. All Rights Reserved.
All versions of this code, including the source and executable versions, 
constitute the intellectual property of AllenPort Co., which expressly reserves 
any and all U.S. and foreign rights and benefits to the code under copyright, 
trade secret and any other intellectual property law or international treaty 
whatsoever. Use of the code is subject to the terms and conditions of a separate 
written license agreement, and the code shall not be reproduced, modified, distributed 
or otherwise used in any form or manner whatsoever without obtaining the prior written 
permission of AllenPort Co. Any unauthorized reproduction or distribution of the code, 
or any portion of it, may result in civil and criminal penalties and be prosecuted 
to the fullest extent of the law.*/
/*
 * 	Distinguished Encoding Rules (DER)
 */

//document.write('<script src="rsa2.js" type="text/javascript"></script>');
var rsaKeysArr;
var der = "";

//rsaKey   [RSAKey]- object representating RSA.
//isPublic [boolean] - identifies whar part (public or private)of rsaKey to encode.
//return   [String] - string of (public or private) part of rsaKey in der format.
function rsa_to_der_format(rsaKey, isPublic)
{
	//Initializes rsaKeysArr (n e d p q dmp1 dmq1 coeff)
	init(rsaKey);
	
	der = "";
	var public_key;
	
	if(!isPublic)
	{
	    //Make private part
		make_data(isPublic);
		//public_key = make_data(!isPublic);	
		//alert("isPublic=" +  isPublic + " der=" + der);
	}
	else
	{
	     //Make public part
		public_key = make_data(isPublic);
		var public_key_length = get_num_bytes(public_key);//00
		var num_size_bytes = make_size(public_key_length);
		der = "03" + ((num_size_bytes==0)?(add_leading_zero(public_key_length+1).toString(16)):(num_size_bytes.toString(16) + add_leading_zero(public_key_length+1).toString(16))) + "00" + der;
		
		der = "300d06092a864886f70d0101010500"  + der;
		der = "30" + (Math.ceil(der.length/2)).toString(16) + der;
		//alert("isPublic=" +  isPublic + " der=" + der);
	}
	//document.getElementById("msg_display").innerHTML+="<BR>Key<BR>" + der;
	
	return getBytesFromStr(der);	
}

//rsaKey   [String] - string in der format of public or private part of RSAKey.
//isPublic [boolean] - specifies what part of RSAKey is supplied in rsaKey parameter[0 - public, 1 - private]
//return   [RSAKey] - with properly initialized data members of corresponding part of RSAKey.
function der_to_rsa_format(rsaKey, isPublic)
{
    var rsa = new RSAKey();
    var rsa_key_hex = stringToHex(rsaKey);
    
    //Skip first byte (30)
    var index = 2;
    
    //Extract length of sequence size part
    var seq_length_size = get_bytes(rsa_key_hex, index);
    index += 2;  
    if(seq_length_size & 0x80)
    {
        seq_length_size &= ~0x80;
        var seq_length = get_bytes(rsa_key_hex, index, seq_length_size);
        index += seq_length_size*2;
        seq_length_size = seq_length;
    }
   
    rsa_key_hex = rsa_key_hex.substr(index);   
    index = 0;
    if(rsa_key_hex.length/2 != seq_length_size)
    {
            //alert("Bad der format: length of sequence is unmatched.");
            WScript.StdOut.WriteLine("Bad der format: length of sequence is unmatched.");
            return null;
    }
            
    if(isPublic)
    {        
        index += 15*2; //Skip standardt header
        index += 5*2;  //Skip. Sizes of sequences does not verified
        rsa_key_hex = rsa_key_hex.substr(index); 
        index = 0; 
        
        var seq_number = get_bytes(rsa_key_hex, index);
        index += 2;
        if(seq_number != 0x02)
        {
            //alert("Bad der format: sequence number is incorect.");
            WScript.StdOut.WriteLine("Bad der format: sequence number is incorect.");
            return null;
        }
        var n_length = get_bytes(rsa_key_hex, index);
        index += 2;
        var n_hex = rsa_key_hex.substr(index, n_length*2);
        index += n_length*2;
        rsa.n = parseBigInt(n_hex,16);
        
        seq_number = get_bytes(rsa_key_hex, index);
        index += 2;
        if(seq_number != 0x02)
        {
            //alert("Bad der format: sequence number is incorect.");
            WScript.StdOut.WriteLine("Bad der format: sequence number is incorect.");
            return null;
        }      
        var e_length = get_bytes(rsa_key_hex, index);
        index += 2;     
        rsa.e = get_bytes(rsa_key_hex, index, e_length);
        //index += e_length*2;
        
    }
    else//Private
    {
        index += 3*2;//Skip standardt header
        rsa_key_hex = rsa_key_hex.substr(index); 
        index = 0;  
        
        //extract n
        var seq_number = get_bytes(rsa_key_hex, index);
        index += 2;
        if(seq_number != 0x02)
        {
            //alert("Bad der format: sequence number is incorect.");
            WScript.StdOut.WriteLine("Bad der format: sequence number is incorect.");
            return null;
        }   
        var n_length = get_bytes(rsa_key_hex, index);
        index += 2;
        var n_hex = rsa_key_hex.substr(index, n_length*2);
        index += n_length*2;
        rsa.n = parseBigInt(n_hex,16);
        
        //extract e
        seq_number = get_bytes(rsa_key_hex, index);
        index += 2;
        if(seq_number != 0x02)
        {
            //alert("Bad der format: sequence number is incorect.");
            WScript.StdOut.WriteLine("Bad der format: sequence number is incorect.");
            return null;
        }      
        var e_length = get_bytes(rsa_key_hex, index);
        index += 2;     
        rsa.e = get_bytes(rsa_key_hex, index, e_length);
        index += e_length*2;
        
        //extract d
        seq_number = get_bytes(rsa_key_hex, index);
        index += 2;
        if(seq_number != 0x02)
        {
            //alert("Bad der format: sequence number is incorect.");
            WScript.StdOut.WriteLine("Bad der format: sequence number is incorect.");
            return null;
        }      
        var d_length = get_bytes(rsa_key_hex, index);
        index += 2;
        var d_hex = rsa_key_hex.substr(index, d_length*2);
        index += d_length*2;
        rsa.d = parseBigInt(d_hex,16);
        
        //extract p
        seq_number = get_bytes(rsa_key_hex, index);
        index += 2;
        if(seq_number != 0x02)
        {
            //alert("Bad der format: sequence number is incorect.");
            WScript.StdOut.WriteLine("Bad der format: sequence number is incorect.");
            return null;
        }      
        var p_length = get_bytes(rsa_key_hex, index);
        index += 2;
        var p_hex = rsa_key_hex.substr(index, p_length*2);
        index += p_length*2;
        rsa.p = parseBigInt(p_hex,16);
        
        //extract q
        seq_number = get_bytes(rsa_key_hex, index);
        index += 2;
        if(seq_number != 0x02)
        {
            //alert("Bad der format: sequence number is incorect.");
            WScript.StdOut.WriteLine("Bad der format: sequence number is incorect.");
            return null;
        }      
        var q_length = get_bytes(rsa_key_hex, index);
        index += 2;
        var q_hex = rsa_key_hex.substr(index, q_length*2);
        index += q_length*2;
        rsa.q = parseBigInt(q_hex,16);
        
        //extract dmp1
        seq_number = get_bytes(rsa_key_hex, index);
        index += 2;
        if(seq_number != 0x02)
        {
            //alert("Bad der format: sequence number is incorect.");
            WScript.StdOut.WriteLine("Bad der format: sequence number is incorect.");
            return null;
        }      
        var dmp1_length = get_bytes(rsa_key_hex, index);
        index += 2;
        var dmp1_hex = rsa_key_hex.substr(index, dmp1_length*2);
        index += dmp1_length*2;
        rsa.dmp1 = parseBigInt(dmp1_hex,16);
        
        //extract dmq1
        seq_number = get_bytes(rsa_key_hex, index);
        index += 2;
        if(seq_number != 0x02)
        {
            //alert("Bad der format: sequence number is incorect.");
            WScript.StdOut.WriteLine("Bad der format: sequence number is incorect.");
            return null;
        }      
        var dmq1_length = get_bytes(rsa_key_hex, index);
        index += 2;
        var dmq1_hex = rsa_key_hex.substr(index, dmq1_length*2);
        index += dmq1_length*2;
        rsa.dmq1 = parseBigInt(dmq1_hex,16);
        
        //extract coeff
        seq_number = get_bytes(rsa_key_hex, index);
        index += 2;
        if(seq_number != 0x02)
        {
            //alert("Bad der format: sequence number is incorect.");
            WScript.StdOut.WriteLine("Bad der format: sequence number is incorect.");
            return null;
        }      
        var coeff_length = get_bytes(rsa_key_hex, index);
        index += 2;
        var coeff_hex = rsa_key_hex.substr(index, coeff_length*2);
        //index += coeff_length*2;
        rsa.coeff = parseBigInt(coeff_hex,16);
    }
    return rsa;
}

//Convert indexed and next literal (its byte in hex representation) to integer
//num_bytes to convert - optional parameter, by default 1 byte
function get_bytes(hexString, start_index, num_bytes)
{
    var bytes_to_convert = 1;
    if(typeof(num_bytes) != 'undefined')
        bytes_to_convert = num_bytes;
    var number_hex = hexString.substr(start_index, bytes_to_convert*2);
    var number = parseInt(number_hex, 16);
    return number;
}

function make_data(isPublic)
{
	var temp_der = ""
	var num_iterations = rsaKeysArr.length;
	if(isPublic)
		num_iterations = 2;
	for(var i = num_iterations - 1; i >=0; i--)
	{
		var key = rsaKeysArr[i];
		var key_length = get_num_bytes(key);
		var isNeedExtraByte = false;
		
		if(is_need_extra_byte(key))
		{
			key_length += 1;
			isNeedExtraByte = true;
		}
		var num_size_bytes = make_size(key_length);
		
		if(is_need_leading_zero(key))
			temp_der = "0" + key.toString(16) + temp_der;
		else
			if(isNeedExtraByte)
				temp_der = "00" + key.toString(16) + temp_der;
			else
				temp_der = key.toString(16) + temp_der;
		
		temp_der = "02" + ((num_size_bytes==0)?(add_leading_zero(key_length).toString(16)):(num_size_bytes.toString(16) + add_leading_zero(key_length).toString(16))) + temp_der;
	}
	//Version
	if(!isPublic)
		temp_der = "020100" + temp_der;

	var rsaDataLength = Math.ceil((temp_der.toString(16).length)/2);
	var isSequence = test_is_sequence(rsaDataLength);
	var num_size_bytes = (add_leading_zero(rsaDataLength).toString(16).length)/2;
	if(isSequence)
	{	
		num_size_bytes = num_size_bytes|0x80;
		temp_der = "30" + num_size_bytes.toString(16) + add_leading_zero(rsaDataLength).toString(16) + temp_der;
	}
	else
		temp_der = "30" + add_leading_zero(rsaDataLength).toString(16) + temp_der;
	der = temp_der + der;
	return temp_der;
}

function make_size(key_length)
{
	var num_size_bytes = 0;
	if(test_is_sequence(key_length))
	{
		num_size_bytes = (add_leading_zero(key_length).toString(16).length)/2;
		num_size_bytes = num_size_bytes|0x80;
	}
	return num_size_bytes;
}

function test_is_sequence(rsaDataLength)
{
	if(rsaDataLength <= 0x7F)
		return false;
	return true;
}
function get_num_bytes(bigNumber)
{
	var length = bigNumber.toString(16).length;
	var num_bytes = parseInt(length/2, 10);
	if(length%2 != 0)
		num_bytes += 1;
	return num_bytes;
}

function is_need_leading_zero(str_number)
{
	if((str_number.toString(16).length%2) != 0)
		return true;
}

function add_leading_zero(str_number)
{
	if(is_need_leading_zero(str_number))
		return "0" + str_number.toString(16);
	return str_number;
}
//nedds extra byte if primary bit of number equal to 1
function is_need_extra_byte(number)
{
	try
	{
		var primaryByte = (number.toByteArray()[0] == 0?number.toByteArray()[1]:number.toByteArray()[0]);
	
		if(((primaryByte&0xFF)&0x80) == 0x80)
			return true;
	}
	catch(exception) {
		return false;
	}	
	
}
function init(rsaKey)
{
	rsaKeysArr = new Array(rsaKey.n, rsaKey.e, rsaKey.d, rsaKey.p, rsaKey.q, rsaKey.dmp1, rsaKey.dmq1, rsaKey.coeff);
	//for(var i = rsaKeysArr.length-1; i >= 0; i--)
		//document.getElementById("msg_display").innerHTML+="<BR>" + rsaKeysArr[i].toString(16);
}
function getBytesFromStr(str)
{
	var bytesStr = "";
	for(var i = 0; i < str.length; i+=2)
	{
		var sub = str.substr(i, 2);
		bytesStr += String.fromCharCode(parseInt(sub, 16));
	}
	return bytesStr;
}

/* Public part sample
    305c
    300d 06092a864886f70d0101010500
    03 4b 00
    30 48
n:  02 41 00ced33be8e30998895f3a2d88b1fb913ac5d98c3f45d1123f14de2ab3bfc1228b9e344a5d8f51692e4f3aa41a8a641aaa021c89cdcebbcd4ff7a83a228798df85
e:  02 03 010001
    */
    /* Private part sample
      3082013b
      02 01 00
n:    02 41 00ced33be8e30998895f3a2d88b1fb913ac5d98c3f45d1123f14de2ab3bfc1228b9e344a5d8f51692e4f3aa41a8a641aaa021c89cdcebbcd4ff7a83a228798df85
e:    02 03 010001
d:    02 41 00a79504a00906477057969e3a7a6c6a1a832168c003e409b2cf47ccb5e493ab569c18dbe6d9cdc70f7cf74cc72ff2927036a40d1d7d284c08baa47fa96a041b81
p:    02 21 00f364be4f8e87eb36205451e64abcdbe62fc7081b6eab2bdc273ec94ab6a02551
q:    02 21 00d9899d6e3fc8a1393797c2c2a7a439b575b1b1796681b936ec38fd3a769c59f5
dmp1: 02 20 18e010fb3c8bf3a42285bba117be59931b0af26f2b4e5f3b2edfa1defaef3f21
dmq1: 02 21 00a72b9ce2cb7b67822bd9a11eab6b85b98fef74be216b112546d4e8acd3d7853d
coeff:02 20 7e4270222d62fb4a38ff9bdd74067f18452b794d9873113dbaa366c79dd06044
*/
