|
| 1 | +/** |
| 2 | + * md5 hashing |
| 3 | + * |
| 4 | + * Uses the built-in 'crypto' library by default for a C implementation |
| 5 | + * of md5, but in case the crypto library has been compiled to disable |
| 6 | + * FIPS-noncompliant hash suites, fall back to a pure JS implementation of |
| 7 | + * md5. |
| 8 | + */ |
| 9 | +import * as crypto from 'crypto'; |
| 10 | + |
| 11 | +let _impl: undefined | ((x: string) => string); |
| 12 | + |
| 13 | +/* eslint-disable no-restricted-syntax */ |
| 14 | + |
| 15 | +/** |
| 16 | + * Return a hash of the given input string, in hex format |
| 17 | + */ |
| 18 | +export function md5hash(x: string) { |
| 19 | + if (!_impl) { |
| 20 | + try { |
| 21 | + crypto.createHash('md5'); |
| 22 | + _impl = cryptoMd5; |
| 23 | + } catch (e) { |
| 24 | + _impl = jsMd5; |
| 25 | + } |
| 26 | + } |
| 27 | + return _impl(x); |
| 28 | +} |
| 29 | + |
| 30 | +/* eslint-disable no-bitwise */ |
| 31 | + |
| 32 | +export function cryptoMd5(x: string) { |
| 33 | + const hash = crypto.createHash('md5'); |
| 34 | + hash.update(x); |
| 35 | + return hash.digest('hex'); |
| 36 | +} |
| 37 | + |
| 38 | +export function jsMd5(s: string) { |
| 39 | + return hex(md5Buffer(Buffer.from(s, 'utf-8'))); |
| 40 | +} |
| 41 | + |
| 42 | +function md5Round(x: number[], k: ReadonlyArray<number>) { |
| 43 | + let a = x[0], b = x[1], c = x[2], d = x[3]; |
| 44 | + |
| 45 | + a = F(a, b, c, d, k[0], 7, -680876936); |
| 46 | + d = F(d, a, b, c, k[1], 12, -389564586); |
| 47 | + c = F(c, d, a, b, k[2], 17, 606105819); |
| 48 | + b = F(b, c, d, a, k[3], 22, -1044525330); |
| 49 | + a = F(a, b, c, d, k[4], 7, -176418897); |
| 50 | + d = F(d, a, b, c, k[5], 12, 1200080426); |
| 51 | + c = F(c, d, a, b, k[6], 17, -1473231341); |
| 52 | + b = F(b, c, d, a, k[7], 22, -45705983); |
| 53 | + a = F(a, b, c, d, k[8], 7, 1770035416); |
| 54 | + d = F(d, a, b, c, k[9], 12, -1958414417); |
| 55 | + c = F(c, d, a, b, k[10], 17, -42063); |
| 56 | + b = F(b, c, d, a, k[11], 22, -1990404162); |
| 57 | + a = F(a, b, c, d, k[12], 7, 1804603682); |
| 58 | + d = F(d, a, b, c, k[13], 12, -40341101); |
| 59 | + c = F(c, d, a, b, k[14], 17, -1502002290); |
| 60 | + b = F(b, c, d, a, k[15], 22, 1236535329); |
| 61 | + |
| 62 | + a = G(a, b, c, d, k[1], 5, -165796510); |
| 63 | + d = G(d, a, b, c, k[6], 9, -1069501632); |
| 64 | + c = G(c, d, a, b, k[11], 14, 643717713); |
| 65 | + b = G(b, c, d, a, k[0], 20, -373897302); |
| 66 | + a = G(a, b, c, d, k[5], 5, -701558691); |
| 67 | + d = G(d, a, b, c, k[10], 9, 38016083); |
| 68 | + c = G(c, d, a, b, k[15], 14, -660478335); |
| 69 | + b = G(b, c, d, a, k[4], 20, -405537848); |
| 70 | + a = G(a, b, c, d, k[9], 5, 568446438); |
| 71 | + d = G(d, a, b, c, k[14], 9, -1019803690); |
| 72 | + c = G(c, d, a, b, k[3], 14, -187363961); |
| 73 | + b = G(b, c, d, a, k[8], 20, 1163531501); |
| 74 | + a = G(a, b, c, d, k[13], 5, -1444681467); |
| 75 | + d = G(d, a, b, c, k[2], 9, -51403784); |
| 76 | + c = G(c, d, a, b, k[7], 14, 1735328473); |
| 77 | + b = G(b, c, d, a, k[12], 20, -1926607734); |
| 78 | + |
| 79 | + a = H(a, b, c, d, k[5], 4, -378558); |
| 80 | + d = H(d, a, b, c, k[8], 11, -2022574463); |
| 81 | + c = H(c, d, a, b, k[11], 16, 1839030562); |
| 82 | + b = H(b, c, d, a, k[14], 23, -35309556); |
| 83 | + a = H(a, b, c, d, k[1], 4, -1530992060); |
| 84 | + d = H(d, a, b, c, k[4], 11, 1272893353); |
| 85 | + c = H(c, d, a, b, k[7], 16, -155497632); |
| 86 | + b = H(b, c, d, a, k[10], 23, -1094730640); |
| 87 | + a = H(a, b, c, d, k[13], 4, 681279174); |
| 88 | + d = H(d, a, b, c, k[0], 11, -358537222); |
| 89 | + c = H(c, d, a, b, k[3], 16, -722521979); |
| 90 | + b = H(b, c, d, a, k[6], 23, 76029189); |
| 91 | + a = H(a, b, c, d, k[9], 4, -640364487); |
| 92 | + d = H(d, a, b, c, k[12], 11, -421815835); |
| 93 | + c = H(c, d, a, b, k[15], 16, 530742520); |
| 94 | + b = H(b, c, d, a, k[2], 23, -995338651); |
| 95 | + |
| 96 | + a = I(a, b, c, d, k[0], 6, -198630844); |
| 97 | + d = I(d, a, b, c, k[7], 10, 1126891415); |
| 98 | + c = I(c, d, a, b, k[14], 15, -1416354905); |
| 99 | + b = I(b, c, d, a, k[5], 21, -57434055); |
| 100 | + a = I(a, b, c, d, k[12], 6, 1700485571); |
| 101 | + d = I(d, a, b, c, k[3], 10, -1894986606); |
| 102 | + c = I(c, d, a, b, k[10], 15, -1051523); |
| 103 | + b = I(b, c, d, a, k[1], 21, -2054922799); |
| 104 | + a = I(a, b, c, d, k[8], 6, 1873313359); |
| 105 | + d = I(d, a, b, c, k[15], 10, -30611744); |
| 106 | + c = I(c, d, a, b, k[6], 15, -1560198380); |
| 107 | + b = I(b, c, d, a, k[13], 21, 1309151649); |
| 108 | + a = I(a, b, c, d, k[4], 6, -145523070); |
| 109 | + d = I(d, a, b, c, k[11], 10, -1120210379); |
| 110 | + c = I(c, d, a, b, k[2], 15, 718787259); |
| 111 | + b = I(b, c, d, a, k[9], 21, -343485551); |
| 112 | + |
| 113 | + x[0] = add32(a, x[0]); |
| 114 | + x[1] = add32(b, x[1]); |
| 115 | + x[2] = add32(c, x[2]); |
| 116 | + x[3] = add32(d, x[3]); |
| 117 | +} |
| 118 | + |
| 119 | +function cmn(q: number, a: number, b: number, x: number, s: number, t: number) { |
| 120 | + a = add32(add32(a, q), add32(x, t)); |
| 121 | + return add32((a << s) | (a >>> (32 - s)), b); |
| 122 | +} |
| 123 | + |
| 124 | +function F(a: number, b: number, c: number, d: number, x: number, s: number, t: number) { |
| 125 | + return cmn((b & c) | (~b & d), a, b, x, s, t); |
| 126 | +} |
| 127 | + |
| 128 | +function G(a: number, b: number, c: number, d: number, x: number, s: number, t: number) { |
| 129 | + return cmn((b & d) | (c & ~d), a, b, x, s, t); |
| 130 | +} |
| 131 | + |
| 132 | +function H(a: number, b: number, c: number, d: number, x: number, s: number, t: number) { |
| 133 | + return cmn(b ^ c ^ d, a, b, x, s, t); |
| 134 | +} |
| 135 | + |
| 136 | +function I(a: number, b: number, c: number, d: number, x: number, s: number, t: number) { |
| 137 | + return cmn(c ^ (b | ~d), a, b, x, s, t); |
| 138 | +} |
| 139 | + |
| 140 | +function md5Buffer(buf: Buffer) { |
| 141 | + let n = buf.length, |
| 142 | + state = [1732584193, -271733879, -1732584194, 271733878], |
| 143 | + i = 0; |
| 144 | + |
| 145 | + for (; i + 64 <= n; i += 64) { |
| 146 | + md5Round(state, bytesToWordsBuf(buf, i)); |
| 147 | + } |
| 148 | + |
| 149 | + // Padding - a single high 1 byte, and the length of the original message at the end |
| 150 | + // Need to add 2 tails if the message is less than 9 bytes shorter than a multiple of 64 |
| 151 | + // (Otherwise not enough room for high bit and the 64 bit size) |
| 152 | + const remainingBytes = n - i; |
| 153 | + const padding = Buffer.alloc(64 - remainingBytes < 9 ? 128 : 64); |
| 154 | + |
| 155 | + buf.copy(padding, 0, i); |
| 156 | + padding.writeUint8(0x80, remainingBytes); // High bit |
| 157 | + |
| 158 | + const bitLength = n * 8; |
| 159 | + padding.writeUint32LE(n << 3, padding.length - 8); |
| 160 | + if (bitLength >= 0xFFFFFFFF) { |
| 161 | + padding.writeUint32LE(Math.floor(bitLength / 0xFFFFFFFF), padding.length - 4); |
| 162 | + } |
| 163 | + |
| 164 | + md5Round(state, bytesToWordsBuf(padding, 0)); |
| 165 | + if (padding.length > 64) { |
| 166 | + md5Round(state, bytesToWordsBuf(padding, 64)); |
| 167 | + } |
| 168 | + |
| 169 | + return state; |
| 170 | +} |
| 171 | + |
| 172 | +function bytesToWordsBuf(buf: Buffer, byteOffset: number) { |
| 173 | + const ret = new Array<number>(16); |
| 174 | + let i = 0, j = byteOffset; |
| 175 | + |
| 176 | + for (; i < 16; i++, j += 4) { |
| 177 | + ret[i] = buf.readUint32LE(j); |
| 178 | + } |
| 179 | + return ret; |
| 180 | +} |
| 181 | + |
| 182 | +let hex_chr = '0123456789abcdef'.split(''); |
| 183 | + |
| 184 | +function hexify(n: number) { |
| 185 | + const s = new Array<string>(); |
| 186 | + for (let j = 0; j < 4; j++) { |
| 187 | + s.push(hex_chr[(n >>> (j * 8 + 4)) & 0x0f] + hex_chr[(n >>> (j * 8)) & 0x0f]); |
| 188 | + } |
| 189 | + return s.join(''); |
| 190 | +} |
| 191 | + |
| 192 | +function hex(x: number[]) { |
| 193 | + const ret = new Array<string>(x.length); |
| 194 | + for (let i = 0; i < x.length; i++) ret[i] = hexify(x[i]); |
| 195 | + return ret.join(''); |
| 196 | +} |
| 197 | + |
| 198 | +function add32(a: number, b: number) { |
| 199 | + return (a + b) & 0xffffffff; |
| 200 | +} |
0 commit comments