more refactoring of the settings (information hiding and code cleanup)
[TortoiseGit.git] / src / TortoisePlink / SSHMD5.C
blob80474dfadd9c861df8eeca745ddeff78de4e0cab
1 #include "ssh.h"\r
2 \r
3 /*\r
4  * MD5 implementation for PuTTY. Written directly from the spec by\r
5  * Simon Tatham.\r
6  */\r
7 \r
8 /* ----------------------------------------------------------------------\r
9  * Core MD5 algorithm: processes 16-word blocks into a message digest.\r
10  */\r
12 #define F(x,y,z) ( ((x) & (y)) | ((~(x)) & (z)) )\r
13 #define G(x,y,z) ( ((x) & (z)) | ((~(z)) & (y)) )\r
14 #define H(x,y,z) ( (x) ^ (y) ^ (z) )\r
15 #define I(x,y,z) ( (y) ^ ( (x) | ~(z) ) )\r
17 #define rol(x,y) ( ((x) << (y)) | (((uint32)x) >> (32-y)) )\r
19 #define subround(f,w,x,y,z,k,s,ti) \\r
20        w = x + rol(w + f(x,y,z) + block[k] + ti, s)\r
22 static void MD5_Core_Init(MD5_Core_State * s)\r
23 {\r
24     s->h[0] = 0x67452301;\r
25     s->h[1] = 0xefcdab89;\r
26     s->h[2] = 0x98badcfe;\r
27     s->h[3] = 0x10325476;\r
28 }\r
30 static void MD5_Block(MD5_Core_State * s, uint32 * block)\r
31 {\r
32     uint32 a, b, c, d;\r
34     a = s->h[0];\r
35     b = s->h[1];\r
36     c = s->h[2];\r
37     d = s->h[3];\r
39     subround(F, a, b, c, d, 0, 7, 0xd76aa478);\r
40     subround(F, d, a, b, c, 1, 12, 0xe8c7b756);\r
41     subround(F, c, d, a, b, 2, 17, 0x242070db);\r
42     subround(F, b, c, d, a, 3, 22, 0xc1bdceee);\r
43     subround(F, a, b, c, d, 4, 7, 0xf57c0faf);\r
44     subround(F, d, a, b, c, 5, 12, 0x4787c62a);\r
45     subround(F, c, d, a, b, 6, 17, 0xa8304613);\r
46     subround(F, b, c, d, a, 7, 22, 0xfd469501);\r
47     subround(F, a, b, c, d, 8, 7, 0x698098d8);\r
48     subround(F, d, a, b, c, 9, 12, 0x8b44f7af);\r
49     subround(F, c, d, a, b, 10, 17, 0xffff5bb1);\r
50     subround(F, b, c, d, a, 11, 22, 0x895cd7be);\r
51     subround(F, a, b, c, d, 12, 7, 0x6b901122);\r
52     subround(F, d, a, b, c, 13, 12, 0xfd987193);\r
53     subround(F, c, d, a, b, 14, 17, 0xa679438e);\r
54     subround(F, b, c, d, a, 15, 22, 0x49b40821);\r
55     subround(G, a, b, c, d, 1, 5, 0xf61e2562);\r
56     subround(G, d, a, b, c, 6, 9, 0xc040b340);\r
57     subround(G, c, d, a, b, 11, 14, 0x265e5a51);\r
58     subround(G, b, c, d, a, 0, 20, 0xe9b6c7aa);\r
59     subround(G, a, b, c, d, 5, 5, 0xd62f105d);\r
60     subround(G, d, a, b, c, 10, 9, 0x02441453);\r
61     subround(G, c, d, a, b, 15, 14, 0xd8a1e681);\r
62     subround(G, b, c, d, a, 4, 20, 0xe7d3fbc8);\r
63     subround(G, a, b, c, d, 9, 5, 0x21e1cde6);\r
64     subround(G, d, a, b, c, 14, 9, 0xc33707d6);\r
65     subround(G, c, d, a, b, 3, 14, 0xf4d50d87);\r
66     subround(G, b, c, d, a, 8, 20, 0x455a14ed);\r
67     subround(G, a, b, c, d, 13, 5, 0xa9e3e905);\r
68     subround(G, d, a, b, c, 2, 9, 0xfcefa3f8);\r
69     subround(G, c, d, a, b, 7, 14, 0x676f02d9);\r
70     subround(G, b, c, d, a, 12, 20, 0x8d2a4c8a);\r
71     subround(H, a, b, c, d, 5, 4, 0xfffa3942);\r
72     subround(H, d, a, b, c, 8, 11, 0x8771f681);\r
73     subround(H, c, d, a, b, 11, 16, 0x6d9d6122);\r
74     subround(H, b, c, d, a, 14, 23, 0xfde5380c);\r
75     subround(H, a, b, c, d, 1, 4, 0xa4beea44);\r
76     subround(H, d, a, b, c, 4, 11, 0x4bdecfa9);\r
77     subround(H, c, d, a, b, 7, 16, 0xf6bb4b60);\r
78     subround(H, b, c, d, a, 10, 23, 0xbebfbc70);\r
79     subround(H, a, b, c, d, 13, 4, 0x289b7ec6);\r
80     subround(H, d, a, b, c, 0, 11, 0xeaa127fa);\r
81     subround(H, c, d, a, b, 3, 16, 0xd4ef3085);\r
82     subround(H, b, c, d, a, 6, 23, 0x04881d05);\r
83     subround(H, a, b, c, d, 9, 4, 0xd9d4d039);\r
84     subround(H, d, a, b, c, 12, 11, 0xe6db99e5);\r
85     subround(H, c, d, a, b, 15, 16, 0x1fa27cf8);\r
86     subround(H, b, c, d, a, 2, 23, 0xc4ac5665);\r
87     subround(I, a, b, c, d, 0, 6, 0xf4292244);\r
88     subround(I, d, a, b, c, 7, 10, 0x432aff97);\r
89     subround(I, c, d, a, b, 14, 15, 0xab9423a7);\r
90     subround(I, b, c, d, a, 5, 21, 0xfc93a039);\r
91     subround(I, a, b, c, d, 12, 6, 0x655b59c3);\r
92     subround(I, d, a, b, c, 3, 10, 0x8f0ccc92);\r
93     subround(I, c, d, a, b, 10, 15, 0xffeff47d);\r
94     subround(I, b, c, d, a, 1, 21, 0x85845dd1);\r
95     subround(I, a, b, c, d, 8, 6, 0x6fa87e4f);\r
96     subround(I, d, a, b, c, 15, 10, 0xfe2ce6e0);\r
97     subround(I, c, d, a, b, 6, 15, 0xa3014314);\r
98     subround(I, b, c, d, a, 13, 21, 0x4e0811a1);\r
99     subround(I, a, b, c, d, 4, 6, 0xf7537e82);\r
100     subround(I, d, a, b, c, 11, 10, 0xbd3af235);\r
101     subround(I, c, d, a, b, 2, 15, 0x2ad7d2bb);\r
102     subround(I, b, c, d, a, 9, 21, 0xeb86d391);\r
104     s->h[0] += a;\r
105     s->h[1] += b;\r
106     s->h[2] += c;\r
107     s->h[3] += d;\r
110 /* ----------------------------------------------------------------------\r
111  * Outer MD5 algorithm: take an arbitrary length byte string,\r
112  * convert it into 16-word blocks with the prescribed padding at\r
113  * the end, and pass those blocks to the core MD5 algorithm.\r
114  */\r
116 #define BLKSIZE 64\r
118 void MD5Init(struct MD5Context *s)\r
120     MD5_Core_Init(&s->core);\r
121     s->blkused = 0;\r
122     s->lenhi = s->lenlo = 0;\r
125 void MD5Update(struct MD5Context *s, unsigned char const *p, unsigned len)\r
127     unsigned char *q = (unsigned char *) p;\r
128     uint32 wordblock[16];\r
129     uint32 lenw = len;\r
130     int i;\r
132     /*\r
133      * Update the length field.\r
134      */\r
135     s->lenlo += lenw;\r
136     s->lenhi += (s->lenlo < lenw);\r
138     if (s->blkused + len < BLKSIZE) {\r
139         /*\r
140          * Trivial case: just add to the block.\r
141          */\r
142         memcpy(s->block + s->blkused, q, len);\r
143         s->blkused += len;\r
144     } else {\r
145         /*\r
146          * We must complete and process at least one block.\r
147          */\r
148         while (s->blkused + len >= BLKSIZE) {\r
149             memcpy(s->block + s->blkused, q, BLKSIZE - s->blkused);\r
150             q += BLKSIZE - s->blkused;\r
151             len -= BLKSIZE - s->blkused;\r
152             /* Now process the block. Gather bytes little-endian into words */\r
153             for (i = 0; i < 16; i++) {\r
154                 wordblock[i] =\r
155                     (((uint32) s->block[i * 4 + 3]) << 24) |\r
156                     (((uint32) s->block[i * 4 + 2]) << 16) |\r
157                     (((uint32) s->block[i * 4 + 1]) << 8) |\r
158                     (((uint32) s->block[i * 4 + 0]) << 0);\r
159             }\r
160             MD5_Block(&s->core, wordblock);\r
161             s->blkused = 0;\r
162         }\r
163         memcpy(s->block, q, len);\r
164         s->blkused = len;\r
165     }\r
168 void MD5Final(unsigned char output[16], struct MD5Context *s)\r
170     int i;\r
171     unsigned pad;\r
172     unsigned char c[64];\r
173     uint32 lenhi, lenlo;\r
175     if (s->blkused >= 56)\r
176         pad = 56 + 64 - s->blkused;\r
177     else\r
178         pad = 56 - s->blkused;\r
180     lenhi = (s->lenhi << 3) | (s->lenlo >> (32 - 3));\r
181     lenlo = (s->lenlo << 3);\r
183     memset(c, 0, pad);\r
184     c[0] = 0x80;\r
185     MD5Update(s, c, pad);\r
187     c[7] = (lenhi >> 24) & 0xFF;\r
188     c[6] = (lenhi >> 16) & 0xFF;\r
189     c[5] = (lenhi >> 8) & 0xFF;\r
190     c[4] = (lenhi >> 0) & 0xFF;\r
191     c[3] = (lenlo >> 24) & 0xFF;\r
192     c[2] = (lenlo >> 16) & 0xFF;\r
193     c[1] = (lenlo >> 8) & 0xFF;\r
194     c[0] = (lenlo >> 0) & 0xFF;\r
196     MD5Update(s, c, 8);\r
198     for (i = 0; i < 4; i++) {\r
199         output[4 * i + 3] = (s->core.h[i] >> 24) & 0xFF;\r
200         output[4 * i + 2] = (s->core.h[i] >> 16) & 0xFF;\r
201         output[4 * i + 1] = (s->core.h[i] >> 8) & 0xFF;\r
202         output[4 * i + 0] = (s->core.h[i] >> 0) & 0xFF;\r
203     }\r
206 void MD5Simple(void const *p, unsigned len, unsigned char output[16])\r
208     struct MD5Context s;\r
210     MD5Init(&s);\r
211     MD5Update(&s, (unsigned char const *)p, len);\r
212     MD5Final(output, &s);\r
215 /* ----------------------------------------------------------------------\r
216  * The above is the MD5 algorithm itself. Now we implement the\r
217  * HMAC wrapper on it.\r
218  * \r
219  * Some of these functions are exported directly, because they are\r
220  * useful elsewhere (SOCKS5 CHAP authentication uses HMAC-MD5).\r
221  */\r
223 void *hmacmd5_make_context(void)\r
225     return snewn(3, struct MD5Context);\r
228 void hmacmd5_free_context(void *handle)\r
230     sfree(handle);\r
233 void hmacmd5_key(void *handle, void const *keyv, int len)\r
235     struct MD5Context *keys = (struct MD5Context *)handle;\r
236     unsigned char foo[64];\r
237     unsigned char const *key = (unsigned char const *)keyv;\r
238     int i;\r
240     memset(foo, 0x36, 64);\r
241     for (i = 0; i < len && i < 64; i++)\r
242         foo[i] ^= key[i];\r
243     MD5Init(&keys[0]);\r
244     MD5Update(&keys[0], foo, 64);\r
246     memset(foo, 0x5C, 64);\r
247     for (i = 0; i < len && i < 64; i++)\r
248         foo[i] ^= key[i];\r
249     MD5Init(&keys[1]);\r
250     MD5Update(&keys[1], foo, 64);\r
252     memset(foo, 0, 64);                /* burn the evidence */\r
255 static void hmacmd5_key_16(void *handle, unsigned char *key)\r
257     hmacmd5_key(handle, key, 16);\r
260 static void hmacmd5_start(void *handle)\r
262     struct MD5Context *keys = (struct MD5Context *)handle;\r
264     keys[2] = keys[0];                /* structure copy */\r
267 static void hmacmd5_bytes(void *handle, unsigned char const *blk, int len)\r
269     struct MD5Context *keys = (struct MD5Context *)handle;\r
270     MD5Update(&keys[2], blk, len);\r
273 static void hmacmd5_genresult(void *handle, unsigned char *hmac)\r
275     struct MD5Context *keys = (struct MD5Context *)handle;\r
276     struct MD5Context s;\r
277     unsigned char intermediate[16];\r
279     s = keys[2];                       /* structure copy */\r
280     MD5Final(intermediate, &s);\r
281     s = keys[1];                       /* structure copy */\r
282     MD5Update(&s, intermediate, 16);\r
283     MD5Final(hmac, &s);\r
286 static int hmacmd5_verresult(void *handle, unsigned char const *hmac)\r
288     unsigned char correct[16];\r
289     hmacmd5_genresult(handle, correct);\r
290     return !memcmp(correct, hmac, 16);\r
293 static void hmacmd5_do_hmac_internal(void *handle,\r
294                                      unsigned char const *blk, int len,\r
295                                      unsigned char const *blk2, int len2,\r
296                                      unsigned char *hmac)\r
298     hmacmd5_start(handle);\r
299     hmacmd5_bytes(handle, blk, len);\r
300     if (blk2) hmacmd5_bytes(handle, blk2, len2);\r
301     hmacmd5_genresult(handle, hmac);\r
304 void hmacmd5_do_hmac(void *handle, unsigned char const *blk, int len,\r
305                      unsigned char *hmac)\r
307     hmacmd5_do_hmac_internal(handle, blk, len, NULL, 0, hmac);\r
310 static void hmacmd5_do_hmac_ssh(void *handle, unsigned char const *blk, int len,\r
311                                 unsigned long seq, unsigned char *hmac)\r
313     unsigned char seqbuf[16];\r
315     seqbuf[0] = (unsigned char) ((seq >> 24) & 0xFF);\r
316     seqbuf[1] = (unsigned char) ((seq >> 16) & 0xFF);\r
317     seqbuf[2] = (unsigned char) ((seq >> 8) & 0xFF);\r
318     seqbuf[3] = (unsigned char) ((seq) & 0xFF);\r
320     hmacmd5_do_hmac_internal(handle, seqbuf, 4, blk, len, hmac);\r
323 static void hmacmd5_generate(void *handle, unsigned char *blk, int len,\r
324                              unsigned long seq)\r
326     hmacmd5_do_hmac_ssh(handle, blk, len, seq, blk + len);\r
329 static int hmacmd5_verify(void *handle, unsigned char *blk, int len,\r
330                           unsigned long seq)\r
332     unsigned char correct[16];\r
333     hmacmd5_do_hmac_ssh(handle, blk, len, seq, correct);\r
334     return !memcmp(correct, blk + len, 16);\r
337 const struct ssh_mac ssh_hmac_md5 = {\r
338     hmacmd5_make_context, hmacmd5_free_context, hmacmd5_key_16,\r
339     hmacmd5_generate, hmacmd5_verify,\r
340     hmacmd5_start, hmacmd5_bytes, hmacmd5_genresult, hmacmd5_verresult,\r
341     "hmac-md5",\r
342     16,\r
343     "HMAC-MD5"\r
344 };\r