]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - sshsh256.c
Add smemclrs of all hash states we destroy.
[PuTTY.git] / sshsh256.c
1 /*
2  * SHA-256 algorithm as described at
3  * 
4  *   http://csrc.nist.gov/cryptval/shs.html
5  */
6
7 #include "ssh.h"
8
9 /* ----------------------------------------------------------------------
10  * Core SHA256 algorithm: processes 16-word blocks into a message digest.
11  */
12
13 #define ror(x,y) ( ((x) << (32-y)) | (((uint32)(x)) >> (y)) )
14 #define shr(x,y) ( (((uint32)(x)) >> (y)) )
15 #define Ch(x,y,z) ( ((x) & (y)) ^ (~(x) & (z)) )
16 #define Maj(x,y,z) ( ((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)) )
17 #define bigsigma0(x) ( ror((x),2) ^ ror((x),13) ^ ror((x),22) )
18 #define bigsigma1(x) ( ror((x),6) ^ ror((x),11) ^ ror((x),25) )
19 #define smallsigma0(x) ( ror((x),7) ^ ror((x),18) ^ shr((x),3) )
20 #define smallsigma1(x) ( ror((x),17) ^ ror((x),19) ^ shr((x),10) )
21
22 void SHA256_Core_Init(SHA256_State *s) {
23     s->h[0] = 0x6a09e667;
24     s->h[1] = 0xbb67ae85;
25     s->h[2] = 0x3c6ef372;
26     s->h[3] = 0xa54ff53a;
27     s->h[4] = 0x510e527f;
28     s->h[5] = 0x9b05688c;
29     s->h[6] = 0x1f83d9ab;
30     s->h[7] = 0x5be0cd19;
31 }
32
33 void SHA256_Block(SHA256_State *s, uint32 *block) {
34     uint32 w[80];
35     uint32 a,b,c,d,e,f,g,h;
36     static const int k[] = {
37         0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
38         0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
39         0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
40         0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
41         0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
42         0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
43         0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
44         0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
45         0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
46         0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
47         0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
48         0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
49         0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
50         0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
51         0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
52         0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
53     };
54
55     int t;
56
57     for (t = 0; t < 16; t++)
58         w[t] = block[t];
59
60     for (t = 16; t < 64; t++)
61         w[t] = smallsigma1(w[t-2]) + w[t-7] + smallsigma0(w[t-15]) + w[t-16];
62
63     a = s->h[0]; b = s->h[1]; c = s->h[2]; d = s->h[3];
64     e = s->h[4]; f = s->h[5]; g = s->h[6]; h = s->h[7];
65
66     for (t = 0; t < 64; t+=8) {
67         uint32 t1, t2;
68
69 #define ROUND(j,a,b,c,d,e,f,g,h) \
70         t1 = h + bigsigma1(e) + Ch(e,f,g) + k[j] + w[j]; \
71         t2 = bigsigma0(a) + Maj(a,b,c); \
72         d = d + t1; h = t1 + t2;
73
74         ROUND(t+0, a,b,c,d,e,f,g,h);
75         ROUND(t+1, h,a,b,c,d,e,f,g);
76         ROUND(t+2, g,h,a,b,c,d,e,f);
77         ROUND(t+3, f,g,h,a,b,c,d,e);
78         ROUND(t+4, e,f,g,h,a,b,c,d);
79         ROUND(t+5, d,e,f,g,h,a,b,c);
80         ROUND(t+6, c,d,e,f,g,h,a,b);
81         ROUND(t+7, b,c,d,e,f,g,h,a);
82     }
83
84     s->h[0] += a; s->h[1] += b; s->h[2] += c; s->h[3] += d;
85     s->h[4] += e; s->h[5] += f; s->h[6] += g; s->h[7] += h;
86 }
87
88 /* ----------------------------------------------------------------------
89  * Outer SHA256 algorithm: take an arbitrary length byte string,
90  * convert it into 16-word blocks with the prescribed padding at
91  * the end, and pass those blocks to the core SHA256 algorithm.
92  */
93
94 #define BLKSIZE 64
95
96 void SHA256_Init(SHA256_State *s) {
97     SHA256_Core_Init(s);
98     s->blkused = 0;
99     s->lenhi = s->lenlo = 0;
100 }
101
102 void SHA256_Bytes(SHA256_State *s, const void *p, int len) {
103     unsigned char *q = (unsigned char *)p;
104     uint32 wordblock[16];
105     uint32 lenw = len;
106     int i;
107
108     /*
109      * Update the length field.
110      */
111     s->lenlo += lenw;
112     s->lenhi += (s->lenlo < lenw);
113
114     if (s->blkused && s->blkused+len < BLKSIZE) {
115         /*
116          * Trivial case: just add to the block.
117          */
118         memcpy(s->block + s->blkused, q, len);
119         s->blkused += len;
120     } else {
121         /*
122          * We must complete and process at least one block.
123          */
124         while (s->blkused + len >= BLKSIZE) {
125             memcpy(s->block + s->blkused, q, BLKSIZE - s->blkused);
126             q += BLKSIZE - s->blkused;
127             len -= BLKSIZE - s->blkused;
128             /* Now process the block. Gather bytes big-endian into words */
129             for (i = 0; i < 16; i++) {
130                 wordblock[i] =
131                     ( ((uint32)s->block[i*4+0]) << 24 ) |
132                     ( ((uint32)s->block[i*4+1]) << 16 ) |
133                     ( ((uint32)s->block[i*4+2]) <<  8 ) |
134                     ( ((uint32)s->block[i*4+3]) <<  0 );
135             }
136             SHA256_Block(s, wordblock);
137             s->blkused = 0;
138         }
139         memcpy(s->block, q, len);
140         s->blkused = len;
141     }
142 }
143
144 void SHA256_Final(SHA256_State *s, unsigned char *digest) {
145     int i;
146     int pad;
147     unsigned char c[64];
148     uint32 lenhi, lenlo;
149
150     if (s->blkused >= 56)
151         pad = 56 + 64 - s->blkused;
152     else
153         pad = 56 - s->blkused;
154
155     lenhi = (s->lenhi << 3) | (s->lenlo >> (32-3));
156     lenlo = (s->lenlo << 3);
157
158     memset(c, 0, pad);
159     c[0] = 0x80;
160     SHA256_Bytes(s, &c, pad);
161
162     c[0] = (lenhi >> 24) & 0xFF;
163     c[1] = (lenhi >> 16) & 0xFF;
164     c[2] = (lenhi >>  8) & 0xFF;
165     c[3] = (lenhi >>  0) & 0xFF;
166     c[4] = (lenlo >> 24) & 0xFF;
167     c[5] = (lenlo >> 16) & 0xFF;
168     c[6] = (lenlo >>  8) & 0xFF;
169     c[7] = (lenlo >>  0) & 0xFF;
170
171     SHA256_Bytes(s, &c, 8);
172
173     for (i = 0; i < 8; i++) {
174         digest[i*4+0] = (s->h[i] >> 24) & 0xFF;
175         digest[i*4+1] = (s->h[i] >> 16) & 0xFF;
176         digest[i*4+2] = (s->h[i] >>  8) & 0xFF;
177         digest[i*4+3] = (s->h[i] >>  0) & 0xFF;
178     }
179 }
180
181 void SHA256_Simple(const void *p, int len, unsigned char *output) {
182     SHA256_State s;
183
184     SHA256_Init(&s);
185     SHA256_Bytes(&s, p, len);
186     SHA256_Final(&s, output);
187     smemclr(&s, sizeof(s));
188 }
189
190 /*
191  * Thin abstraction for things where hashes are pluggable.
192  */
193
194 static void *sha256_init(void)
195 {
196     SHA256_State *s;
197
198     s = snew(SHA256_State);
199     SHA256_Init(s);
200     return s;
201 }
202
203 static void sha256_bytes(void *handle, void *p, int len)
204 {
205     SHA256_State *s = handle;
206
207     SHA256_Bytes(s, p, len);
208 }
209
210 static void sha256_final(void *handle, unsigned char *output)
211 {
212     SHA256_State *s = handle;
213
214     SHA256_Final(s, output);
215     smemclr(s, sizeof(*s));
216     sfree(s);
217 }
218
219 const struct ssh_hash ssh_sha256 = {
220     sha256_init, sha256_bytes, sha256_final, 32, "SHA-256"
221 };
222
223 /* ----------------------------------------------------------------------
224  * The above is the SHA-256 algorithm itself. Now we implement the
225  * HMAC wrapper on it.
226  */
227
228 static void *sha256_make_context(void)
229 {
230     return snewn(3, SHA256_State);
231 }
232
233 static void sha256_free_context(void *handle)
234 {
235     smemclr(handle, 3 * sizeof(SHA256_State));
236     sfree(handle);
237 }
238
239 static void sha256_key_internal(void *handle, unsigned char *key, int len)
240 {
241     SHA256_State *keys = (SHA256_State *)handle;
242     unsigned char foo[64];
243     int i;
244
245     memset(foo, 0x36, 64);
246     for (i = 0; i < len && i < 64; i++)
247         foo[i] ^= key[i];
248     SHA256_Init(&keys[0]);
249     SHA256_Bytes(&keys[0], foo, 64);
250
251     memset(foo, 0x5C, 64);
252     for (i = 0; i < len && i < 64; i++)
253         foo[i] ^= key[i];
254     SHA256_Init(&keys[1]);
255     SHA256_Bytes(&keys[1], foo, 64);
256
257     smemclr(foo, 64);                  /* burn the evidence */
258 }
259
260 static void sha256_key(void *handle, unsigned char *key)
261 {
262     sha256_key_internal(handle, key, 32);
263 }
264
265 static void hmacsha256_start(void *handle)
266 {
267     SHA256_State *keys = (SHA256_State *)handle;
268
269     keys[2] = keys[0];                /* structure copy */
270 }
271
272 static void hmacsha256_bytes(void *handle, unsigned char const *blk, int len)
273 {
274     SHA256_State *keys = (SHA256_State *)handle;
275     SHA256_Bytes(&keys[2], (void *)blk, len);
276 }
277
278 static void hmacsha256_genresult(void *handle, unsigned char *hmac)
279 {
280     SHA256_State *keys = (SHA256_State *)handle;
281     SHA256_State s;
282     unsigned char intermediate[32];
283
284     s = keys[2];                       /* structure copy */
285     SHA256_Final(&s, intermediate);
286     s = keys[1];                       /* structure copy */
287     SHA256_Bytes(&s, intermediate, 32);
288     SHA256_Final(&s, hmac);
289 }
290
291 static void sha256_do_hmac(void *handle, unsigned char *blk, int len,
292                          unsigned long seq, unsigned char *hmac)
293 {
294     unsigned char seqbuf[4];
295
296     PUT_32BIT_MSB_FIRST(seqbuf, seq);
297     hmacsha256_start(handle);
298     hmacsha256_bytes(handle, seqbuf, 4);
299     hmacsha256_bytes(handle, blk, len);
300     hmacsha256_genresult(handle, hmac);
301 }
302
303 static void sha256_generate(void *handle, unsigned char *blk, int len,
304                           unsigned long seq)
305 {
306     sha256_do_hmac(handle, blk, len, seq, blk + len);
307 }
308
309 static int hmacsha256_verresult(void *handle, unsigned char const *hmac)
310 {
311     unsigned char correct[32];
312     hmacsha256_genresult(handle, correct);
313     return smemeq(correct, hmac, 32);
314 }
315
316 static int sha256_verify(void *handle, unsigned char *blk, int len,
317                        unsigned long seq)
318 {
319     unsigned char correct[32];
320     sha256_do_hmac(handle, blk, len, seq, correct);
321     return smemeq(correct, blk + len, 32);
322 }
323
324 const struct ssh_mac ssh_hmac_sha256 = {
325     sha256_make_context, sha256_free_context, sha256_key,
326     sha256_generate, sha256_verify,
327     hmacsha256_start, hmacsha256_bytes,
328     hmacsha256_genresult, hmacsha256_verresult,
329     "hmac-sha2-256", "hmac-sha2-256-etm@openssh.com",
330     32,
331     "HMAC-SHA-256"
332 };
333
334 #ifdef TEST
335
336 #include <stdio.h>
337 #include <stdlib.h>
338 #include <assert.h>
339
340 int main(void) {
341     unsigned char digest[32];
342     int i, j, errors;
343
344     struct {
345         const char *teststring;
346         unsigned char digest[32];
347     } tests[] = {
348         { "abc", {
349             0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea,
350             0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23,
351             0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
352             0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad,
353         } },
354         { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", {
355             0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8,
356             0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39,
357             0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67,
358             0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1,
359         } },
360     };
361
362     errors = 0;
363
364     for (i = 0; i < sizeof(tests) / sizeof(*tests); i++) {
365         SHA256_Simple(tests[i].teststring,
366                       strlen(tests[i].teststring), digest);
367         for (j = 0; j < 32; j++) {
368             if (digest[j] != tests[i].digest[j]) {
369                 fprintf(stderr,
370                         "\"%s\" digest byte %d should be 0x%02x, is 0x%02x\n",
371                         tests[i].teststring, j, tests[i].digest[j], digest[j]);
372                 errors++;
373             }
374         }
375     }
376
377     printf("%d errors\n", errors);
378
379     return 0;
380 }
381
382 #endif