|
| 1 | +import {get32, add32, rotl32, lil32} from '@arithmetic-type/uint32'; |
| 2 | + |
| 3 | +function cycle(h, k, r, w) { |
| 4 | + // Initialize hash value for this chunk: |
| 5 | + let a = h[0]; |
| 6 | + let b = h[1]; |
| 7 | + let c = h[2]; |
| 8 | + let d = h[3]; |
| 9 | + |
| 10 | + // Main loop |
| 11 | + for (let i = 0; i < 64; ++i) { |
| 12 | + let f; |
| 13 | + let g; |
| 14 | + |
| 15 | + if (i < 16) { |
| 16 | + f = (b & c) | (~b & d); |
| 17 | + g = i; |
| 18 | + } else if (i < 32) { |
| 19 | + f = (d & b) | (~d & c); |
| 20 | + g = (5 * i + 1) % 16; |
| 21 | + } else if (i < 48) { |
| 22 | + f = b ^ c ^ d; |
| 23 | + g = (3 * i + 5) % 16; |
| 24 | + } else { |
| 25 | + f = c ^ (b | ~d); |
| 26 | + g = (7 * i) % 16; |
| 27 | + } |
| 28 | + |
| 29 | + const t = d; |
| 30 | + d = c; |
| 31 | + c = b; |
| 32 | + b = add32(b, rotl32(add32(add32(a, f), add32(k[i], w[g])), r[i])); |
| 33 | + a = t; |
| 34 | + } |
| 35 | + |
| 36 | + // Add this chunk's hash to result so far: |
| 37 | + h[0] = add32(h[0], a); |
| 38 | + h[1] = add32(h[1], b); |
| 39 | + h[2] = add32(h[2], c); |
| 40 | + h[3] = add32(h[3], d); |
| 41 | +} |
| 42 | + |
| 43 | +function call(h, k, r, data, o) { |
| 44 | + // Break chunk into sixteen 32-bit little-endian words w[i], 0 ≤ i ≤ 15 |
| 45 | + |
| 46 | + const w = [ |
| 47 | + lil32(data, o + 0), |
| 48 | + lil32(data, o + 4), |
| 49 | + lil32(data, o + 8), |
| 50 | + lil32(data, o + 12), |
| 51 | + lil32(data, o + 16), |
| 52 | + lil32(data, o + 20), |
| 53 | + lil32(data, o + 24), |
| 54 | + lil32(data, o + 28), |
| 55 | + lil32(data, o + 32), |
| 56 | + lil32(data, o + 36), |
| 57 | + lil32(data, o + 40), |
| 58 | + lil32(data, o + 44), |
| 59 | + lil32(data, o + 48), |
| 60 | + lil32(data, o + 52), |
| 61 | + lil32(data, o + 56), |
| 62 | + lil32(data, o + 60), |
| 63 | + ]; |
| 64 | + |
| 65 | + cycle(h, k, r, w); |
| 66 | +} |
| 67 | + |
| 68 | +/** |
| 69 | + * MD5 |
| 70 | + */ |
| 71 | +export function md5(bytes, n, digest) { |
| 72 | + const k = [ |
| 73 | + get32(0xd7_6a_a4_78), |
| 74 | + get32(0xe8_c7_b7_56), |
| 75 | + get32(0x24_20_70_db), |
| 76 | + get32(0xc1_bd_ce_ee), |
| 77 | + get32(0xf5_7c_0f_af), |
| 78 | + get32(0x47_87_c6_2a), |
| 79 | + get32(0xa8_30_46_13), |
| 80 | + get32(0xfd_46_95_01), |
| 81 | + get32(0x69_80_98_d8), |
| 82 | + get32(0x8b_44_f7_af), |
| 83 | + get32(0xff_ff_5b_b1), |
| 84 | + get32(0x89_5c_d7_be), |
| 85 | + get32(0x6b_90_11_22), |
| 86 | + get32(0xfd_98_71_93), |
| 87 | + get32(0xa6_79_43_8e), |
| 88 | + get32(0x49_b4_08_21), |
| 89 | + get32(0xf6_1e_25_62), |
| 90 | + get32(0xc0_40_b3_40), |
| 91 | + get32(0x26_5e_5a_51), |
| 92 | + get32(0xe9_b6_c7_aa), |
| 93 | + get32(0xd6_2f_10_5d), |
| 94 | + get32(0x02_44_14_53), |
| 95 | + get32(0xd8_a1_e6_81), |
| 96 | + get32(0xe7_d3_fb_c8), |
| 97 | + get32(0x21_e1_cd_e6), |
| 98 | + get32(0xc3_37_07_d6), |
| 99 | + get32(0xf4_d5_0d_87), |
| 100 | + get32(0x45_5a_14_ed), |
| 101 | + get32(0xa9_e3_e9_05), |
| 102 | + get32(0xfc_ef_a3_f8), |
| 103 | + get32(0x67_6f_02_d9), |
| 104 | + get32(0x8d_2a_4c_8a), |
| 105 | + get32(0xff_fa_39_42), |
| 106 | + get32(0x87_71_f6_81), |
| 107 | + get32(0x6d_9d_61_22), |
| 108 | + get32(0xfd_e5_38_0c), |
| 109 | + get32(0xa4_be_ea_44), |
| 110 | + get32(0x4b_de_cf_a9), |
| 111 | + get32(0xf6_bb_4b_60), |
| 112 | + get32(0xbe_bf_bc_70), |
| 113 | + get32(0x28_9b_7e_c6), |
| 114 | + get32(0xea_a1_27_fa), |
| 115 | + get32(0xd4_ef_30_85), |
| 116 | + get32(0x04_88_1d_05), |
| 117 | + get32(0xd9_d4_d0_39), |
| 118 | + get32(0xe6_db_99_e5), |
| 119 | + get32(0x1f_a2_7c_f8), |
| 120 | + get32(0xc4_ac_56_65), |
| 121 | + get32(0xf4_29_22_44), |
| 122 | + get32(0x43_2a_ff_97), |
| 123 | + get32(0xab_94_23_a7), |
| 124 | + get32(0xfc_93_a0_39), |
| 125 | + get32(0x65_5b_59_c3), |
| 126 | + get32(0x8f_0c_cc_92), |
| 127 | + get32(0xff_ef_f4_7d), |
| 128 | + get32(0x85_84_5d_d1), |
| 129 | + get32(0x6f_a8_7e_4f), |
| 130 | + get32(0xfe_2c_e6_e0), |
| 131 | + get32(0xa3_01_43_14), |
| 132 | + get32(0x4e_08_11_a1), |
| 133 | + get32(0xf7_53_7e_82), |
| 134 | + get32(0xbd_3a_f2_35), |
| 135 | + get32(0x2a_d7_d2_bb), |
| 136 | + get32(0xeb_86_d3_91), |
| 137 | + ]; |
| 138 | + |
| 139 | + const r = [ |
| 140 | + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, |
| 141 | + 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, |
| 142 | + 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, |
| 143 | + 15, 21, |
| 144 | + ]; |
| 145 | + |
| 146 | + // PREPARE |
| 147 | + |
| 148 | + const q = (n / 8) | 0; |
| 149 | + const z = q * 8; |
| 150 | + const u = n - z; |
| 151 | + |
| 152 | + // Append the bit '1' to the message |
| 153 | + const last = u > 0 ? bytes[q] & (~0 << (7 - u)) : 0x80; |
| 154 | + |
| 155 | + // Initialize state |
| 156 | + const h = [ |
| 157 | + get32(0x67_45_23_01), |
| 158 | + get32(0xef_cd_ab_89), |
| 159 | + get32(0x98_ba_dc_fe), |
| 160 | + get32(0x10_32_54_76), |
| 161 | + ]; |
| 162 | + |
| 163 | + // Process the message in successive 512-bit chunks: |
| 164 | + // break message into 512-bit chunks |
| 165 | + |
| 166 | + const m = (n / 512) | 0; |
| 167 | + const y = ((n - 512 * m) / 8) | 0; |
| 168 | + |
| 169 | + // Offset in data |
| 170 | + let o = 0; |
| 171 | + |
| 172 | + // For each chunk |
| 173 | + for (let j = 0; j < m; ++j, o += 64) { |
| 174 | + call(h, k, r, bytes, o); |
| 175 | + } |
| 176 | + |
| 177 | + // Last bytes + padding + length |
| 178 | + let tail = []; |
| 179 | + |
| 180 | + // Last bytes |
| 181 | + for (let j = 0; j < y; ++j) { |
| 182 | + tail.push(bytes[o + j]); |
| 183 | + } |
| 184 | + |
| 185 | + // Special care taken for the very last byte which could |
| 186 | + // have been modified if n is not a multiple of 8 |
| 187 | + tail.push(last); |
| 188 | + |
| 189 | + // Append 0 ≤ k < 512 bits '0', so that the resulting |
| 190 | + // message length (in bits) is congruent to 448 (mod 512) |
| 191 | + let zeroes = ((448 - ((n + 1) % 512)) / 8) | 0; |
| 192 | + |
| 193 | + if (zeroes < 0) { |
| 194 | + // We need an additional block as there is |
| 195 | + // not enough space left to append |
| 196 | + // the length of the data in bits |
| 197 | + |
| 198 | + for (let j = 0; j < -zeroes; ++j) { |
| 199 | + tail.push(0); |
| 200 | + } |
| 201 | + |
| 202 | + call(h, k, r, tail, 0); |
| 203 | + |
| 204 | + zeroes = 448 / 8; |
| 205 | + tail = []; |
| 206 | + } |
| 207 | + |
| 208 | + // Pad with zeroes |
| 209 | + for (let j = 0; j < zeroes; ++j) { |
| 210 | + tail.push(0); |
| 211 | + } |
| 212 | + |
| 213 | + // Append length of message (before preparation), in bits, |
| 214 | + // as 64-bit little-endian integer |
| 215 | + |
| 216 | + tail.push( |
| 217 | + (n >>> 0) & 0xff, |
| 218 | + (n >>> 8) & 0xff, |
| 219 | + (n >>> 16) & 0xff, |
| 220 | + (n >>> 24) & 0xff, |
| 221 | + 0, |
| 222 | + 0, |
| 223 | + 0, |
| 224 | + 0, |
| 225 | + ); |
| 226 | + |
| 227 | + call(h, k, r, tail, 0); |
| 228 | + |
| 229 | + digest[0] = (h[0] >>> 0) & 0xff; |
| 230 | + digest[1] = (h[0] >>> 8) & 0xff; |
| 231 | + digest[2] = (h[0] >>> 16) & 0xff; |
| 232 | + digest[3] = (h[0] >>> 24) & 0xff; |
| 233 | + digest[4] = (h[1] >>> 0) & 0xff; |
| 234 | + digest[5] = (h[1] >>> 8) & 0xff; |
| 235 | + digest[6] = (h[1] >>> 16) & 0xff; |
| 236 | + digest[7] = (h[1] >>> 24) & 0xff; |
| 237 | + digest[8] = (h[2] >>> 0) & 0xff; |
| 238 | + digest[9] = (h[2] >>> 8) & 0xff; |
| 239 | + digest[10] = (h[2] >>> 16) & 0xff; |
| 240 | + digest[11] = (h[2] >>> 24) & 0xff; |
| 241 | + digest[12] = (h[3] >>> 0) & 0xff; |
| 242 | + digest[13] = (h[3] >>> 8) & 0xff; |
| 243 | + digest[14] = (h[3] >>> 16) & 0xff; |
| 244 | + digest[15] = (h[3] >>> 24) & 0xff; |
| 245 | + |
| 246 | + return digest; |
| 247 | +} |
0 commit comments