Initial commit.
[BoarSSL] / Crypto / SHA2Small.cs
1 /*
2 * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25 using System;
26
27 namespace Crypto {
28
29 /*
30 * Implementation of SHA-224 and SHA-256, as described in FIPS 180-4.
31 */
32
33 public abstract class SHA2Small : DigestCore {
34
35 const int BLOCK_LEN = 64;
36
37 uint[] state;
38 byte[] block, saveBlock;
39 int ptr;
40 ulong byteCount;
41 uint[] W;
42
43 /*
44 * Create a new instance, ready to process data bytes. The
45 * output length (in bytes) and initial value must be specified.
46 */
47 internal SHA2Small()
48 {
49 state = new uint[8];
50 block = new byte[BLOCK_LEN];
51 saveBlock = new byte[BLOCK_LEN];
52 W = new uint[64];
53 Reset();
54 }
55
56 internal abstract uint[] IV { get; }
57
58 internal abstract SHA2Small DupInner();
59
60 /* see IDigest */
61 public override int BlockSize {
62 get {
63 return BLOCK_LEN;
64 }
65 }
66
67 /* see IDigest */
68 public override void Reset()
69 {
70 Array.Copy(IV, 0, state, 0, state.Length);
71 byteCount = 0;
72 ptr = 0;
73 }
74
75 /* see IDigest */
76 public override void Update(byte b)
77 {
78 block[ptr ++] = b;
79 byteCount ++;
80 if (ptr == BLOCK_LEN) {
81 ProcessBlock();
82 }
83 }
84
85 /* see IDigest */
86 public override void Update(byte[] buf, int off, int len)
87 {
88 if (len < 0) {
89 throw new ArgumentException("negative chunk length");
90 }
91 byteCount += (ulong)len;
92 while (len > 0) {
93 int clen = Math.Min(len, BLOCK_LEN - ptr);
94 Array.Copy(buf, off, block, ptr, clen);
95 off += clen;
96 len -= clen;
97 ptr += clen;
98 if (ptr == BLOCK_LEN) {
99 ProcessBlock();
100 }
101 }
102 }
103
104 /* see IDigest */
105 public override void DoPartial(byte[] outBuf, int off)
106 {
107 /*
108 * Save current state.
109 */
110 uint A = state[0];
111 uint B = state[1];
112 uint C = state[2];
113 uint D = state[3];
114 uint E = state[4];
115 uint F = state[5];
116 uint G = state[6];
117 uint H = state[7];
118 int savePtr = ptr;
119 Array.Copy(block, 0, saveBlock, 0, savePtr);
120
121 /*
122 * Add padding. This may involve processing an extra block.
123 */
124 block[ptr ++] = 0x80;
125 if (ptr > BLOCK_LEN - 8) {
126 for (int j = ptr; j < BLOCK_LEN; j ++) {
127 block[j] = 0;
128 }
129 ProcessBlock();
130 }
131 for (int j = ptr; j < (BLOCK_LEN - 8); j ++) {
132 block[j] = 0;
133 }
134 ulong x = byteCount << 3;
135 Enc32be((uint)(x >> 32), block, BLOCK_LEN - 8);
136 Enc32be((uint)x, block, BLOCK_LEN - 4);
137
138 /*
139 * Process final block and encode result.
140 */
141 ProcessBlock();
142 int n = DigestSize >> 2;
143 for (int i = 0; i < n; i ++) {
144 Enc32be(state[i], outBuf, off + (i << 2));
145 }
146
147 /*
148 * Restore current state.
149 */
150 Array.Copy(saveBlock, 0, block, 0, savePtr);
151 state[0] = A;
152 state[1] = B;
153 state[2] = C;
154 state[3] = D;
155 state[4] = E;
156 state[5] = F;
157 state[6] = G;
158 state[7] = H;
159 ptr = savePtr;
160 }
161
162 /* see IDigest */
163 public override IDigest Dup()
164 {
165 SHA2Small h = DupInner();
166 Array.Copy(state, 0, h.state, 0, state.Length);
167 h.ptr = ptr;
168 h.byteCount = byteCount;
169 Array.Copy(block, 0, h.block, 0, ptr);
170 return h;
171 }
172
173 /* see IDigest */
174 public override void CurrentState(byte[] outBuf, int off)
175 {
176 int n = DigestSize >> 2;
177 for (int i = 0; i < n; i ++) {
178 Enc32be(state[i], outBuf, off + (i << 2));
179 }
180 }
181
182 static uint[] K = {
183 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5,
184 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
185 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3,
186 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
187 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC,
188 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
189 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7,
190 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
191 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13,
192 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
193 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3,
194 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
195 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5,
196 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
197 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208,
198 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2
199 };
200
201 void ProcessBlock()
202 {
203 /*
204 * Read state words.
205 */
206 uint A = state[0];
207 uint B = state[1];
208 uint C = state[2];
209 uint D = state[3];
210 uint E = state[4];
211 uint F = state[5];
212 uint G = state[6];
213 uint H = state[7];
214
215 uint T1, T2;
216 uint[] W = this.W;
217 byte[] block = this.block;
218
219 for (int i = 0, j = 0; i < 16; i ++, j += 4) {
220 W[i] = Dec32be(block, j);
221 }
222 for (int i = 16; i < 64; i ++) {
223 uint w2 = W[i - 2];
224 uint w15 = W[i - 15];
225 W[i] = (((w2 << 15) | (w2 >> 17))
226 ^ ((w2 << 13) | (w2 >> 19))
227 ^ (w2 >> 10))
228 + W[i - 7]
229 + (((w15 << 25) | (w15 >> 7))
230 ^ ((w15 << 14) | (w15 >> 18))
231 ^ (w15 >> 3))
232 + W[i - 16];
233 }
234 for (int i = 0; i < 64; i += 8) {
235 T1 = H + (((E << 26) | (E >> 6))
236 ^ ((E << 21) | (E >> 11))
237 ^ ((E << 7) | (E >> 25)))
238 + (G ^ (E & (F ^ G)))
239 + K[i + 0] + W[i + 0];
240 T2 = (((A << 30) | (A >> 2))
241 ^ ((A << 19) | (A >> 13))
242 ^ ((A << 10) | (A >> 22)))
243 + ((A & B) ^ (C & (A ^ B)));
244 D += T1;
245 H = T1 + T2;
246 T1 = G + (((D << 26) | (D >> 6))
247 ^ ((D << 21) | (D >> 11))
248 ^ ((D << 7) | (D >> 25)))
249 + (F ^ (D & (E ^ F)))
250 + K[i + 1] + W[i + 1];
251 T2 = (((H << 30) | (H >> 2))
252 ^ ((H << 19) | (H >> 13))
253 ^ ((H << 10) | (H >> 22)))
254 + ((H & A) ^ (B & (H ^ A)));
255 C += T1;
256 G = T1 + T2;
257 T1 = F + (((C << 26) | (C >> 6))
258 ^ ((C << 21) | (C >> 11))
259 ^ ((C << 7) | (C >> 25)))
260 + (E ^ (C & (D ^ E)))
261 + K[i + 2] + W[i + 2];
262 T2 = (((G << 30) | (G >> 2))
263 ^ ((G << 19) | (G >> 13))
264 ^ ((G << 10) | (G >> 22)))
265 + ((G & H) ^ (A & (G ^ H)));
266 B += T1;
267 F = T1 + T2;
268 T1 = E + (((B << 26) | (B >> 6))
269 ^ ((B << 21) | (B >> 11))
270 ^ ((B << 7) | (B >> 25)))
271 + (D ^ (B & (C ^ D)))
272 + K[i + 3] + W[i + 3];
273 T2 = (((F << 30) | (F >> 2))
274 ^ ((F << 19) | (F >> 13))
275 ^ ((F << 10) | (F >> 22)))
276 + ((F & G) ^ (H & (F ^ G)));
277 A += T1;
278 E = T1 + T2;
279 T1 = D + (((A << 26) | (A >> 6))
280 ^ ((A << 21) | (A >> 11))
281 ^ ((A << 7) | (A >> 25)))
282 + (C ^ (A & (B ^ C)))
283 + K[i + 4] + W[i + 4];
284 T2 = (((E << 30) | (E >> 2))
285 ^ ((E << 19) | (E >> 13))
286 ^ ((E << 10) | (E >> 22)))
287 + ((E & F) ^ (G & (E ^ F)));
288 H += T1;
289 D = T1 + T2;
290 T1 = C + (((H << 26) | (H >> 6))
291 ^ ((H << 21) | (H >> 11))
292 ^ ((H << 7) | (H >> 25)))
293 + (B ^ (H & (A ^ B)))
294 + K[i + 5] + W[i + 5];
295 T2 = (((D << 30) | (D >> 2))
296 ^ ((D << 19) | (D >> 13))
297 ^ ((D << 10) | (D >> 22)))
298 + ((D & E) ^ (F & (D ^ E)));
299 G += T1;
300 C = T1 + T2;
301 T1 = B + (((G << 26) | (G >> 6))
302 ^ ((G << 21) | (G >> 11))
303 ^ ((G << 7) | (G >> 25)))
304 + (A ^ (G & (H ^ A)))
305 + K[i + 6] + W[i + 6];
306 T2 = (((C << 30) | (C >> 2))
307 ^ ((C << 19) | (C >> 13))
308 ^ ((C << 10) | (C >> 22)))
309 + ((C & D) ^ (E & (C ^ D)));
310 F += T1;
311 B = T1 + T2;
312 T1 = A + (((F << 26) | (F >> 6))
313 ^ ((F << 21) | (F >> 11))
314 ^ ((F << 7) | (F >> 25)))
315 + (H ^ (F & (G ^ H)))
316 + K[i + 7] + W[i + 7];
317 T2 = (((B << 30) | (B >> 2))
318 ^ ((B << 19) | (B >> 13))
319 ^ ((B << 10) | (B >> 22)))
320 + ((B & C) ^ (D & (B ^ C)));
321 E += T1;
322 A = T1 + T2;
323 }
324
325 /* obsolete
326 for (int i = 0; i < 64; i ++) {
327 uint T1 = H + (((E << 26) | (E >> 6))
328 ^ ((E << 21) | (E >> 11))
329 ^ ((E << 7) | (E >> 25)))
330 + (G ^ (E & (F ^ G)))
331 + K[i] + W[i];
332 uint T2 = (((A << 30) | (A >> 2))
333 ^ ((A << 19) | (A >> 13))
334 ^ ((A << 10) | (A >> 22)))
335 + ((A & B) ^ (C & (A ^ B)));
336 H = G; G = F; F = E; E = D + T1;
337 D = C; C = B; B = A; A = T1 + T2;
338 }
339 */
340
341 /*
342 * Update state words and reset block pointer.
343 */
344 state[0] += A;
345 state[1] += B;
346 state[2] += C;
347 state[3] += D;
348 state[4] += E;
349 state[5] += F;
350 state[6] += G;
351 state[7] += H;
352 ptr = 0;
353 }
354
355 static uint Dec32be(byte[] buf, int off)
356 {
357 return ((uint)buf[off] << 24)
358 | ((uint)buf[off + 1] << 16)
359 | ((uint)buf[off + 2] << 8)
360 | (uint)buf[off + 3];
361 }
362
363 static void Enc32be(uint x, byte[] buf, int off)
364 {
365 buf[off] = (byte)(x >> 24);
366 buf[off + 1] = (byte)(x >> 16);
367 buf[off + 2] = (byte)(x >> 8);
368 buf[off + 3] = (byte)x;
369 }
370 }
371
372 }