1 | import { jsSHABase, TWO_PWR_32, H_full, H_trunc, K_sha2, sha_variant_error, parseInputOption } from "./common";
|
2 | import {
|
3 | packedValue,
|
4 | FixedLengthOptionsEncodingType,
|
5 | FixedLengthOptionsNoEncodingType,
|
6 | FormatNoTextType,
|
7 | } from "./custom_types";
|
8 | import { getStrConverter } from "./converters";
|
9 | import {
|
10 | ch_32,
|
11 | gamma0_32,
|
12 | gamma1_32,
|
13 | maj_32,
|
14 | safeAdd_32_2,
|
15 | safeAdd_32_4,
|
16 | safeAdd_32_5,
|
17 | sigma0_32,
|
18 | sigma1_32,
|
19 | } from "./primitives_32";
|
20 |
|
21 | type VariantType = "SHA-224" | "SHA-256";
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 | function getNewState256(variant: VariantType): number[] {
|
30 | let retVal;
|
31 |
|
32 | if ("SHA-224" == variant) {
|
33 | retVal = H_trunc.slice();
|
34 | } else {
|
35 |
|
36 | retVal = H_full.slice();
|
37 | }
|
38 | return retVal;
|
39 | }
|
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 | function roundSHA256(block: number[], H: number[]): number[] {
|
49 | let a, b, c, d, e, f, g, h, T1, T2, t;
|
50 |
|
51 | const W: number[] = [];
|
52 |
|
53 | a = H[0];
|
54 | b = H[1];
|
55 | c = H[2];
|
56 | d = H[3];
|
57 | e = H[4];
|
58 | f = H[5];
|
59 | g = H[6];
|
60 | h = H[7];
|
61 |
|
62 | for (t = 0; t < 64; t += 1) {
|
63 | if (t < 16) {
|
64 | W[t] = block[t];
|
65 | } else {
|
66 | W[t] = safeAdd_32_4(gamma1_32(W[t - 2]), W[t - 7], gamma0_32(W[t - 15]), W[t - 16]);
|
67 | }
|
68 | T1 = safeAdd_32_5(h, sigma1_32(e), ch_32(e, f, g), K_sha2[t], W[t]);
|
69 | T2 = safeAdd_32_2(sigma0_32(a), maj_32(a, b, c));
|
70 | h = g;
|
71 | g = f;
|
72 | f = e;
|
73 | e = safeAdd_32_2(d, T1);
|
74 | d = c;
|
75 | c = b;
|
76 | b = a;
|
77 | a = safeAdd_32_2(T1, T2);
|
78 | }
|
79 |
|
80 | H[0] = safeAdd_32_2(a, H[0]);
|
81 | H[1] = safeAdd_32_2(b, H[1]);
|
82 | H[2] = safeAdd_32_2(c, H[2]);
|
83 | H[3] = safeAdd_32_2(d, H[3]);
|
84 | H[4] = safeAdd_32_2(e, H[4]);
|
85 | H[5] = safeAdd_32_2(f, H[5]);
|
86 | H[6] = safeAdd_32_2(g, H[6]);
|
87 | H[7] = safeAdd_32_2(h, H[7]);
|
88 |
|
89 | return H;
|
90 | }
|
91 |
|
92 |
|
93 |
|
94 |
|
95 |
|
96 |
|
97 |
|
98 |
|
99 |
|
100 |
|
101 |
|
102 | function finalizeSHA256(
|
103 | remainder: number[],
|
104 | remainderBinLen: number,
|
105 | processedBinLen: number,
|
106 | H: number[],
|
107 | variant: VariantType
|
108 | ): number[] {
|
109 | let i, retVal;
|
110 |
|
111 | |
112 |
|
113 |
|
114 |
|
115 | const offset = (((remainderBinLen + 65) >>> 9) << 4) + 15,
|
116 | binaryStringInc = 16,
|
117 | totalLen = remainderBinLen + processedBinLen;
|
118 |
|
119 | while (remainder.length <= offset) {
|
120 | remainder.push(0);
|
121 | }
|
122 |
|
123 | remainder[remainderBinLen >>> 5] |= 0x80 << (24 - (remainderBinLen % 32));
|
124 | |
125 |
|
126 |
|
127 |
|
128 | remainder[offset] = totalLen & 0xffffffff;
|
129 | |
130 |
|
131 | remainder[offset - 1] = (totalLen / TWO_PWR_32) | 0;
|
132 |
|
133 |
|
134 | for (i = 0; i < remainder.length; i += binaryStringInc) {
|
135 | H = roundSHA256(remainder.slice(i, i + binaryStringInc), H);
|
136 | }
|
137 |
|
138 | if ("SHA-224" === variant) {
|
139 | retVal = [H[0], H[1], H[2], H[3], H[4], H[5], H[6]];
|
140 | } else {
|
141 |
|
142 | retVal = H;
|
143 | }
|
144 |
|
145 | return retVal;
|
146 | }
|
147 | export default class jsSHA extends jsSHABase<number[], VariantType> {
|
148 | intermediateState: number[];
|
149 | variantBlockSize: number;
|
150 | bigEndianMod: -1 | 1;
|
151 | outputBinLen: number;
|
152 | isVariableLen: boolean;
|
153 | HMACSupported: boolean;
|
154 |
|
155 |
|
156 | converterFunc: (input: any, existingBin: number[], existingBinLen: number) => packedValue;
|
157 | roundFunc: (block: number[], H: number[]) => number[];
|
158 | finalizeFunc: (remainder: number[], remainderBinLen: number, processedBinLen: number, H: number[]) => number[];
|
159 | stateCloneFunc: (state: number[]) => number[];
|
160 | newStateFunc: (variant: VariantType) => number[];
|
161 | getMAC: () => number[];
|
162 |
|
163 | constructor(variant: VariantType, inputFormat: "TEXT", options?: FixedLengthOptionsEncodingType);
|
164 | constructor(variant: VariantType, inputFormat: FormatNoTextType, options?: FixedLengthOptionsNoEncodingType);
|
165 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
166 | constructor(variant: any, inputFormat: any, options?: any) {
|
167 | if (!("SHA-224" === variant || "SHA-256" === variant)) {
|
168 | throw new Error(sha_variant_error);
|
169 | }
|
170 | super(variant, inputFormat, options);
|
171 | const resolvedOptions = options || {};
|
172 |
|
173 |
|
174 | this.getMAC = this._getHMAC;
|
175 | this.HMACSupported = true;
|
176 | this.bigEndianMod = -1;
|
177 | this.converterFunc = getStrConverter(this.inputFormat, this.utfType, this.bigEndianMod);
|
178 | this.roundFunc = roundSHA256;
|
179 | this.stateCloneFunc = function (state): number[] {
|
180 | return state.slice();
|
181 | };
|
182 |
|
183 | this.newStateFunc = getNewState256;
|
184 | this.finalizeFunc = function (remainder, remainderBinLen, processedBinLen, H): number[] {
|
185 | return finalizeSHA256(remainder, remainderBinLen, processedBinLen, H, variant);
|
186 | };
|
187 |
|
188 | this.intermediateState = getNewState256(variant);
|
189 | this.variantBlockSize = 512;
|
190 | this.outputBinLen = "SHA-224" === variant ? 224 : 256;
|
191 | this.isVariableLen = false;
|
192 |
|
193 | if (resolvedOptions["hmacKey"]) {
|
194 | this._setHMACKey(parseInputOption("hmacKey", resolvedOptions["hmacKey"], this.bigEndianMod));
|
195 | }
|
196 | }
|
197 | }
|