1 | import { jsSHABase, TWO_PWR_32, 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 { ch_32, parity_32, maj_32, rotl_32, safeAdd_32_2, safeAdd_32_5 } from "./primitives_32";
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 | function getNewState(_variant: "SHA-1"): number[] {
|
18 | return [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0];
|
19 | }
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 | function roundSHA1(block: number[], H: number[]): number[] {
|
29 | let a, b, c, d, e, T, t;
|
30 | const W: number[] = [];
|
31 |
|
32 | a = H[0];
|
33 | b = H[1];
|
34 | c = H[2];
|
35 | d = H[3];
|
36 | e = H[4];
|
37 |
|
38 | for (t = 0; t < 80; t += 1) {
|
39 | if (t < 16) {
|
40 | W[t] = block[t];
|
41 | } else {
|
42 | W[t] = rotl_32(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1);
|
43 | }
|
44 |
|
45 | if (t < 20) {
|
46 | T = safeAdd_32_5(rotl_32(a, 5), ch_32(b, c, d), e, 0x5a827999, W[t]);
|
47 | } else if (t < 40) {
|
48 | T = safeAdd_32_5(rotl_32(a, 5), parity_32(b, c, d), e, 0x6ed9eba1, W[t]);
|
49 | } else if (t < 60) {
|
50 | T = safeAdd_32_5(rotl_32(a, 5), maj_32(b, c, d), e, 0x8f1bbcdc, W[t]);
|
51 | } else {
|
52 | T = safeAdd_32_5(rotl_32(a, 5), parity_32(b, c, d), e, 0xca62c1d6, W[t]);
|
53 | }
|
54 |
|
55 | e = d;
|
56 | d = c;
|
57 | c = rotl_32(b, 30);
|
58 | b = a;
|
59 | a = T;
|
60 | }
|
61 |
|
62 | H[0] = safeAdd_32_2(a, H[0]);
|
63 | H[1] = safeAdd_32_2(b, H[1]);
|
64 | H[2] = safeAdd_32_2(c, H[2]);
|
65 | H[3] = safeAdd_32_2(d, H[3]);
|
66 | H[4] = safeAdd_32_2(e, H[4]);
|
67 |
|
68 | return H;
|
69 | }
|
70 |
|
71 |
|
72 |
|
73 |
|
74 |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 |
|
80 | function finalizeSHA1(remainder: number[], remainderBinLen: number, processedBinLen: number, H: number[]): number[] {
|
81 | let i;
|
82 |
|
83 | |
84 |
|
85 |
|
86 |
|
87 | const offset = (((remainderBinLen + 65) >>> 9) << 4) + 15,
|
88 | totalLen = remainderBinLen + processedBinLen;
|
89 | while (remainder.length <= offset) {
|
90 | remainder.push(0);
|
91 | }
|
92 |
|
93 | remainder[remainderBinLen >>> 5] |= 0x80 << (24 - (remainderBinLen % 32));
|
94 |
|
95 | |
96 |
|
97 |
|
98 |
|
99 |
|
100 | remainder[offset] = totalLen & 0xffffffff;
|
101 |
|
102 | |
103 |
|
104 | remainder[offset - 1] = (totalLen / TWO_PWR_32) | 0;
|
105 |
|
106 |
|
107 | for (i = 0; i < remainder.length; i += 16) {
|
108 | H = roundSHA1(remainder.slice(i, i + 16), H);
|
109 | }
|
110 |
|
111 | return H;
|
112 | }
|
113 |
|
114 | export default class jsSHA extends jsSHABase<number[], "SHA-1"> {
|
115 | intermediateState: number[];
|
116 | variantBlockSize: number;
|
117 | bigEndianMod: -1 | 1;
|
118 | outputBinLen: number;
|
119 | isVariableLen: boolean;
|
120 | HMACSupported: boolean;
|
121 |
|
122 |
|
123 | converterFunc: (input: any, existingBin: number[], existingBinLen: number) => packedValue;
|
124 | roundFunc: (block: number[], H: number[]) => number[];
|
125 | finalizeFunc: (remainder: number[], remainderBinLen: number, processedBinLen: number, H: number[]) => number[];
|
126 | stateCloneFunc: (state: number[]) => number[];
|
127 | newStateFunc: (variant: "SHA-1") => number[];
|
128 | getMAC: () => number[];
|
129 |
|
130 | constructor(variant: "SHA-1", inputFormat: "TEXT", options?: FixedLengthOptionsEncodingType);
|
131 | constructor(variant: "SHA-1", inputFormat: FormatNoTextType, options?: FixedLengthOptionsNoEncodingType);
|
132 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
133 | constructor(variant: any, inputFormat: any, options?: any) {
|
134 | if ("SHA-1" !== variant) {
|
135 | throw new Error(sha_variant_error);
|
136 | }
|
137 | super(variant, inputFormat, options);
|
138 | const resolvedOptions = options || {};
|
139 |
|
140 | this.HMACSupported = true;
|
141 |
|
142 | this.getMAC = this._getHMAC;
|
143 | this.bigEndianMod = -1;
|
144 | this.converterFunc = getStrConverter(this.inputFormat, this.utfType, this.bigEndianMod);
|
145 | this.roundFunc = roundSHA1;
|
146 | this.stateCloneFunc = function (state: number[]): number[] {
|
147 | return state.slice();
|
148 | };
|
149 | this.newStateFunc = getNewState;
|
150 | this.finalizeFunc = finalizeSHA1;
|
151 |
|
152 | this.intermediateState = getNewState(variant);
|
153 | this.variantBlockSize = 512;
|
154 | this.outputBinLen = 160;
|
155 | this.isVariableLen = false;
|
156 |
|
157 | if (resolvedOptions["hmacKey"]) {
|
158 | this._setHMACKey(parseInputOption("hmacKey", resolvedOptions["hmacKey"], this.bigEndianMod));
|
159 | }
|
160 | }
|
161 | }
|