UNPKG

6.06 kBJavaScriptView Raw
1var Buffer = require('buffer/').Buffer;
2var hashUtils = require('./browserHashUtils');
3
4var BLOCK_SIZE = 64;
5
6var DIGEST_LENGTH = 32;
7
8var KEY = new Uint32Array([
9 0x428a2f98,
10 0x71374491,
11 0xb5c0fbcf,
12 0xe9b5dba5,
13 0x3956c25b,
14 0x59f111f1,
15 0x923f82a4,
16 0xab1c5ed5,
17 0xd807aa98,
18 0x12835b01,
19 0x243185be,
20 0x550c7dc3,
21 0x72be5d74,
22 0x80deb1fe,
23 0x9bdc06a7,
24 0xc19bf174,
25 0xe49b69c1,
26 0xefbe4786,
27 0x0fc19dc6,
28 0x240ca1cc,
29 0x2de92c6f,
30 0x4a7484aa,
31 0x5cb0a9dc,
32 0x76f988da,
33 0x983e5152,
34 0xa831c66d,
35 0xb00327c8,
36 0xbf597fc7,
37 0xc6e00bf3,
38 0xd5a79147,
39 0x06ca6351,
40 0x14292967,
41 0x27b70a85,
42 0x2e1b2138,
43 0x4d2c6dfc,
44 0x53380d13,
45 0x650a7354,
46 0x766a0abb,
47 0x81c2c92e,
48 0x92722c85,
49 0xa2bfe8a1,
50 0xa81a664b,
51 0xc24b8b70,
52 0xc76c51a3,
53 0xd192e819,
54 0xd6990624,
55 0xf40e3585,
56 0x106aa070,
57 0x19a4c116,
58 0x1e376c08,
59 0x2748774c,
60 0x34b0bcb5,
61 0x391c0cb3,
62 0x4ed8aa4a,
63 0x5b9cca4f,
64 0x682e6ff3,
65 0x748f82ee,
66 0x78a5636f,
67 0x84c87814,
68 0x8cc70208,
69 0x90befffa,
70 0xa4506ceb,
71 0xbef9a3f7,
72 0xc67178f2
73]);
74
75var INIT = [
76 0x6a09e667,
77 0xbb67ae85,
78 0x3c6ef372,
79 0xa54ff53a,
80 0x510e527f,
81 0x9b05688c,
82 0x1f83d9ab,
83 0x5be0cd19,
84];
85
86var MAX_HASHABLE_LENGTH = Math.pow(2, 53) - 1;
87
88/**
89 * @private
90 */
91function Sha256() {
92 this.state = [
93 0x6a09e667,
94 0xbb67ae85,
95 0x3c6ef372,
96 0xa54ff53a,
97 0x510e527f,
98 0x9b05688c,
99 0x1f83d9ab,
100 0x5be0cd19,
101 ];
102 this.temp = new Int32Array(64);
103 this.buffer = new Uint8Array(64);
104 this.bufferLength = 0;
105 this.bytesHashed = 0;
106 /**
107 * @private
108 */
109 this.finished = false;
110}
111
112/**
113 * @api private
114 */
115module.exports = exports = Sha256;
116
117Sha256.BLOCK_SIZE = BLOCK_SIZE;
118
119Sha256.prototype.update = function (data) {
120 if (this.finished) {
121 throw new Error('Attempted to update an already finished hash.');
122 }
123
124 if (hashUtils.isEmptyData(data)) {
125 return this;
126 }
127
128 data = hashUtils.convertToBuffer(data);
129
130 var position = 0;
131 var byteLength = data.byteLength;
132 this.bytesHashed += byteLength;
133 if (this.bytesHashed * 8 > MAX_HASHABLE_LENGTH) {
134 throw new Error('Cannot hash more than 2^53 - 1 bits');
135 }
136
137 while (byteLength > 0) {
138 this.buffer[this.bufferLength++] = data[position++];
139 byteLength--;
140 if (this.bufferLength === BLOCK_SIZE) {
141 this.hashBuffer();
142 this.bufferLength = 0;
143 }
144 }
145
146 return this;
147};
148
149Sha256.prototype.digest = function (encoding) {
150 if (!this.finished) {
151 var bitsHashed = this.bytesHashed * 8;
152 var bufferView = new DataView(this.buffer.buffer, this.buffer.byteOffset, this.buffer.byteLength);
153 var undecoratedLength = this.bufferLength;
154 bufferView.setUint8(this.bufferLength++, 0x80);
155 // Ensure the final block has enough room for the hashed length
156 if (undecoratedLength % BLOCK_SIZE >= BLOCK_SIZE - 8) {
157 for (var i = this.bufferLength; i < BLOCK_SIZE; i++) {
158 bufferView.setUint8(i, 0);
159 }
160 this.hashBuffer();
161 this.bufferLength = 0;
162 }
163 for (var i = this.bufferLength; i < BLOCK_SIZE - 8; i++) {
164 bufferView.setUint8(i, 0);
165 }
166 bufferView.setUint32(BLOCK_SIZE - 8, Math.floor(bitsHashed / 0x100000000), true);
167 bufferView.setUint32(BLOCK_SIZE - 4, bitsHashed);
168 this.hashBuffer();
169 this.finished = true;
170 }
171 // The value in state is little-endian rather than big-endian, so flip
172 // each word into a new Uint8Array
173 var out = new Buffer(DIGEST_LENGTH);
174 for (var i = 0; i < 8; i++) {
175 out[i * 4] = (this.state[i] >>> 24) & 0xff;
176 out[i * 4 + 1] = (this.state[i] >>> 16) & 0xff;
177 out[i * 4 + 2] = (this.state[i] >>> 8) & 0xff;
178 out[i * 4 + 3] = (this.state[i] >>> 0) & 0xff;
179 }
180 return encoding ? out.toString(encoding) : out;
181};
182
183Sha256.prototype.hashBuffer = function () {
184 var _a = this,
185 buffer = _a.buffer,
186 state = _a.state;
187 var state0 = state[0],
188 state1 = state[1],
189 state2 = state[2],
190 state3 = state[3],
191 state4 = state[4],
192 state5 = state[5],
193 state6 = state[6],
194 state7 = state[7];
195 for (var i = 0; i < BLOCK_SIZE; i++) {
196 if (i < 16) {
197 this.temp[i] = (((buffer[i * 4] & 0xff) << 24) |
198 ((buffer[(i * 4) + 1] & 0xff) << 16) |
199 ((buffer[(i * 4) + 2] & 0xff) << 8) |
200 (buffer[(i * 4) + 3] & 0xff));
201 }
202 else {
203 var u = this.temp[i - 2];
204 var t1_1 = (u >>> 17 | u << 15) ^
205 (u >>> 19 | u << 13) ^
206 (u >>> 10);
207 u = this.temp[i - 15];
208 var t2_1 = (u >>> 7 | u << 25) ^
209 (u >>> 18 | u << 14) ^
210 (u >>> 3);
211 this.temp[i] = (t1_1 + this.temp[i - 7] | 0) +
212 (t2_1 + this.temp[i - 16] | 0);
213 }
214 var t1 = (((((state4 >>> 6 | state4 << 26) ^
215 (state4 >>> 11 | state4 << 21) ^
216 (state4 >>> 25 | state4 << 7))
217 + ((state4 & state5) ^ (~state4 & state6))) | 0)
218 + ((state7 + ((KEY[i] + this.temp[i]) | 0)) | 0)) | 0;
219 var t2 = (((state0 >>> 2 | state0 << 30) ^
220 (state0 >>> 13 | state0 << 19) ^
221 (state0 >>> 22 | state0 << 10)) + ((state0 & state1) ^ (state0 & state2) ^ (state1 & state2))) | 0;
222 state7 = state6;
223 state6 = state5;
224 state5 = state4;
225 state4 = (state3 + t1) | 0;
226 state3 = state2;
227 state2 = state1;
228 state1 = state0;
229 state0 = (t1 + t2) | 0;
230 }
231 state[0] += state0;
232 state[1] += state1;
233 state[2] += state2;
234 state[3] += state3;
235 state[4] += state4;
236 state[5] += state5;
237 state[6] += state6;
238 state[7] += state7;
239};