| 1 | var Sha1 = {}; // SHA-1 namespace |
| 2 | |
| 3 | // SHA-1 algorithm as described at http://en.wikipedia.org/wiki/SHA-1 |
| 4 | // The implementation follows http://fr.wikipedia.org/wiki/Sp%C3%A9cifications_SHA-1 (in french). |
| 5 | // SHA-1 implementation of Chris Veness 2002-2010 [www.movable-type.co.uk] helped a lot for debugging, |
| 6 | // and for hacks like toHexStr(). See his script at http://www.movable-type.co.uk/scripts/sha1.html |
| 7 | Sha1.Compute = function(subject) |
| 8 | { |
| 9 | var i, j, tmp, redIndex, a, b, c, d, e; |
| 10 | |
| 11 | // 1) pretreatment |
| 12 | |
| 13 | // note: no check on message length, since the 2^64 boundary is |
| 14 | // a lot longer than what would be allowed by HTML/PHP |
| 15 | |
| 16 | // add trailing '1' bit (+ 0's padding) to string |
| 17 | subject += String.fromCharCode(0x80); |
| 18 | |
| 19 | // add 8 for two last reserved words to store message length |
| 20 | // 8 = 2 x 4, one 32-bits word is 4 characters (bytes) length. |
| 21 | var L = subject.length + 8; |
| 22 | |
| 23 | // initialize 512-bits blocks representing the message, each containing 16 32-bits words. |
| 24 | // NOTE: one char is 8 bits, so one block in the initial string is 64 chars. |
| 25 | var countBlocks = Math.ceil(L / 64); |
| 26 | var blocks = new Array(countBlocks); |
| 27 | for (i=0; i<countBlocks; i++) |
| 28 | { |
| 29 | var words = new Array(16); |
| 30 | for (j=0; j<16; j++) |
| 31 | { |
| 32 | tmp = subject.substr(64 * i + 4 * j, 4); |
| 33 | // note: running off the end of msg is ok because bitwise ops on NaN return 0 |
| 34 | words[j] = (1 << 24) * tmp.charCodeAt(0) | (1 << 16) * tmp.charCodeAt(1) | (1 << 8) * tmp.charCodeAt(2) | tmp.charCodeAt(3); |
| 35 | } |
| 36 | blocks[i] = words; |
| 37 | } |
| 38 | |
| 39 | // note: 'subject' in our context will never be of length >= 2^32. |
| 40 | // therefore we don't need to fill before-last block. |
| 41 | blocks[countBlocks-1][15] = (subject.length-1) * 8; |
| 42 | |
| 43 | // initialize parts of the final hash |
| 44 | var h0 = 0x67452301; |
| 45 | var h1 = 0xefcdab89; |
| 46 | var h2 = 0x98badcfe; |
| 47 | var h3 = 0x10325476; |
| 48 | var h4 = 0xc3d2e1f0; |
| 49 | |
| 50 | // initialize constants array |
| 51 | var k = [0x5a827999,0x6ed9eba1,0x8f1bbcdc,0xca62c1d6]; |
| 52 | |
| 53 | // 2) computations |
| 54 | |
| 55 | for (i=0; i<blocks.length; i++) |
| 56 | { |
| 57 | // initialize w array |
| 58 | var w = new Array(80); |
| 59 | for (j=0; j<16; j++) w[j] = blocks[i][j]; |
| 60 | for (j=16; j<80; j++) |
| 61 | w[j] = Sha1.LeftRotate(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1); |
| 62 | |
| 63 | // initialize a,b,c,d,e variables |
| 64 | a = h0; |
| 65 | b = h1; |
| 66 | c = h2; |
| 67 | d = h3; |
| 68 | e = h4; |
| 69 | |
| 70 | // iterations over a,b,c,d,e |
| 71 | for (j=0; j<80; j++) |
| 72 | { |
| 73 | // note: '& 0xffffffff' == 'modulo 2^32'. |
| 74 | redIndex = Math.floor(j/20); |
| 75 | tmp = (Sha1.LeftRotate(a, 5) + Sha1.BitOp(b, c, d, redIndex) + e + k[redIndex] + w[j]) & 0xffffffff; |
| 76 | e = d; |
| 77 | d = c; |
| 78 | c = Sha1.LeftRotate(b, 30); |
| 79 | b = a; |
| 80 | a = tmp; |
| 81 | } |
| 82 | |
| 83 | // update intermediate hash values |
| 84 | h0 = (h0+a) & 0xffffffff; |
| 85 | h1 = (h1+b) & 0xffffffff; |
| 86 | h2 = (h2+c) & 0xffffffff; |
| 87 | h3 = (h3+d) & 0xffffffff; |
| 88 | h4 = (h4+e) & 0xffffffff; |
| 89 | } |
| 90 | |
| 91 | return Sha1.ToHexStr(h0)+Sha1.ToHexStr(h1)+Sha1.ToHexStr(h2)+Sha1.ToHexStr(h3)+Sha1.ToHexStr(h4); |
| 92 | } |
| 93 | |
| 94 | // auxiliary functions. |
| 95 | Sha1.BitOp = function(x, y, z, t) |
| 96 | { |
| 97 | if (t == 0) return (x & y) ^ (~x & z); |
| 98 | if (t == 1) return x ^ y ^ z; |
| 99 | if (t == 2) return (x & y) ^ (x & z) ^ (y & z); |
| 100 | if (t == 3) return x ^ y ^ z; |
| 101 | } |
| 102 | |
| 103 | // left rotation (within 32 bits). |
| 104 | Sha1.LeftRotate = function(x, n) |
| 105 | { |
| 106 | return (x << n) | (x >>> (32 - n)); |
| 107 | } |
| 108 | |
| 109 | // [copy-pasted from Chris Veness implementation] |
| 110 | // Hexadecimal representation of a number |
| 111 | // (note toString(16) is implementation-dependant, and |
| 112 | // in IE returns signed numbers when used on full words) |
| 113 | Sha1.ToHexStr = function(x) |
| 114 | { |
| 115 | var s=""; |
| 116 | for (var i=7; i>=0; i--) |
| 117 | { |
| 118 | var v = (x >>> (i*4)) & 0xf; |
| 119 | s += v.toString(16); |
| 120 | } |
| 121 | return s; |
| 122 | } |
| 123 | |
| 124 | try { module.exports = Sha1; } catch (err) {} |