﻿/// <reference name="MicrosoftAjax.debug.js" />
/// <reference path="BadBug.debug.js" />

Type.registerNamespace( "BadBug.Security.Cryptography" );

BadBug.Security.Cryptography._MD5 = function(){
    BadBug.Security.Cryptography._MD5.initializeBase( this );
};

BadBug.Security.Cryptography._MD5.prototype = {
    initialize: function(){
        BadBug.Security.Cryptography._MD5.callBaseMethod( this, "initialize" );    
    },
    dispose: function(){
        BadBug.Security.Cryptography._MD5.callBaseMethod( this, "dispose" );
    },
    _CMN: function( q, a, b, x, s, t ){
        return a.add32( q ).add32( x.add32( t ) ).rotateL32( s ).add32( b );
    },
    _FF: function( a, b, c, d, x, s, t ){
        return this._CMN( ( b & c ) | ( ( ~b ) & d ), a, b, x, s, t );
    },
    _GG: function( a, b, c, d, x, s, t ){
        return this._CMN( ( b & d ) | ( c & ( ~d ) ), a, b, x, s, t );
    },
    _HH: function( a, b, c, d, x, s, t ){
        return this._CMN( b ^ c ^ d, a, b, x, s, t );
    },
    _II: function( a, b, c, d, x, s, t ){
        return this._CMN( c ^ ( b | ( ~d ) ), a, b, x, s, t );
    },
    computeText: function( text ){
        this.compute( text.toUTF8Bytes() ).toHexString( 2 );
    },
    compute: function( bytes, offset, count ){
        /// <summary>
        /// 计算MD5
        /// </summary>       
        /// <param name="bytes" type="Array">包含要计算的数据的字节数组</param>
        /// <param name="offset" type="Number">要计算的数据在字节数组中的偏移位置</param>
        /// <param name="count" type="Number">要计算的数据的字节数</param>
        /// <returns type="Array"></returns>
        if( !offset || isNaN( offset ) ) offset = 0;
        if( !count || isNaN( count ) ) count = bytes.length;
        var _t = bytes.slice( offset, offset + count );
        var binCount = count << 3;
        var paddingCount = 448 - ( binCount % 512 );
        if( paddingCount < 0 ) paddingCount = 960 - binCount % 512;
        _t.push( 0x80 );
        paddingCount >>= 3;
        paddingCount --;
        while( _t.length % 4 != 0 )
        {
            _t.push( 0 );
            paddingCount--;
        }
        var x = [];
        var numberCount = _t.length >> 2;
        for( var i = 0; i < numberCount; i ++ )
        {
            x[ i ] = Number.fromBytes32( _t, i << 2 );
        }
        paddingCount >>= 2;
        while( paddingCount -- > 0 )
        {
            x[ x.length ] = 0;
        }
        var binLen = count << 3;
        x[ x.length ] = ( binLen & 0xFFFFFFFF ); 
        x[ x.length ] = ( ( ( binLen & 0xFFFFFFFF00000000 ) >> 32 ) & 0xFFFFFFFF );

        var a =  1732584193;
        var b = -271733879;
        var c = -1732584194;
        var d =  271733878;

        for( var i = 0; i < x.length; i += 16 )
        {
            var olda = a;
            var oldb = b;
            var oldc = c;
            var oldd = d;
 
            a = this._FF(a, b, c, d, x[i+ 0], 7 , -680876936);
            d = this._FF(d, a, b, c, x[i+ 1], 12, -389564586);
            c = this._FF(c, d, a, b, x[i+ 2], 17,  606105819);
            b = this._FF(b, c, d, a, x[i+ 3], 22, -1044525330);
            a = this._FF(a, b, c, d, x[i+ 4], 7 , -176418897);
            d = this._FF(d, a, b, c, x[i+ 5], 12,  1200080426);
            c = this._FF(c, d, a, b, x[i+ 6], 17, -1473231341);
            b = this._FF(b, c, d, a, x[i+ 7], 22, -45705983);
            a = this._FF(a, b, c, d, x[i+ 8], 7 ,  1770035416);
            d = this._FF(d, a, b, c, x[i+ 9], 12, -1958414417);
            c = this._FF(c, d, a, b, x[i+10], 17, -42063);
            b = this._FF(b, c, d, a, x[i+11], 22, -1990404162);
            a = this._FF(a, b, c, d, x[i+12], 7 ,  1804603682);
            d = this._FF(d, a, b, c, x[i+13], 12, -40341101);
            c = this._FF(c, d, a, b, x[i+14], 17, -1502002290);
            b = this._FF(b, c, d, a, x[i+15], 22,  1236535329);

            a = this._GG(a, b, c, d, x[i+ 1], 5 , -165796510);
            d = this._GG(d, a, b, c, x[i+ 6], 9 , -1069501632);
            c = this._GG(c, d, a, b, x[i+11], 14,  643717713);
            b = this._GG(b, c, d, a, x[i+ 0], 20, -373897302);
            a = this._GG(a, b, c, d, x[i+ 5], 5 , -701558691);
            d = this._GG(d, a, b, c, x[i+10], 9 ,  38016083);
            c = this._GG(c, d, a, b, x[i+15], 14, -660478335);
            b = this._GG(b, c, d, a, x[i+ 4], 20, -405537848);
            a = this._GG(a, b, c, d, x[i+ 9], 5 ,  568446438);
            d = this._GG(d, a, b, c, x[i+14], 9 , -1019803690);
            c = this._GG(c, d, a, b, x[i+ 3], 14, -187363961);
            b = this._GG(b, c, d, a, x[i+ 8], 20,  1163531501);
            a = this._GG(a, b, c, d, x[i+13], 5 , -1444681467);
            d = this._GG(d, a, b, c, x[i+ 2], 9 , -51403784);
            c = this._GG(c, d, a, b, x[i+ 7], 14,  1735328473);
            b = this._GG(b, c, d, a, x[i+12], 20, -1926607734);

            a = this._HH(a, b, c, d, x[i+ 5], 4 , -378558);
            d = this._HH(d, a, b, c, x[i+ 8], 11, -2022574463);
            c = this._HH(c, d, a, b, x[i+11], 16,  1839030562);
            b = this._HH(b, c, d, a, x[i+14], 23, -35309556);
            a = this._HH(a, b, c, d, x[i+ 1], 4 , -1530992060);
            d = this._HH(d, a, b, c, x[i+ 4], 11,  1272893353);
            c = this._HH(c, d, a, b, x[i+ 7], 16, -155497632);
            b = this._HH(b, c, d, a, x[i+10], 23, -1094730640);
            a = this._HH(a, b, c, d, x[i+13], 4 ,  681279174);
            d = this._HH(d, a, b, c, x[i+ 0], 11, -358537222);
            c = this._HH(c, d, a, b, x[i+ 3], 16, -722521979);
            b = this._HH(b, c, d, a, x[i+ 6], 23,  76029189);
            a = this._HH(a, b, c, d, x[i+ 9], 4 , -640364487);
            d = this._HH(d, a, b, c, x[i+12], 11, -421815835);
            c = this._HH(c, d, a, b, x[i+15], 16,  530742520);
            b = this._HH(b, c, d, a, x[i+ 2], 23, -995338651);

            a = this._II(a, b, c, d, x[i+ 0], 6 , -198630844);
            d = this._II(d, a, b, c, x[i+ 7], 10,  1126891415);
            c = this._II(c, d, a, b, x[i+14], 15, -1416354905);
            b = this._II(b, c, d, a, x[i+ 5], 21, -57434055);
            a = this._II(a, b, c, d, x[i+12], 6 ,  1700485571);
            d = this._II(d, a, b, c, x[i+ 3], 10, -1894986606);
            c = this._II(c, d, a, b, x[i+10], 15, -1051523);
            b = this._II(b, c, d, a, x[i+ 1], 21, -2054922799);
            a = this._II(a, b, c, d, x[i+ 8], 6 ,  1873313359);
            d = this._II(d, a, b, c, x[i+15], 10, -30611744);
            c = this._II(c, d, a, b, x[i+ 6], 15, -1560198380);
            b = this._II(b, c, d, a, x[i+13], 21,  1309151649);
            a = this._II(a, b, c, d, x[i+ 4], 6 , -145523070);
            d = this._II(d, a, b, c, x[i+11], 10, -1120210379);
            c = this._II(c, d, a, b, x[i+ 2], 15,  718787259);
            b = this._II(b, c, d, a, x[i+ 9], 21, -343485551);

            a = a.add32( olda );
            b = b.add32( oldb );
            c = c.add32( oldc );
            d = d.add32( oldd );
        }
        return a.toBytes32().concat( b.toBytes32(), c.toBytes32(), d.toBytes32() );
    }
}

BadBug.Security.Cryptography._MD5.registerClass( "BadBug.Security.Cryptography._MD5", Sys.Component );
BadBug.Security.Cryptography.MD5 = new BadBug.Security.Cryptography._MD5();



BadBug.Security.Cryptography._TEA = function(){
    BadBug.Security.Cryptography._TEA.initializeBase( this );
};
BadBug.Security.Cryptography._TEA.prototype = {
    initialize: function(){
        BadBug.Security.Cryptography._TEA.callBaseMethod( this, "initialize" );    
    },
    dispose: function(){
        BadBug.Security.Cryptography._TEA.callBaseMethod( this, "dispose" );
    },
    encode16: function( key, input, inOffset, output, outOffset ){
        /// <summary>
        /// 使用TEA算法进行16轮编码
        /// </summary>       
        /// <param name="key" type="Array">16字节密钥</param>
        /// <param name="input" type="Array">包含要编码的数据的字节数组</param>
        /// <param name="inOffset" type="Number">要编码的数据在字节数组中的偏移位置</param>
        /// <param name="output" type="Array">用于保存编码结果的字节数组</param>
        /// <param name="outOffset" type="Number">指定从数组中第outOffset位置开始保存编码结果</param>
        var n = 16, sum = 0, delta = 0x9E3779B9;
        var y = Number.fromBytes32( input, inOffset ).swap32();
        var z = Number.fromBytes32( input, inOffset + 4 ).swap32();
        var keys = new Array( 4 );
        for( var i = 0; i < 4; i ++ )
        {
            keys[ i ] = Number.fromBytes32( key, i << 2 ).swap32();
        }
        while ( n-- > 0 )
        {
            sum = sum.add32( delta );
            y = y.add32( ( ( z << 4 ).add32( keys[ 0 ] ) ) ^ ( z.add32( sum ) ) ^ ( ( z >>> 5 ).add32( keys[ 1 ] ) ) );
            z = z.add32( ( ( y << 4 ).add32( keys[ 2 ] ) ) ^ ( y.add32( sum ) ) ^ ( ( y >>> 5 ).add32( keys[ 3 ] ) ) );
        }
        var _t1 = y.swap32().toBytes32();
        var _t2 = z.swap32().toBytes32();
        for( var i = 0; i < 4; i ++ )
        {
            output[ outOffset + i ] = _t1[ i ];
            output[ outOffset + i + 4 ] = _t2[ i ];
        }        
    },
    decode16: function( key, input, inOffset, output, outOffset ){
        /// <summary>
        /// 使用TEA算法进行16轮解码
        /// </summary>       
        /// <param name="key" type="Array">16字节密钥</param>
        /// <param name="input" type="Array">包含要解码的数据的字节数组</param>
        /// <param name="inOffset" type="Number">要解码的数据在字节数组中的偏移位置</param>
        /// <param name="output" type="Array">用于保存解码结果的字节数组</param>
        /// <param name="outOffset" type="Number">指定从数组中第outOffset位置开始保存解码结果</param>
        var n = 16, delta = 0x9E3779B9;
        var sum = delta << 4;
        var y = Number.fromBytes32( input, inOffset ).swap32();
        var z = Number.fromBytes32( input, inOffset + 4 ).swap32();
        var keys = new Array( 4 );
        for( var i = 0; i < 4; i ++ )
        {
            keys[ i ] = Number.fromBytes32( key, i << 2 ).swap32();
        }
        while ( n-- > 0 )
        {
            z = z.sub32( ( ( y << 4 ).add32( keys[ 2 ] ) ) ^ ( y.add32( sum ) ) ^ ( ( y >>> 5 ).add32( keys[ 3 ] ) ) );
            y = y.sub32( ( ( z << 4 ).add32( keys[ 0 ] ) ) ^ ( z.add32( sum ) ) ^ ( ( z >>> 5 ).add32( keys[ 1 ] ) ) );
            sum = sum.sub32( delta );
        }
        var _t1 = y.swap32().toBytes32();
        var _t2 = z.swap32().toBytes32();
        for( var i = 0; i < 4; i ++ )
        {
            output[ outOffset + i ] = _t1[ i ];
            output[ outOffset + i + 4 ] = _t2[ i ];
        }        
    }
};
BadBug.Security.Cryptography._TEA.registerClass( "BadBug.Security.Cryptography._TEA", Sys.Component );
BadBug.Security.Cryptography.TEA = new BadBug.Security.Cryptography._TEA();

BadBug.Security.Cryptography._QQCrypt = function(){
    BadBug.Security.Cryptography._QQCrypt.initializeBase( this );
};
BadBug.Security.Cryptography._QQCrypt.prototype = {
    initialize: function(){
        BadBug.Security.Cryptography._QQCrypt.callBaseMethod( this, "initialize" );    
    },
    dispose: function(){
        BadBug.Security.Cryptography._QQCrypt.callBaseMethod( this, "dispose" );
    },
    rand: function(){
        return Math.ceil( Math.random() * 100000 );
    },
    encode: function( key, input, offset, count ){
        /// <summary>
        /// 使用QQCrypt来加密数据
        /// </summary>       
        /// <param name="key" type="Array">16字节密钥</param>
        /// <param name="input" type="Array">包含要加密的数据的字节数组</param>
        /// <param name="offset" type="Number">要加密的数据在字节数组中的偏移位置</param>
        /// <param name="count" type="Number">要加密的数据的字节数</param>
        /// <returns type="Array"></returns>
        if( !offset ) offset = 0;
        if( !count ) count = input.length - offset;
        var crypt = 0;
        var preCrypt = 0;
        var _o = ( count + 10 ) % 8;
        if ( _o != 0 ) _o = 8 - _o;
        var outLen = count + _o + 10;
        var plain = [ 0, 0, 0, 0, 0, 0, 0, 0 ];
        var prePlain = [ 0, 0, 0, 0, 0, 0, 0, 0 ];
        var output = new Array( outLen );
        plain[ 0 ] = ( this.rand() & 0xF8 ) | _o;
        for ( var j = 1; j <= _o; j++ ) plain[ j ] = this.rand() & 0xFF;
        var pos = _o + 1;
        var isHead = true;
        var padding = 0;
        while ( padding++ < 2 )
        {
            if ( pos < 8 ) plain[ pos++ ] = this.rand() & 0xFF;
            if ( pos == 8 )
            {
                for ( pos = 0; pos < 8; pos++ )
                {
                    if ( isHead ) plain[ pos ] ^= prePlain[ pos ];
                    else plain[ pos ] ^= output[ preCrypt + pos ];
                }
                BadBug.Security.Cryptography.TEA.encode16( key, plain, 0, output, crypt );
                for ( pos = 0; pos < 8; pos++ ) output[ crypt + pos ] ^= prePlain[ pos ];
                for ( var j = 0; j < 8; j++ ) prePlain[ j ] = plain[ j ];
                preCrypt = crypt;
                crypt += 8;
                pos = 0;
                isHead = false;
            }
        }
        var i = 0;
        var leftlen = count;
        while ( leftlen > 0 )
        {
            if ( pos < 8 )
            {
                plain[ pos++ ] = input[ offset + i++ ];
                leftlen--;
            }
            if ( pos == 8 )
            {
                for ( pos = 0; pos < 8; pos++ )
                {
                    if ( isHead ) plain[ pos ] ^= prePlain[ pos ];
                    else plain[ pos ] ^= output[ preCrypt + pos ];
                }
                BadBug.Security.Cryptography.TEA.encode16( key, plain, 0, output, crypt );
                for ( pos = 0; pos < 8; pos++ ) output[ crypt + pos ] ^= prePlain[ pos ];
                for ( var j = 0; j < 8; j++ ) prePlain[ j ] = plain[ j ];
                preCrypt = crypt;
                crypt += 8;
                pos = 0;
                isHead = false;
            }
        }
        padding = 0;
        for ( i = pos; i < 8; i++ ) plain[ i ] = 0x00;
        for ( pos = 0; pos < 8; pos++ ) plain[ pos ] ^= output[ preCrypt + pos ];
        BadBug.Security.Cryptography.TEA.encode16( key, plain, 0, output, crypt );
        for ( pos = 0; pos < 8; pos++ ) output[ crypt + pos ] ^= prePlain[ pos ];
        return output;
    },
    decode: function( key, input, offset, count ){
        /// <summary>
        /// 使用QQCrypt来解密数据
        /// </summary>       
        /// <param name="key" type="Array">16字节密钥</param>
        /// <param name="input" type="Array">包含要解密的数据的字节数组</param>
        /// <param name="offset" type="Number">要解密的数据在字节数组中的偏移位置</param>
        /// <param name="count" type="Number">要解密的数据的字节数</param>
        /// <returns type="Array"></returns>
        if( !offset ) offset = 0;
        if( !count ) count = input.length - offset;
        var crypt = 0;
        var preCrypt = 0;
        var prePlain = [ 0, 0, 0, 0, 0, 0, 0, 0 ];
        if ( ( count % 8 != 0 ) || ( count < 16 ) ) return null;
        var outLen = 0, counter = 0, pos = 0, contextStart = 0;
        var m = null;
        BadBug.Security.Cryptography.TEA.decode16( key, input, offset, prePlain, 0 );
        pos = prePlain[ 0 ] & 0x07;
        counter = outLen = count - pos - 10;
        if ( outLen < 0 ) return null;
        var output = new Array( outLen );
        var _t = [ 0, 0, 0, 0, 0, 0, 0, 0 ];
        m = _t;
        preCrypt = 0;
        crypt = 8;
        contextStart = 8;
        pos++;
        var padding = 0;
        while ( padding++ < 2 )
        {
            if ( pos < 8 ) pos++;
            if ( pos == 8 )
            {
                m = input;
                for ( pos = 0; pos < 8; pos++ )
                {
                    if ( contextStart + pos >= count ) return null;
                    prePlain[ pos ] ^= input[ crypt + offset + pos ];
                }
                BadBug.Security.Cryptography.TEA.decode16( key, prePlain, 0, prePlain, 0 );
                contextStart += 8;
                crypt += 8;
                pos = 0;
            }
        }
        var i = 0;
        while ( counter != 0 )
        {
            if ( pos < 8 )
            {
                if ( m == _t ) output[ i++ ] = ( m[ preCrypt + pos ] ^ prePlain[ pos ] );
                else output[ i++ ] = ( m[ preCrypt + offset + pos ] ^ prePlain[ pos ] );
                counter--;
                pos++;
            }
            if ( pos == 8 )
            {
                m = input;
                preCrypt = crypt - 8;
                for ( pos = 0; pos < 8; pos++ )
                {
                    if ( contextStart + pos >= count ) return null;
                    prePlain[ pos ] ^= input[ crypt + offset + pos ];
                }
                BadBug.Security.Cryptography.TEA.decode16( key, prePlain, 0, prePlain, 0 );
                contextStart += 8;
                crypt += 8;
                pos = 0;
            }
        }
        padding = 0;
        var decoded = true;
        while ( pos < 8 )
        {
            if ( ( m[ preCrypt + offset + pos ] ^ prePlain[ pos ] ) != 0x00 )
            {
                decoded = false;
                break;
            }
            pos++;
        }
        return decoded ? output : null;
    }    
};
BadBug.Security.Cryptography._QQCrypt.registerClass( "BadBug.Security.Cryptography._QQCrypt", Sys.Component );
BadBug.Security.Cryptography.QQCrypt = new BadBug.Security.Cryptography._QQCrypt();

if ( typeof(Sys) !== "undefined" ) Sys.Application.notifyScriptLoaded();

