|
| 1 | +/*! @license MIT ©2015-2019 Ruben Verborgh, Ghent University - imec */ |
| 2 | +/* Browser replacement for a subset of crypto. */ |
| 3 | + |
| 4 | +exports.getHashes = () => ['sha1']; |
| 5 | + |
| 6 | +exports.createHash = () => { |
| 7 | + let contents; |
| 8 | + return { |
| 9 | + update: c => contents ? (contents += c) : (contents = c), |
| 10 | + digest: () => sha1(contents), |
| 11 | + }; |
| 12 | +}; |
| 13 | + |
| 14 | +/*! @license MIT ©2002-2014 Chris Veness */ |
| 15 | +/* SHA-1 implementation */ |
| 16 | + |
| 17 | +// constants [§4.2.1] |
| 18 | +const K = [0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6]; |
| 19 | +const pow2to35 = Math.pow(2, 35); |
| 20 | + |
| 21 | +/** |
| 22 | + * Generates SHA-1 hash of string. |
| 23 | + * |
| 24 | + * @param {string} msg - (Unicode) string to be hashed. |
| 25 | + * @returns {string} Hash of msg as hex character string. |
| 26 | + */ |
| 27 | +function sha1(msg = '') { |
| 28 | + // PREPROCESSING |
| 29 | + msg += '\u0080'; // add trailing '1' bit (+ 0's padding) to string [§5.1.1] |
| 30 | + |
| 31 | + // convert string msg into 512-bit/16-integer blocks arrays of ints [§5.2.1] |
| 32 | + const length = msg.length; |
| 33 | + const l = length / 4 + 2; // length (in 32-bit integers) of msg + ‘1’ + appended length |
| 34 | + const N = ~~((l + 15) / 16); // number of 16-integer-blocks required to hold 'l' ints |
| 35 | + const M = new Array(N); |
| 36 | + |
| 37 | + for (let i = 0, index = 0; i < N; i++) { |
| 38 | + M[i] = new Array(16); |
| 39 | + for (let j = 0; j < 16; j++, index++) { // encode 4 chars per integer, big-endian encoding |
| 40 | + M[i][j] = (index < length ? msg.charCodeAt(index) << 24 : 0) | |
| 41 | + (++index < length ? msg.charCodeAt(index) << 16 : 0) | |
| 42 | + (++index < length ? msg.charCodeAt(index) << 8 : 0) | |
| 43 | + (++index < length ? msg.charCodeAt(index) : 0); |
| 44 | + } |
| 45 | + } |
| 46 | + // add length (in bits) into final pair of 32-bit integers (big-endian) [§5.1.1] |
| 47 | + // note: most significant word would be (len-1)*8 >>> 32, but since JS converts |
| 48 | + // bitwise-op args to 32 bits, we need to simulate this by arithmetic operators |
| 49 | + M[N - 1][14] = ~~((length - 1) / pow2to35); |
| 50 | + M[N - 1][15] = ((length - 1) * 8) & 0xffffffff; |
| 51 | + |
| 52 | + // set initial hash value [§5.3.1] |
| 53 | + let H0 = 0x67452301, H1 = 0xefcdab89, H2 = 0x98badcfe, H3 = 0x10325476, H4 = 0xc3d2e1f0; |
| 54 | + |
| 55 | + // HASH COMPUTATION [§6.1.2] |
| 56 | + const W = new Array(80); |
| 57 | + for (let i = 0; i < N; i++) { |
| 58 | + // 1 - prepare message schedule 'W' |
| 59 | + for (let t = 0; t < 16; t++) |
| 60 | + W[t] = M[i][t]; |
| 61 | + for (let t = 16; t < 80; t++) |
| 62 | + W[t] = rotl(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1); |
| 63 | + |
| 64 | + // 2 - initialise five working variables a, b, c, d, e with previous hash value |
| 65 | + let a = H0, b = H1, c = H2, d = H3, e = H4; |
| 66 | + |
| 67 | + // 3 - main loop |
| 68 | + for (let t = 0; t < 80; t++) { |
| 69 | + const s = ~~(t / 20); // seq for blocks of 'f' functions and 'K' constants |
| 70 | + const T = (rotl(a, 5) + f(s, b, c, d) + e + K[s] + W[t]) & 0xffffffff; |
| 71 | + e = d; |
| 72 | + d = c; |
| 73 | + c = rotl(b, 30); |
| 74 | + b = a; |
| 75 | + a = T; |
| 76 | + } |
| 77 | + |
| 78 | + // 4 - compute the new intermediate hash value (note 'addition modulo 2^32') |
| 79 | + H0 = (H0 + a) & 0xffffffff; |
| 80 | + H1 = (H1 + b) & 0xffffffff; |
| 81 | + H2 = (H2 + c) & 0xffffffff; |
| 82 | + H3 = (H3 + d) & 0xffffffff; |
| 83 | + H4 = (H4 + e) & 0xffffffff; |
| 84 | + } |
| 85 | + |
| 86 | + return toHexStr(H0) + toHexStr(H1) + toHexStr(H2) + toHexStr(H3) + toHexStr(H4); |
| 87 | +} |
| 88 | + |
| 89 | +/** |
| 90 | + * Function 'f' [§4.1.1]. |
| 91 | + */ |
| 92 | +function f(s, x, y, z) { |
| 93 | + switch (s) { |
| 94 | + case 0: |
| 95 | + return (x & y) ^ (~x & z); // Ch() |
| 96 | + case 1: |
| 97 | + return x ^ y ^ z; // Parity() |
| 98 | + case 2: |
| 99 | + return (x & y) ^ (x & z) ^ (y & z); // Maj() |
| 100 | + case 3: |
| 101 | + return x ^ y ^ z; // Parity() |
| 102 | + } |
| 103 | +} |
| 104 | + |
| 105 | +/** |
| 106 | + * Rotates left (circular left shift) value x by n positions [§3.2.5]. |
| 107 | + */ |
| 108 | +function rotl(x, n) { |
| 109 | + return (x << n) | (x >>> (32 - n)); |
| 110 | +} |
| 111 | + |
| 112 | +/** |
| 113 | + * Hexadecimal representation of a number. |
| 114 | + */ |
| 115 | +function toHexStr(n) { |
| 116 | + // note can't use toString(16) as it is implementation-dependent, |
| 117 | + // and in IE returns signed numbers when used on full words |
| 118 | + let s = ''; |
| 119 | + for (let i = 7; i >= 0; i--) { |
| 120 | + const v = (n >>> (i * 4)) & 0xf; |
| 121 | + s += v.toString(16); |
| 122 | + } |
| 123 | + return s; |
| 124 | +} |
0 commit comments