/**
 * RSA, a suite of routines for performing RSA public-key computations in
 * JavaScript.
 *
 * Requires BigInt.js and Barrett.js.
 *
 * Copyright 1998-2005 David Shapiro.
 *
 * You may use, re-use, abuse, copy, and modify this code to your liking, but
 * please keep this header.
 *
 * Thanks!
 * 
 * @author Dave Shapiro <dave AT ohdave DOT com>
 */ 
if (typeof Crypt == "undefined") var Crypt = {};

Crypt.RSA = (function() {
    function RSAKeyPair(encryptionExponent, decryptionExponent, modulus) {
        this.e = Crypt.BigInt.fromHex(encryptionExponent);
        this.d = Crypt.BigInt.fromHex(decryptionExponent);
        this.m = Crypt.BigInt.fromHex(modulus);
        /*
         * We can do two bytes per digit, so
         * chunkSize = 2 * (number of digits in modulus - 1).
         * Since biHighIndex returns the high index, not the number of digits, 1 has
         * already been subtracted.
         */
        ////////////////////////////////// TYF
        this.digitSize = 2 * Crypt.BigInt.highIndex(this.m) + 2;
        this.chunkSize = this.digitSize - 11; // maximum, anything lower is fine
        ////////////////////////////////// TYF
        this.radix = 16;
        this.barrett = new (Crypt.Barrett)(this.m);
    }
    
    function twoDigit(n) {
        return (n < 10 ? "0" : "") + String(n);
    }
    
    function encryptedString(key, s) {
        /*
         * Altered by Rob Saunders (rob@robsaunders.net). New routine pads the
         * string after it has been converted to an array. This fixes an
         * incompatibility with Flash MX's ActionScript.
         * Altered by Tang Yu Feng for interoperability with Microsoft's
         * RSACryptoServiceProvider implementation.
         */
        ////////////////////////////////// TYF
        if (key.chunkSize > key.digitSize - 11) {
            return "Error";
        }
        ////////////////////////////////// TYF
        var a = new (Array)();
        var sl = s.length;
        
        var i = 0;
        while (i < sl) {
             _proxy_jslib_assign('', a, (i), '=', ( s.charCodeAt(i)));
            i++;
        }
        
        var al = a.length;
        var result = "";
        var j, k, block;
        for (i = 0; i < al; i += key.chunkSize) {
            block = new (Crypt.BigInt.construct)();
            j = 0;
            ////////////////////////////////// TYF
            /*
             * Add PKCS#1 v1.5 padding
             * 0x00 || 0x02 || PseudoRandomNonZeroBytes || 0x00 || Message
             * Variable a before padding must be of at most digitSize-11
             * That is for 3 marker bytes plus at least 8 random non-zero bytes
             */
            var x;
            var msgLength = (i+key.chunkSize)>al ? al%key.chunkSize : key.chunkSize;
            
            // Variable b with 0x00 || 0x02 at the highest index.
            var b = new (Array)();
            for (x = 0; x < msgLength; x++) {
                 _proxy_jslib_assign('', b, (x), '=', (  _proxy_jslib_handle(a, (i + msgLength - 1 - x), 0, 0)));
            }
             _proxy_jslib_assign('', b, (msgLength), '=', ( 0)); // marker
            var paddedSize = Math.max(8, key.digitSize - 3 - msgLength);
            for (x = 0; x < paddedSize; x++) {
                 _proxy_jslib_assign('', b, (msgLength + 1 + x), '=', ( Math.floor(Math.random() * 254) + 1)); // [1,255]
            }
            // It can be asserted that msgLength+paddedSize == key.digitSize-3
             _proxy_jslib_assign('', b, (key.digitSize - 2), '=', ( 2)); // marker
             _proxy_jslib_assign('', b, (key.digitSize - 1), '=', ( 0)); // marker
            
            for (k = 0; k < key.digitSize; (j= _proxy_jslib_assign_rval('++', 'j', '', '', j))) 
            {
                 _proxy_jslib_assign('', block.digits, (j), '=', (  _proxy_jslib_handle(b, (k++), 0, 0)));
                 _proxy_jslib_assign('', block.digits, (j), '+=', (  _proxy_jslib_handle(b, (k++), 0, 0) << 8));
            }
            ////////////////////////////////// TYF
            
            var crypt = key.barrett.powMod(block, key.e);
            var text = key.radix == 16 ? Crypt.BigInt.toHex(crypt) :  _proxy_jslib_handle(Crypt.BigInt, 'toString', '', 1, 0)(crypt, key.radix);
            result += text + " ";
        }
        return result.substring(0, result.length - 1); // Remove last space.
    }
    
    function decryptedString(key, s) {
        var blocks = s.split(" ");
        var result = "";
        var i, j, block;
        for (i = 0; i < blocks.length; (i= _proxy_jslib_assign_rval('++', 'i', '', '', i))) {
            var bi;
            if (key.radix == 16) {
                bi = Crypt.BigInt.fromHex( _proxy_jslib_handle(blocks, (i), 0, 0));
            } else {
                bi = Crypt.BigInt.fromString( _proxy_jslib_handle(blocks, (i), 0, 0), key.radix);
            }
            block = key.barrett.powMod(bi, key.d);
            for (j = 0; j <= Crypt.BigInt.highIndex(block); (j= _proxy_jslib_assign_rval('++', 'j', '', '', j))) {
                result += String.fromCharCode( _proxy_jslib_handle(block.digits, (j), 0, 0) & 255,
                   _proxy_jslib_handle(block.digits, (j), 0, 0) >> 8);
            }
        }
        // Remove trailing null, if any.
        if (result.charCodeAt(result.length - 1) == 0) {
            result = result.substring(0, result.length - 1);
        }
        return result;
    }
    
    //publish public functions:
    return {
        getKeyPair: RSAKeyPair,
        twoDigit: twoDigit,
        encrypt: encryptedString,
        decrypt: decryptedString
 };
})();
 ;
_proxy_jslib_flush_write_buffers() ;