// Emacs settings: -*- mode: Fundamental; tab-width: 4; -*- //////////////////////////////////////////////////////////////////////////// // // // An implementation of MD5, from RFC 1321 (not the C code) // // Also HMAC-MD5, from RFC 2104 // // // // See also the test code in md5.html // // // // Copyright (c) 2005, Andrew Birrell // // // //////////////////////////////////////////////////////////////////////////// function md5LShift(x, n) { // Left circular shift of x by n bits return (x << n) | (x >>> (32-n)); } function md5Add32(x, y) { // Add mod 2^32 var ls = (x & 0xFFFF) + (y & 0xFFFF); var ms = (x >> 16) + (y >> 16) + (ls >> 16); return (ms << 16) | (ls & 0xFFFF); } function md5Rounds(a, b, fghi, x, s, t) { // Common subroutine in each round return md5Add32(b, md5LShift(md5Add32(md5Add32(a,fghi),md5Add32(x,t)), s)); } function md5Round1(a, b, c, d, x, s, t) { return md5Rounds(a, b, (b & c) | (~b & d), x, s, t); } function md5Round2(a, b, c, d, x, s, t) { return md5Rounds(a, b, (b & d) | (c & ~d), x, s, t); } function md5Round3(a, b, c, d, x, s, t) { return md5Rounds(a, b, b ^ c ^ d, x, s, t); } function md5Round4(a, b, c, d, x, s, t) { return md5Rounds(a, b, c ^ (b | ~d), x, s, t); } function md5Raw(str) { // Return array of four 32-bit words, containing the MD5 hash of str // Bit order within the words is as specified in the RFC 1321 text // Assumes str.length is less than 256 MBytes (I'm lazy) // Javascript strings are in Unicode; MD5 applies to bit sequences. // This function runs MD5 on the bottom 8 bits of the character codes. // You might want to convert to UTF-8 before calling this function. // This is especially true if the string will be converted to UTF-8 // later, e.g., by a call of encodeURIComponent. var byteCount = str.length; var wordCount = (((byteCount + 8) >>> 6) * 16) + 16; var words = new Array(wordCount); var i; for (i = 0; i < words.length; i++) words[i] = 0; for (i = 0; i < byteCount; i++) { words[i >> 2] |= (str.charCodeAt(i) & 255) << ((i % 4) * 8); } words[byteCount >> 2] |= 0x80 << ((byteCount % 4) * 8); words[wordCount-2] = byteCount*8; // Low-order 32 bits of bit-count words[wordCount-1] = 0; // High-order part of bit-count, in principle var a = 1732584193; // Translated from hex, to avoid overflow var b = -271733879; var c = -1732584194; var d = 271733878; for (i = 0; i < wordCount; i += 16) { var aa = a; var bb = b; var cc = c; var dd = d; // Round 1 a=md5Round1(a, b, c, d, words[i], 7, -680876936); d=md5Round1(d, a, b, c, words[i+1], 12, -389564586); c=md5Round1(c, d, a, b, words[i+2], 17, 606105819); b=md5Round1(b, c, d, a, words[i+3], 22, -1044525330); a=md5Round1(a, b, c, d, words[i+4], 7, -176418897); d=md5Round1(d, a, b, c, words[i+5], 12, 1200080426); c=md5Round1(c, d, a, b, words[i+6], 17, -1473231341); b=md5Round1(b, c, d, a, words[i+7], 22, -45705983); a=md5Round1(a, b, c, d, words[i+8], 7, 1770035416); d=md5Round1(d, a, b, c, words[i+9], 12, -1958414417); c=md5Round1(c, d, a, b, words[i+10], 17, -42063); b=md5Round1(b, c, d, a, words[i+11], 22, -1990404162); a=md5Round1(a, b, c, d, words[i+12], 7, 1804603682); d=md5Round1(d, a, b, c, words[i+13], 12, -40341101); c=md5Round1(c, d, a, b, words[i+14], 17, -1502002290); b=md5Round1(b, c, d, a, words[i+15], 22, 1236535329); // Round 2 a=md5Round2(a, b, c, d, words[i+1], 5, -165796510); d=md5Round2(d, a, b, c, words[i+6], 9, -1069501632); c=md5Round2(c, d, a, b, words[i+11], 14, 643717713); b=md5Round2(b, c, d, a, words[i], 20, -373897302); a=md5Round2(a, b, c, d, words[i+5], 5, -701558691); d=md5Round2(d, a, b, c, words[i+10], 9, 38016083); c=md5Round2(c, d, a, b, words[i+15], 14, -660478335); b=md5Round2(b, c, d, a, words[i+4], 20, -405537848); a=md5Round2(a, b, c, d, words[i+9], 5, 568446438); d=md5Round2(d, a, b, c, words[i+14], 9, -1019803690); c=md5Round2(c, d, a, b, words[i+3], 14, -187363961); b=md5Round2(b, c, d, a, words[i+8], 20, 1163531501); a=md5Round2(a, b, c, d, words[i+13], 5, -1444681467); d=md5Round2(d, a, b, c, words[i+2], 9, -51403784); c=md5Round2(c, d, a, b, words[i+7], 14, 1735328473); b=md5Round2(b, c, d, a, words[i+12], 20, -1926607734); // Round 3 a=md5Round3(a, b, c, d, words[i+5], 4, -378558); d=md5Round3(d, a, b, c, words[i+8], 11, -2022574463); c=md5Round3(c, d, a, b, words[i+11], 16, 1839030562); b=md5Round3(b, c, d, a, words[i+14], 23, -35309556); a=md5Round3(a, b, c, d, words[i+1], 4, -1530992060); d=md5Round3(d, a, b, c, words[i+4], 11, 1272893353); c=md5Round3(c, d, a, b, words[i+7], 16, -155497632); b=md5Round3(b, c, d, a, words[i+10], 23, -1094730640); a=md5Round3(a, b, c, d, words[i+13], 4, 681279174); d=md5Round3(d, a, b, c, words[i], 11, -358537222); c=md5Round3(c, d, a, b, words[i+3], 16, -722521979); b=md5Round3(b, c, d, a, words[i+6], 23, 76029189); a=md5Round3(a, b, c, d, words[i+9], 4, -640364487); d=md5Round3(d, a, b, c, words[i+12], 11, -421815835); c=md5Round3(c, d, a, b, words[i+15], 16, 530742520); b=md5Round3(b, c, d, a, words[i+2], 23, -995338651); // Round 4 a=md5Round4(a, b, c, d, words[i], 6, -198630844); d=md5Round4(d, a, b, c, words[i+7], 10, 1126891415); c=md5Round4(c, d, a, b, words[i+14], 15, -1416354905); b=md5Round4(b, c, d, a, words[i+5], 21, -57434055); a=md5Round4(a, b, c, d, words[i+12], 6, 1700485571); d=md5Round4(d, a, b, c, words[i+3], 10, -1894986606); c=md5Round4(c, d, a, b, words[i+10], 15, -1051523); b=md5Round4(b, c, d, a, words[i+1], 21, -2054922799); a=md5Round4(a, b, c, d, words[i+8], 6, 1873313359); d=md5Round4(d, a, b, c, words[i+15], 10, -30611744); c=md5Round4(c, d, a, b, words[i+6], 15, -1560198380); b=md5Round4(b, c, d, a, words[i+13], 21, 1309151649); a=md5Round4(a, b, c, d, words[i+4], 6, -145523070); d=md5Round4(d, a, b, c, words[i+11], 10, -1120210379); c=md5Round4(c, d, a, b, words[i+2], 15, 718787259); b=md5Round4(b, c, d, a, words[i+9], 21, -343485551); a = md5Add32(a, aa); b = md5Add32(b, bb); c = md5Add32(c, cc); d = md5Add32(d, dd); } return [a, b, c, d]; } function md5RawToHex(raw) { // convert raw 4-word array to hex string var resStr = ""; var hex = "0123456789abcdef"; for (i = 0; i < 4; i ++) { var word = raw[i]; for (var j = 0; j < 32; j += 8) { resStr += hex.charAt((word >>> (j+4)) & 0xF); resStr += hex.charAt((word >>> j) & 0xF); } } return resStr; } function md5RawToBinary(raw) { // convert raw 4-word array to binary string var resStr = ""; for (i = 0; i < 4; i ++) { var word = raw[i]; for (var j = 0; j < 32; j += 8) { resStr += String.fromCharCode((word >>> j) & 0xFF); } } return resStr; } function md5Hex(str) { // Return the MD5 hash of str as a hex string return md5RawToHex(md5Raw(str)); } function md5Binary(str) { // Return the MD5 hash of str as a binary string return md5RawToBinary(md5Raw(str)); } function md5HmacRaw(str, key) { // Return HMAC-MD5 signature of str with pwd, as 4 binary words. // Javascript strings are in Unicode; MD5 applies to bit sequences. // This function runs MD5 on the bottom 8 bits of the character codes. // You might want to convert to UTF-8 before calling this function. // This is especially true if the strings will be converted to UTF-8 // later, e.g., by a call of encodeURIComponent. var myKey = key; if (myKey.length > 64) myKey = md5Binary(myKey); var iPad = ""; var oPad = ""; for (var i = 0; i < 64; i++) { if (i < myKey.length) { var c = myKey.charCodeAt(i); iPad += String.fromCharCode(0x36 ^ c); oPad += String.fromCharCode(0x5c ^ c); } else { iPad += String.fromCharCode(0x36); oPad += String.fromCharCode(0x5c); } } return md5Raw(oPad + md5Binary(iPad + str)); } function md5HmacHex(str, key) { return md5RawToHex(md5HmacRaw(str, key)); } function md5HmacBinary(str, key) { return md5RawToBinary(md5HmacRaw(str, key)); }