blob: 7f60532f625aeed59fae747ec79650807b2efdec [file] [log] [blame]
Alexander Afanasyev181a8b92013-02-28 13:28:53 -08001/*
2 * A JavaScript implementation of the RIPEMD-160 Algorithm
3 * Version 2.2 Copyright Jeremy Lin, Paul Johnston 2000 - 2009.
4 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
5 * Distributed under the BSD License
6 * See http://pajhome.org.uk/crypt/md5 for details.
7 * Also http://www.ocf.berkeley.edu/~jjlin/jsotp/
8 */
9
10/*
11 * Configurable variables. You may need to tweak these to be compatible with
12 * the server-side, but the defaults work in most cases.
13 */
14var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
15var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
16
17/*
18 * These are the functions you'll usually want to call
19 * They take string arguments and return either hex or base-64 encoded strings
20 */
21function hex_rmd160(s) { return rstr2hex(rstr_rmd160(str2rstr_utf8(s))); }
22function b64_rmd160(s) { return rstr2b64(rstr_rmd160(str2rstr_utf8(s))); }
23function any_rmd160(s, e) { return rstr2any(rstr_rmd160(str2rstr_utf8(s)), e); }
24function hex_hmac_rmd160(k, d)
25 { return rstr2hex(rstr_hmac_rmd160(str2rstr_utf8(k), str2rstr_utf8(d))); }
26function b64_hmac_rmd160(k, d)
27 { return rstr2b64(rstr_hmac_rmd160(str2rstr_utf8(k), str2rstr_utf8(d))); }
28function any_hmac_rmd160(k, d, e)
29 { return rstr2any(rstr_hmac_rmd160(str2rstr_utf8(k), str2rstr_utf8(d)), e); }
30
31/*
32 * Perform a simple self-test to see if the VM is working
33 */
34function rmd160_vm_test()
35{
36 return hex_rmd160("abc").toLowerCase() == "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc";
37}
38
39/*
40 * Calculate the rmd160 of a raw string
41 */
42function rstr_rmd160(s)
43{
44 return binl2rstr(binl_rmd160(rstr2binl(s), s.length * 8));
45}
46
47/*
48 * Calculate the HMAC-rmd160 of a key and some data (raw strings)
49 */
50function rstr_hmac_rmd160(key, data)
51{
52 var bkey = rstr2binl(key);
53 if(bkey.length > 16) bkey = binl_rmd160(bkey, key.length * 8);
54
55 var ipad = Array(16), opad = Array(16);
56 for(var i = 0; i < 16; i++)
57 {
58 ipad[i] = bkey[i] ^ 0x36363636;
59 opad[i] = bkey[i] ^ 0x5C5C5C5C;
60 }
61
62 var hash = binl_rmd160(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
63 return binl2rstr(binl_rmd160(opad.concat(hash), 512 + 160));
64}
65
66/*
67 * Convert a raw string to a hex string
68 */
69function rstr2hex(input)
70{
71 try { hexcase } catch(e) { hexcase=0; }
72 var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
73 var output = "";
74 var x;
75 for(var i = 0; i < input.length; i++)
76 {
77 x = input.charCodeAt(i);
78 output += hex_tab.charAt((x >>> 4) & 0x0F)
79 + hex_tab.charAt( x & 0x0F);
80 }
81 return output;
82}
83
84/*
85 * Convert a raw string to a base-64 string
86 */
87function rstr2b64(input)
88{
89 try { b64pad } catch(e) { b64pad=''; }
90 var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
91 var output = "";
92 var len = input.length;
93 for(var i = 0; i < len; i += 3)
94 {
95 var triplet = (input.charCodeAt(i) << 16)
96 | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
97 | (i + 2 < len ? input.charCodeAt(i+2) : 0);
98 for(var j = 0; j < 4; j++)
99 {
100 if(i * 8 + j * 6 > input.length * 8) output += b64pad;
101 else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
102 }
103 }
104 return output;
105}
106
107/*
108 * Convert a raw string to an arbitrary string encoding
109 */
110function rstr2any(input, encoding)
111{
112 var divisor = encoding.length;
113 var remainders = Array();
114 var i, q, x, quotient;
115
116 /* Convert to an array of 16-bit big-endian values, forming the dividend */
117 var dividend = Array(Math.ceil(input.length / 2));
118 for(i = 0; i < dividend.length; i++)
119 {
120 dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
121 }
122
123 /*
124 * Repeatedly perform a long division. The binary array forms the dividend,
125 * the length of the encoding is the divisor. Once computed, the quotient
126 * forms the dividend for the next step. We stop when the dividend is zero.
127 * All remainders are stored for later use.
128 */
129 while(dividend.length > 0)
130 {
131 quotient = Array();
132 x = 0;
133 for(i = 0; i < dividend.length; i++)
134 {
135 x = (x << 16) + dividend[i];
136 q = Math.floor(x / divisor);
137 x -= q * divisor;
138 if(quotient.length > 0 || q > 0)
139 quotient[quotient.length] = q;
140 }
141 remainders[remainders.length] = x;
142 dividend = quotient;
143 }
144
145 /* Convert the remainders to the output string */
146 var output = "";
147 for(i = remainders.length - 1; i >= 0; i--)
148 output += encoding.charAt(remainders[i]);
149
150 /* Append leading zero equivalents */
151 var full_length = Math.ceil(input.length * 8 /
152 (Math.log(encoding.length) / Math.log(2)))
153 for(i = output.length; i < full_length; i++)
154 output = encoding[0] + output;
155
156 return output;
157}
158
159/*
160 * Encode a string as utf-8.
161 * For efficiency, this assumes the input is valid utf-16.
162 */
163function str2rstr_utf8(input)
164{
165 var output = "";
166 var i = -1;
167 var x, y;
168
169 while(++i < input.length)
170 {
171 /* Decode utf-16 surrogate pairs */
172 x = input.charCodeAt(i);
173 y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
174 if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)
175 {
176 x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
177 i++;
178 }
179
180 /* Encode output as utf-8 */
181 if(x <= 0x7F)
182 output += String.fromCharCode(x);
183 else if(x <= 0x7FF)
184 output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
185 0x80 | ( x & 0x3F));
186 else if(x <= 0xFFFF)
187 output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
188 0x80 | ((x >>> 6 ) & 0x3F),
189 0x80 | ( x & 0x3F));
190 else if(x <= 0x1FFFFF)
191 output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
192 0x80 | ((x >>> 12) & 0x3F),
193 0x80 | ((x >>> 6 ) & 0x3F),
194 0x80 | ( x & 0x3F));
195 }
196 return output;
197}
198
199/*
200 * Encode a string as utf-16
201 */
202function str2rstr_utf16le(input)
203{
204 var output = "";
205 for(var i = 0; i < input.length; i++)
206 output += String.fromCharCode( input.charCodeAt(i) & 0xFF,
207 (input.charCodeAt(i) >>> 8) & 0xFF);
208 return output;
209}
210
211function str2rstr_utf16be(input)
212{
213 var output = "";
214 for(var i = 0; i < input.length; i++)
215 output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
216 input.charCodeAt(i) & 0xFF);
217 return output;
218}
219
220/*
221 * Convert a raw string to an array of little-endian words
222 * Characters >255 have their high-byte silently ignored.
223 */
224function rstr2binl(input)
225{
226 var output = Array(input.length >> 2);
227 for(var i = 0; i < output.length; i++)
228 output[i] = 0;
229 for(var i = 0; i < input.length * 8; i += 8)
230 output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (i%32);
231 return output;
232}
233
234/*
235 * Convert an array of little-endian words to a string
236 */
237function binl2rstr(input)
238{
239 var output = "";
240 for(var i = 0; i < input.length * 32; i += 8)
241 output += String.fromCharCode((input[i>>5] >>> (i % 32)) & 0xFF);
242 return output;
243}
244
245/*
246 * Calculate the RIPE-MD160 of an array of little-endian words, and a bit length.
247 */
248function binl_rmd160(x, len)
249{
250 /* append padding */
251 x[len >> 5] |= 0x80 << (len % 32);
252 x[(((len + 64) >>> 9) << 4) + 14] = len;
253
254 var h0 = 0x67452301;
255 var h1 = 0xefcdab89;
256 var h2 = 0x98badcfe;
257 var h3 = 0x10325476;
258 var h4 = 0xc3d2e1f0;
259
260 for (var i = 0; i < x.length; i += 16) {
261 var T;
262 var A1 = h0, B1 = h1, C1 = h2, D1 = h3, E1 = h4;
263 var A2 = h0, B2 = h1, C2 = h2, D2 = h3, E2 = h4;
264 for (var j = 0; j <= 79; ++j) {
265 T = safe_add(A1, rmd160_f(j, B1, C1, D1));
266 T = safe_add(T, x[i + rmd160_r1[j]]);
267 T = safe_add(T, rmd160_K1(j));
268 T = safe_add(bit_rol(T, rmd160_s1[j]), E1);
269 A1 = E1; E1 = D1; D1 = bit_rol(C1, 10); C1 = B1; B1 = T;
270 T = safe_add(A2, rmd160_f(79-j, B2, C2, D2));
271 T = safe_add(T, x[i + rmd160_r2[j]]);
272 T = safe_add(T, rmd160_K2(j));
273 T = safe_add(bit_rol(T, rmd160_s2[j]), E2);
274 A2 = E2; E2 = D2; D2 = bit_rol(C2, 10); C2 = B2; B2 = T;
275 }
276 T = safe_add(h1, safe_add(C1, D2));
277 h1 = safe_add(h2, safe_add(D1, E2));
278 h2 = safe_add(h3, safe_add(E1, A2));
279 h3 = safe_add(h4, safe_add(A1, B2));
280 h4 = safe_add(h0, safe_add(B1, C2));
281 h0 = T;
282 }
283 return [h0, h1, h2, h3, h4];
284}
285
286function rmd160_f(j, x, y, z)
287{
288 return ( 0 <= j && j <= 15) ? (x ^ y ^ z) :
289 (16 <= j && j <= 31) ? (x & y) | (~x & z) :
290 (32 <= j && j <= 47) ? (x | ~y) ^ z :
291 (48 <= j && j <= 63) ? (x & z) | (y & ~z) :
292 (64 <= j && j <= 79) ? x ^ (y | ~z) :
293 "rmd160_f: j out of range";
294}
295function rmd160_K1(j)
296{
297 return ( 0 <= j && j <= 15) ? 0x00000000 :
298 (16 <= j && j <= 31) ? 0x5a827999 :
299 (32 <= j && j <= 47) ? 0x6ed9eba1 :
300 (48 <= j && j <= 63) ? 0x8f1bbcdc :
301 (64 <= j && j <= 79) ? 0xa953fd4e :
302 "rmd160_K1: j out of range";
303}
304function rmd160_K2(j)
305{
306 return ( 0 <= j && j <= 15) ? 0x50a28be6 :
307 (16 <= j && j <= 31) ? 0x5c4dd124 :
308 (32 <= j && j <= 47) ? 0x6d703ef3 :
309 (48 <= j && j <= 63) ? 0x7a6d76e9 :
310 (64 <= j && j <= 79) ? 0x00000000 :
311 "rmd160_K2: j out of range";
312}
313var rmd160_r1 = [
314 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
315 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
316 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
317 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
318 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13
319];
320var rmd160_r2 = [
321 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
322 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
323 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
324 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
325 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11
326];
327var rmd160_s1 = [
328 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
329 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
330 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
331 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
332 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6
333];
334var rmd160_s2 = [
335 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
336 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
337 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
338 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
339 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11
340];
341
342/*
343 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
344 * to work around bugs in some JS interpreters.
345 */
346function safe_add(x, y)
347{
348 var lsw = (x & 0xFFFF) + (y & 0xFFFF);
349 var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
350 return (msw << 16) | (lsw & 0xFFFF);
351}
352
353/*
354 * Bitwise rotate a 32-bit number to the left.
355 */
356function bit_rol(num, cnt)
357{
358 return (num << cnt) | (num >>> (32 - cnt));
359}