Commit | Line | Data |
---|---|---|
e99c53fb BA |
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) {} |