UNPKG

10.6 kBPlain TextView Raw
1import { jsSHABase, TWO_PWR_32, H_trunc, H_full, K_sha2, sha_variant_error, parseInputOption } from "./common";
2import {
3 packedValue,
4 FixedLengthOptionsEncodingType,
5 FixedLengthOptionsNoEncodingType,
6 FormatNoTextType,
7} from "./custom_types";
8import { getStrConverter } from "./converters";
9import {
10 ch_64,
11 gamma0_64,
12 gamma1_64,
13 Int_64,
14 maj_64,
15 safeAdd_64_2,
16 safeAdd_64_4,
17 safeAdd_64_5,
18 sigma0_64,
19 sigma1_64,
20} from "./primitives_64";
21
22type VariantType = "SHA-384" | "SHA-512";
23
24const K_sha512 = [
25 new Int_64(K_sha2[0], 0xd728ae22),
26 new Int_64(K_sha2[1], 0x23ef65cd),
27 new Int_64(K_sha2[2], 0xec4d3b2f),
28 new Int_64(K_sha2[3], 0x8189dbbc),
29 new Int_64(K_sha2[4], 0xf348b538),
30 new Int_64(K_sha2[5], 0xb605d019),
31 new Int_64(K_sha2[6], 0xaf194f9b),
32 new Int_64(K_sha2[7], 0xda6d8118),
33 new Int_64(K_sha2[8], 0xa3030242),
34 new Int_64(K_sha2[9], 0x45706fbe),
35 new Int_64(K_sha2[10], 0x4ee4b28c),
36 new Int_64(K_sha2[11], 0xd5ffb4e2),
37 new Int_64(K_sha2[12], 0xf27b896f),
38 new Int_64(K_sha2[13], 0x3b1696b1),
39 new Int_64(K_sha2[14], 0x25c71235),
40 new Int_64(K_sha2[15], 0xcf692694),
41 new Int_64(K_sha2[16], 0x9ef14ad2),
42 new Int_64(K_sha2[17], 0x384f25e3),
43 new Int_64(K_sha2[18], 0x8b8cd5b5),
44 new Int_64(K_sha2[19], 0x77ac9c65),
45 new Int_64(K_sha2[20], 0x592b0275),
46 new Int_64(K_sha2[21], 0x6ea6e483),
47 new Int_64(K_sha2[22], 0xbd41fbd4),
48 new Int_64(K_sha2[23], 0x831153b5),
49 new Int_64(K_sha2[24], 0xee66dfab),
50 new Int_64(K_sha2[25], 0x2db43210),
51 new Int_64(K_sha2[26], 0x98fb213f),
52 new Int_64(K_sha2[27], 0xbeef0ee4),
53 new Int_64(K_sha2[28], 0x3da88fc2),
54 new Int_64(K_sha2[29], 0x930aa725),
55 new Int_64(K_sha2[30], 0xe003826f),
56 new Int_64(K_sha2[31], 0x0a0e6e70),
57 new Int_64(K_sha2[32], 0x46d22ffc),
58 new Int_64(K_sha2[33], 0x5c26c926),
59 new Int_64(K_sha2[34], 0x5ac42aed),
60 new Int_64(K_sha2[35], 0x9d95b3df),
61 new Int_64(K_sha2[36], 0x8baf63de),
62 new Int_64(K_sha2[37], 0x3c77b2a8),
63 new Int_64(K_sha2[38], 0x47edaee6),
64 new Int_64(K_sha2[39], 0x1482353b),
65 new Int_64(K_sha2[40], 0x4cf10364),
66 new Int_64(K_sha2[41], 0xbc423001),
67 new Int_64(K_sha2[42], 0xd0f89791),
68 new Int_64(K_sha2[43], 0x0654be30),
69 new Int_64(K_sha2[44], 0xd6ef5218),
70 new Int_64(K_sha2[45], 0x5565a910),
71 new Int_64(K_sha2[46], 0x5771202a),
72 new Int_64(K_sha2[47], 0x32bbd1b8),
73 new Int_64(K_sha2[48], 0xb8d2d0c8),
74 new Int_64(K_sha2[49], 0x5141ab53),
75 new Int_64(K_sha2[50], 0xdf8eeb99),
76 new Int_64(K_sha2[51], 0xe19b48a8),
77 new Int_64(K_sha2[52], 0xc5c95a63),
78 new Int_64(K_sha2[53], 0xe3418acb),
79 new Int_64(K_sha2[54], 0x7763e373),
80 new Int_64(K_sha2[55], 0xd6b2b8a3),
81 new Int_64(K_sha2[56], 0x5defb2fc),
82 new Int_64(K_sha2[57], 0x43172f60),
83 new Int_64(K_sha2[58], 0xa1f0ab72),
84 new Int_64(K_sha2[59], 0x1a6439ec),
85 new Int_64(K_sha2[60], 0x23631e28),
86 new Int_64(K_sha2[61], 0xde82bde9),
87 new Int_64(K_sha2[62], 0xb2c67915),
88 new Int_64(K_sha2[63], 0xe372532b),
89 new Int_64(0xca273ece, 0xea26619c),
90 new Int_64(0xd186b8c7, 0x21c0c207),
91 new Int_64(0xeada7dd6, 0xcde0eb1e),
92 new Int_64(0xf57d4f7f, 0xee6ed178),
93 new Int_64(0x06f067aa, 0x72176fba),
94 new Int_64(0x0a637dc5, 0xa2c898a6),
95 new Int_64(0x113f9804, 0xbef90dae),
96 new Int_64(0x1b710b35, 0x131c471b),
97 new Int_64(0x28db77f5, 0x23047d84),
98 new Int_64(0x32caab7b, 0x40c72493),
99 new Int_64(0x3c9ebe0a, 0x15c9bebc),
100 new Int_64(0x431d67c4, 0x9c100d4c),
101 new Int_64(0x4cc5d4be, 0xcb3e42b6),
102 new Int_64(0x597f299c, 0xfc657e2a),
103 new Int_64(0x5fcb6fab, 0x3ad6faec),
104 new Int_64(0x6c44198c, 0x4a475817),
105];
106
107/**
108 * Gets the state values for the specified SHA variant.
109 *
110 * @param variant: The SHA-512 family variant.
111 * @returns The initial state values.
112 */
113function getNewState512(variant: VariantType): Int_64[] {
114 if ("SHA-384" === variant) {
115 return [
116 new Int_64(0xcbbb9d5d, H_trunc[0]),
117 new Int_64(0x0629a292a, H_trunc[1]),
118 new Int_64(0x9159015a, H_trunc[2]),
119 new Int_64(0x0152fecd8, H_trunc[3]),
120 new Int_64(0x67332667, H_trunc[4]),
121 new Int_64(0x98eb44a87, H_trunc[5]),
122 new Int_64(0xdb0c2e0d, H_trunc[6]),
123 new Int_64(0x047b5481d, H_trunc[7]),
124 ];
125 } else {
126 /* SHA-512 */
127 return [
128 new Int_64(H_full[0], 0xf3bcc908),
129 new Int_64(H_full[1], 0x84caa73b),
130 new Int_64(H_full[2], 0xfe94f82b),
131 new Int_64(H_full[3], 0x5f1d36f1),
132 new Int_64(H_full[4], 0xade682d1),
133 new Int_64(H_full[5], 0x2b3e6c1f),
134 new Int_64(H_full[6], 0xfb41bd6b),
135 new Int_64(H_full[7], 0x137e2179),
136 ];
137 }
138}
139
140/**
141 * Performs a round of SHA-512 hashing over a block. This clobbers `H`.
142 *
143 * @param block The binary array representation of the block to hash.
144 * @param H The intermediate H values from a previous round.
145 * @returns The resulting H values.
146 */
147function roundSHA512(block: number[], H: Int_64[]): Int_64[] {
148 let a, b, c, d, e, f, g, h, T1, T2, t, offset;
149
150 const W: Int_64[] = [];
151
152 a = H[0];
153 b = H[1];
154 c = H[2];
155 d = H[3];
156 e = H[4];
157 f = H[5];
158 g = H[6];
159 h = H[7];
160
161 for (t = 0; t < 80; t += 1) {
162 if (t < 16) {
163 offset = t * 2;
164 W[t] = new Int_64(block[offset], block[offset + 1]);
165 } else {
166 W[t] = safeAdd_64_4(gamma1_64(W[t - 2]), W[t - 7], gamma0_64(W[t - 15]), W[t - 16]);
167 }
168 T1 = safeAdd_64_5(h, sigma1_64(e), ch_64(e, f, g), K_sha512[t], W[t]);
169 T2 = safeAdd_64_2(sigma0_64(a), maj_64(a, b, c));
170 h = g;
171 g = f;
172 f = e;
173 e = safeAdd_64_2(d, T1);
174 d = c;
175 c = b;
176 b = a;
177 a = safeAdd_64_2(T1, T2);
178 }
179
180 H[0] = safeAdd_64_2(a, H[0]);
181 H[1] = safeAdd_64_2(b, H[1]);
182 H[2] = safeAdd_64_2(c, H[2]);
183 H[3] = safeAdd_64_2(d, H[3]);
184 H[4] = safeAdd_64_2(e, H[4]);
185 H[5] = safeAdd_64_2(f, H[5]);
186 H[6] = safeAdd_64_2(g, H[6]);
187 H[7] = safeAdd_64_2(h, H[7]);
188
189 return H;
190}
191
192/**
193 * Finalizes the SHA-512 hash. This clobbers `remainder` and `H`.
194 *
195 * @param remainder Any leftover unprocessed packed ints that still need to be processed.
196 * @param remainderBinLen The number of bits in `remainder`.
197 * @param processedBinLen The number of bits already processed.
198 * @param H The intermediate H values from a previous round.
199 * @param variant The desired SHA-512 variant.
200 * @returns The array of integers representing the SHA-512 hash of message.
201 */
202function finalizeSHA512(
203 remainder: number[],
204 remainderBinLen: number,
205 processedBinLen: number,
206 H: Int_64[],
207 variant: VariantType
208): number[] {
209 let i, retVal;
210
211 /* The 129 addition is a hack but it works. The correct number is
212 actually 136 (128 + 8) but the below math fails if
213 remainderBinLen + 136 % 1024 = 0. Since remainderBinLen % 8 = 0,
214 "shorting" the addition is OK. */
215 const offset = (((remainderBinLen + 129) >>> 10) << 5) + 31,
216 binaryStringInc = 32,
217 totalLen = remainderBinLen + processedBinLen;
218
219 while (remainder.length <= offset) {
220 remainder.push(0);
221 }
222 /* Append '1' at the end of the binary string */
223 remainder[remainderBinLen >>> 5] |= 0x80 << (24 - (remainderBinLen % 32));
224 /* Append length of binary string in the position such that the new
225 * length is correct. JavaScript numbers are limited to 2^53 so it's
226 * "safe" to treat the totalLen as a 64-bit integer. */
227
228 remainder[offset] = totalLen & 0xffffffff;
229 /* Bitwise operators treat the operand as a 32-bit number so need to
230 * use hacky division and round to get access to upper 32-ish bits */
231 remainder[offset - 1] = (totalLen / TWO_PWR_32) | 0;
232
233 /* This will always be at least 1 full chunk */
234 for (i = 0; i < remainder.length; i += binaryStringInc) {
235 H = roundSHA512(remainder.slice(i, i + binaryStringInc), H);
236 }
237
238 if ("SHA-384" === variant) {
239 H = (H as unknown) as Int_64[];
240 retVal = [
241 H[0].highOrder,
242 H[0].lowOrder,
243 H[1].highOrder,
244 H[1].lowOrder,
245 H[2].highOrder,
246 H[2].lowOrder,
247 H[3].highOrder,
248 H[3].lowOrder,
249 H[4].highOrder,
250 H[4].lowOrder,
251 H[5].highOrder,
252 H[5].lowOrder,
253 ];
254 } else {
255 /* SHA-512 */
256 retVal = [
257 H[0].highOrder,
258 H[0].lowOrder,
259 H[1].highOrder,
260 H[1].lowOrder,
261 H[2].highOrder,
262 H[2].lowOrder,
263 H[3].highOrder,
264 H[3].lowOrder,
265 H[4].highOrder,
266 H[4].lowOrder,
267 H[5].highOrder,
268 H[5].lowOrder,
269 H[6].highOrder,
270 H[6].lowOrder,
271 H[7].highOrder,
272 H[7].lowOrder,
273 ];
274 }
275 return retVal;
276}
277
278export default class jsSHA extends jsSHABase<Int_64[], VariantType> {
279 intermediateState: Int_64[];
280 variantBlockSize: number;
281 bigEndianMod: -1 | 1;
282 outputBinLen: number;
283 isVariableLen: boolean;
284 HMACSupported: boolean;
285
286 /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
287 converterFunc: (input: any, existingBin: number[], existingBinLen: number) => packedValue;
288 roundFunc: (block: number[], H: Int_64[]) => Int_64[];
289 finalizeFunc: (remainder: number[], remainderBinLen: number, processedBinLen: number, H: Int_64[]) => number[];
290 stateCloneFunc: (state: Int_64[]) => Int_64[];
291 newStateFunc: (variant: VariantType) => Int_64[];
292 getMAC: () => number[];
293
294 constructor(variant: VariantType, inputFormat: "TEXT", options?: FixedLengthOptionsEncodingType);
295 constructor(variant: VariantType, inputFormat: FormatNoTextType, options?: FixedLengthOptionsNoEncodingType);
296 // eslint-disable-next-line @typescript-eslint/no-explicit-any
297 constructor(variant: any, inputFormat: any, options?: any) {
298 if (!("SHA-384" === variant || "SHA-512" === variant)) {
299 throw new Error(sha_variant_error);
300 }
301 super(variant, inputFormat, options);
302 const resolvedOptions = options || {};
303
304 // eslint-disable-next-line @typescript-eslint/unbound-method
305 this.getMAC = this._getHMAC;
306 this.HMACSupported = true;
307 this.bigEndianMod = -1;
308 this.converterFunc = getStrConverter(this.inputFormat, this.utfType, this.bigEndianMod);
309 this.roundFunc = roundSHA512;
310 this.stateCloneFunc = function (state): Int_64[] {
311 return state.slice();
312 };
313 this.newStateFunc = getNewState512;
314 this.finalizeFunc = function (remainder, remainderBinLen, processedBinLen, H): number[] {
315 return finalizeSHA512(remainder, remainderBinLen, processedBinLen, H, variant);
316 };
317
318 this.intermediateState = getNewState512(variant);
319 this.variantBlockSize = 1024;
320 this.outputBinLen = "SHA-384" === variant ? 384 : 512;
321 this.isVariableLen = false;
322
323 if (resolvedOptions["hmacKey"]) {
324 this._setHMACKey(parseInputOption("hmacKey", resolvedOptions["hmacKey"], this.bigEndianMod));
325 }
326 }
327}