UNPKG

6.59 kBJavaScriptView Raw
1/** @fileOverview Javascript SHA-256 implementation.
2 *
3 * An older version of this implementation is available in the public
4 * domain, but this one is (c) Emily Stark, Mike Hamburg, Dan Boneh,
5 * Stanford University 2008-2010 and BSD-licensed for liability
6 * reasons.
7 *
8 * Special thanks to Aldo Cortesi for pointing out several bugs in
9 * this code.
10 *
11 * @author Emily Stark
12 * @author Mike Hamburg
13 * @author Dan Boneh
14 */
15
16/**
17 * Context for a SHA-256 operation in progress.
18 * @constructor
19 */
20sjcl.hash.sha256 = function (hash) {
21 if (!this._key[0]) { this._precompute(); }
22 if (hash) {
23 this._h = hash._h.slice(0);
24 this._buffer = hash._buffer.slice(0);
25 this._length = hash._length;
26 } else {
27 this.reset();
28 }
29};
30
31/**
32 * Hash a string or an array of words.
33 * @static
34 * @param {bitArray|String} data the data to hash.
35 * @return {bitArray} The hash value, an array of 16 big-endian words.
36 */
37sjcl.hash.sha256.hash = function (data) {
38 return (new sjcl.hash.sha256()).update(data).finalize();
39};
40
41sjcl.hash.sha256.prototype = {
42 /**
43 * The hash's block size, in bits.
44 * @constant
45 */
46 blockSize: 512,
47
48 /**
49 * Reset the hash state.
50 * @return this
51 */
52 reset:function () {
53 this._h = this._init.slice(0);
54 this._buffer = [];
55 this._length = 0;
56 return this;
57 },
58
59 /**
60 * Input several words to the hash.
61 * @param {bitArray|String} data the data to hash.
62 * @return this
63 */
64 update: function (data) {
65 if (typeof data === "string") {
66 data = sjcl.codec.utf8String.toBits(data);
67 }
68 var i, b = this._buffer = sjcl.bitArray.concat(this._buffer, data),
69 ol = this._length,
70 nl = this._length = ol + sjcl.bitArray.bitLength(data);
71 if (nl > 9007199254740991){
72 throw new sjcl.exception.invalid("Cannot hash more than 2^53 - 1 bits");
73 }
74
75 if (typeof Uint32Array !== 'undefined') {
76 var c = new Uint32Array(b);
77 var j = 0;
78 for (i = 512+ol - ((512+ol) & 511); i <= nl; i+= 512) {
79 this._block(c.subarray(16 * j, 16 * (j+1)));
80 j += 1;
81 }
82 b.splice(0, 16 * j);
83 } else {
84 for (i = 512+ol - ((512+ol) & 511); i <= nl; i+= 512) {
85 this._block(b.splice(0,16));
86 }
87 }
88 return this;
89 },
90
91 /**
92 * Complete hashing and output the hash value.
93 * @return {bitArray} The hash value, an array of 8 big-endian words.
94 */
95 finalize:function () {
96 var i, b = this._buffer, h = this._h;
97
98 // Round out and push the buffer
99 b = sjcl.bitArray.concat(b, [sjcl.bitArray.partial(1,1)]);
100
101 // Round out the buffer to a multiple of 16 words, less the 2 length words.
102 for (i = b.length + 2; i & 15; i++) {
103 b.push(0);
104 }
105
106 // append the length
107 b.push(Math.floor(this._length / 0x100000000));
108 b.push(this._length | 0);
109
110 while (b.length) {
111 this._block(b.splice(0,16));
112 }
113
114 this.reset();
115 return h;
116 },
117
118 /**
119 * The SHA-256 initialization vector, to be precomputed.
120 * @private
121 */
122 _init:[],
123 /*
124 _init:[0x6a09e667,0xbb67ae85,0x3c6ef372,0xa54ff53a,0x510e527f,0x9b05688c,0x1f83d9ab,0x5be0cd19],
125 */
126
127 /**
128 * The SHA-256 hash key, to be precomputed.
129 * @private
130 */
131 _key:[],
132 /*
133 _key:
134 [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
135 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
136 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
137 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
138 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
139 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
140 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
141 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2],
142 */
143
144
145 /**
146 * Function to precompute _init and _key.
147 * @private
148 */
149 _precompute: function () {
150 var i = 0, prime = 2, factor, isPrime;
151
152 function frac(x) { return (x-Math.floor(x)) * 0x100000000 | 0; }
153
154 for (; i<64; prime++) {
155 isPrime = true;
156 for (factor=2; factor*factor <= prime; factor++) {
157 if (prime % factor === 0) {
158 isPrime = false;
159 break;
160 }
161 }
162 if (isPrime) {
163 if (i<8) {
164 this._init[i] = frac(Math.pow(prime, 1/2));
165 }
166 this._key[i] = frac(Math.pow(prime, 1/3));
167 i++;
168 }
169 }
170 },
171
172 /**
173 * Perform one cycle of SHA-256.
174 * @param {Uint32Array|bitArray} w one block of words.
175 * @private
176 */
177 _block:function (w) {
178 var i, tmp, a, b,
179 h = this._h,
180 k = this._key,
181 h0 = h[0], h1 = h[1], h2 = h[2], h3 = h[3],
182 h4 = h[4], h5 = h[5], h6 = h[6], h7 = h[7];
183
184 /* Rationale for placement of |0 :
185 * If a value can overflow is original 32 bits by a factor of more than a few
186 * million (2^23 ish), there is a possibility that it might overflow the
187 * 53-bit mantissa and lose precision.
188 *
189 * To avoid this, we clamp back to 32 bits by |'ing with 0 on any value that
190 * propagates around the loop, and on the hash state h[]. I don't believe
191 * that the clamps on h4 and on h0 are strictly necessary, but it's close
192 * (for h4 anyway), and better safe than sorry.
193 *
194 * The clamps on h[] are necessary for the output to be correct even in the
195 * common case and for short inputs.
196 */
197 for (i=0; i<64; i++) {
198 // load up the input word for this round
199 if (i<16) {
200 tmp = w[i];
201 } else {
202 a = w[(i+1 ) & 15];
203 b = w[(i+14) & 15];
204 tmp = w[i&15] = ((a>>>7 ^ a>>>18 ^ a>>>3 ^ a<<25 ^ a<<14) +
205 (b>>>17 ^ b>>>19 ^ b>>>10 ^ b<<15 ^ b<<13) +
206 w[i&15] + w[(i+9) & 15]) | 0;
207 }
208
209 tmp = (tmp + h7 + (h4>>>6 ^ h4>>>11 ^ h4>>>25 ^ h4<<26 ^ h4<<21 ^ h4<<7) + (h6 ^ h4&(h5^h6)) + k[i]); // | 0;
210
211 // shift register
212 h7 = h6; h6 = h5; h5 = h4;
213 h4 = h3 + tmp | 0;
214 h3 = h2; h2 = h1; h1 = h0;
215
216 h0 = (tmp + ((h1&h2) ^ (h3&(h1^h2))) + (h1>>>2 ^ h1>>>13 ^ h1>>>22 ^ h1<<30 ^ h1<<19 ^ h1<<10)) | 0;
217 }
218
219 h[0] = h[0]+h0 | 0;
220 h[1] = h[1]+h1 | 0;
221 h[2] = h[2]+h2 | 0;
222 h[3] = h[3]+h3 | 0;
223 h[4] = h[4]+h4 | 0;
224 h[5] = h[5]+h5 | 0;
225 h[6] = h[6]+h6 | 0;
226 h[7] = h[7]+h7 | 0;
227 }
228};
229
230