* * A JavaScript implementation of the RSA Data Security, Inc. MD4 message * Digest algorithm, as defined in RFC 1320.
* Version 2.1 Copyright (C) Jerrad Pierce, Paul Johnston 1999-2002. * Other Contributors:greg Holt, Andrew Kepert, Ydnar, lostinet * Distributed under the BSD License * http://pajhome
. org.uk/crypt/md5 for more info. */
* * * Configurable variables. You could need to tweak this compatible with * server-side, but the defaults work in most. */ VarHexcase= 0; /* Hex output format. 0-lowercase; 1-uppercase * VarB64pad= ""; /* base-64 pad character. "=" for strict RFC compliance * * VarChrsz= 8; /* bits per input character. 8-ascii; 16-unicode * * * These are the functions "ll usually want to call * * functionHex_md4(S){ ReturnBinl2hex(Core_md4(Str2binl(S), S.Length* Chrsz));} functionB64_md4(S){ ReturnBinl2b64(Core_md4(Str2binl(S), S.Length* Chrsz));} functionStr_md4(S){ ReturnBinl2str(Core_md4(Str2binl(S), S.Length* Chrsz));} functionHex_hmac_md4(Key, data) { ReturnBinl2hex(Core_hmac_md4(Key, data)); } functionB64_hmac_md4(Key, data) { ReturnBinl2b64(Core_hmac_md4(Key, data)); } functionStr_hmac_md4(Key, data) { ReturnBinl2str(Core_hmac_md4(Key, data)); } * * Perform a simple self-test to, if the VM is working * * functionMd4_vm_test() { ReturnHex_md4("ABC") == "a448017aaf21d8525fc10ae87aa6729d"; } * * Calculate The MD4 of an array of Little-endian words, and a bit length * * functionCore_md4(X, Len) { /* Append padding * *X[len>> 5]|= 0x80 << (Len%32);x[(((Len +64) >>> 9) << 4)+14]=Len; VarA= 1732584193; VarB=-271733879; VarC=-1732584194; VarD= 271733878; For(VarI= 0;I<X.Length;i += 16) { VarOlda=A; VarOldb=B; VarOldc=C; VarOldd=D;A=Md4_ff(A, B, C, D, x[i+0],3 );D=Md4_ff(D, A, B, C, x[i+1],7 );C=Md4_ff(C, D, a, B, x[i+2],11);B=Md4_ff(b, C, D, a, x[i+3],19);A=Md4_ff(A, B, C, D, x[i+4],3 );D=Md4_ff(D, A, B, C, x[i+5],7 );C=Md4_ff(C, D, a, B, x[i+6],11);B=Md4_ff(b, C, D, a, x[i+7],19);A=Md4_ff(A, B, C, D, x[i+8],3 );D=Md4_ff(D, A, B, C, x[i+9],7 );C=Md4_ff(C, D, a, B, x[i+10],11);B=Md4_ff(b, C, D, a, x[i+11],19);A=Md4_ff(A, B, C, D, x[i+12],3 );D=Md4_ff(D, A, B, C, x[i+13],7 );C=Md4_ff(C, D, a, B, x[i+14],11);B=Md4_ff(b, C, D, a, x[i+15],19);A=Md4_gg(A, B, C, D, x[i+0],3 );D=Md4_gg(D, A, B, C, x[i+4],5 );C=Md4_gg(C, D, a, B, x[i+8],9 );B=Md4_gg(b, C, D, a, x[i+12],13);A=Md4_gg(A, B, C, D, x[i+1],3 );D=Md4_gg(D, A, B, C, x[i+5],5 );C=Md4_gg(C, D, a, B, x[i+9],9 );B=Md4_gg(b, C, D, a, x[i+13],13);A=Md4_gg(A, B, C, D, x[i+2],3 );D=Md4_gg(D, A, B, C, x[i+6],5 );C=Md4_gg(C, D, a, B, x[i+10],9 );B=Md4_gg(b, C, D, a, x[i+14],13);A=Md4_gg(A, B, C, D, x[i+3],3 );D=Md4_gg(D, A, B, C, x[i+7],5 );C=Md4_gg(C, D, a, B, x[i+11],9 );B=Md4_gg(b, C, D, a, x[i+15],13);A=Md4_hh(A, B, C, D, x[i+0],3 );D=Md4_hh(D, A, B, C, x[i+8],9 );C=Md4_hh(C, D, a, B, x[i+4],11);B=Md4_hh(b, C, D, a, x[i+12],15);A=Md4_hh(A, B, C, D, x[i+2],3 );D=Md4_hh(D, A, B, C, x[i+10],9 );C=Md4_hh(C, D, a, B, x[i+6],11);B=Md4_hh(b, C, D, a, x[i+14],15);A=Md4_hh(A, B, C, D, x[i+1],3 );D=Md4_hh(D, A, B, C, x[i+9],9 );C=Md4_hh(C, D, a, B, x[i+5],11);B=Md4_hh(b, C, D, a, x[i+13],15);A=Md4_hh(A, B, C, D, x[i+3],3 );D=Md4_hh(D, A, B, C, x[i+11],9 );C=Md4_hh(C, D, a, B, x[i+7],11);B=Md4_hh(b, C, D, a, x[i+15],15);A=Safe_add(A, Olda);B=Safe_add(B, Oldb);C=Safe_add(C, OLDC);D=Safe_add(D, OLDD); } Return Array(A, B, C, D); } * * These functions implement the basic operation to each round of the * algorithm. */ functionMd4_cmn(Q, A, B, X, S, t) { ReturnSafe_add(Rol(Safe_add(Safe_add(A, q), Safe_add(X, t)), S)B); } functionMd4_ff(A, B, C, D, X, S) { ReturnMd4_cmn((B&C) | ((~b) &D)A0, X, S,0); } functionMd4_gg(A, B, C, D, X, S) { ReturnMd4_cmn((B&C) | (B&D) | (C&D)A0, X, S,1518500249); } functionMd4_hh(A, B, C, D, X, S) { ReturnMd4_cmn(b ^ C ^ D, a,0, X, S,1859775393); } * * Calculate the HMAC-MD4, a key and some data * * functionCore_hmac_md4(Key, data) { VarBkey=Str2binl(Key); If(Bkey.Length > 16)Bkey=Core_md4(Bkey, key.Length* Chrsz); VarIpad= Array(16), Opad= Array(16); For(VarI= 0;I< 16;i++) {Ipad[i]=Bkey[i] ^0x36363636;Opad[i]=Bkey[i] ^0x5c5c5c5c; } Var Hash =Core_md4(Ipad.concat(Str2binl(Data)),512+ data.Length* Chrsz); ReturnCore_md4(Opad.concat(Hash),512+128); } * * Add integers, wrapping at 2^32. This is uses 16-bit operations internally * To work around bugs in some JS interpreters. */ functionSafe_add(X, y) { VarLsw= (X& 0xFFFF)+(Y& 0xFFFF); VarMsw= (X>> 16)+(Y>> 16)+(Lsw>> 16); Return (Msw<< 16) | (Lsw& 0xFFFF); } * * Bitwise rotate a 32-bit number to the left. */ functionRol(NUM, CNT) { Return (Num<<Cnt) | (Num>>> (32-CNT)); } /* Convert A string to an array of Little-endian words * If Chrsz is ASCII, characters >255 have their hi-byte-silent Ly ignored. */ functionStr2binl(Str) { VarBin= Array(); VarMask= (1 <<Chrsz)-1; For(VarI= 0;I<Str.Length* Chrsz;i +=Chrsz)Bin[i>>5]|= (Str.charcodeat(I/Chrsz) &Mask) << (i%32); ReturnBin; } * * Convert An array of Little-endian words to a string * * functionBinl2str(Bin) { VarStr= ""; VarMask= (1 <<Chrsz)-1; For(VarI= 0;I<Bin.Length*32;i +=Chrsz)STR +=String.fromCharCode((Bin[i>>5]>>> (I32)) &Mask); ReturnStr; } * * Convert An array of Little-endian words to a hex string. */ functionBinl2hex(BinArray) { VarHex_tab=Hexcase?"0123456789ABCDEF":"0123456789abcdef"; VarStr= ""; For(VarI= 0;I<BinArray.Length*4;i++) {STR +=Hex_tab.CharAt((Binarray[i>>2]>> ((i%4)*8+4)) & 0xF)+ Hex_tab.CharAt((Binarray[i>>2]>> ((i%4)*8 )) & 0xF); } ReturnStr; } * * Convert An array of Little-endian words to a base-64 string * * functionBinl2b64(BinArray) { Vartab= "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz0123456789+/"; VarStr= ""; For(VarI= 0;I<BinArray.Length*4;i += 3) { VarTriplet= (((Binarray[i>> 2]>> 8*(I4)) & 0xFF) << 16) | (((binarray[i+1 >> 2]>> 8*((i+1)%4)) & 0xFF) << 8 ) | ((binarray[i+2 >> 2]>> 8*((i+2)%4)) & 0xFF); For(VarJ= 0;J< 4;J + +) { If(I8 + J * 6 > binarray.length * 32) str += B64pad
;
else str += tab.charat>> 6*3-j & 0x3f
} return str}