Commit | Line | Data |
---|---|---|
c988f1f4 | 1 | /* $Cambridge: exim/src/src/auths/md5.c,v 1.2 2005/01/04 10:00:43 ph10 Exp $ */ |
0756eb3c PH |
2 | |
3 | /************************************************* | |
4 | * Exim - an Internet mail transport agent * | |
5 | *************************************************/ | |
6 | ||
c988f1f4 | 7 | /* Copyright (c) University of Cambridge 1995 - 2005 */ |
0756eb3c PH |
8 | /* See the file NOTICE for conditions of use and distribution. */ |
9 | ||
10 | #ifndef STAND_ALONE | |
11 | #include "../exim.h" | |
12 | ||
13 | /* For stand-alone testing, we need to have the structure defined, and | |
14 | to be able to do I/O */ | |
15 | ||
16 | #else | |
17 | #include <stdio.h> | |
18 | #include "../mytypes.h" | |
19 | typedef struct md5 { | |
20 | unsigned int length; | |
21 | unsigned int abcd[4]; | |
22 | } | |
23 | md5; | |
24 | #endif | |
25 | ||
26 | ||
27 | ||
28 | /************************************************* | |
29 | * Start off a new MD5 computation. * | |
30 | *************************************************/ | |
31 | ||
32 | /* | |
33 | Argument: pointer to md5 storage structure | |
34 | Returns: nothing | |
35 | */ | |
36 | ||
37 | void | |
38 | md5_start(md5 *base) | |
39 | { | |
40 | base->abcd[0] = 0x67452301; | |
41 | base->abcd[1] = 0xefcdab89; | |
42 | base->abcd[2] = 0x98badcfe; | |
43 | base->abcd[3] = 0x10325476; | |
44 | base->length = 0; | |
45 | } | |
46 | ||
47 | ||
48 | ||
49 | /************************************************* | |
50 | * Process another 64-byte block * | |
51 | *************************************************/ | |
52 | ||
53 | /* This function implements central part of the algorithm which is described | |
54 | in RFC 1321. | |
55 | ||
56 | Arguments: | |
57 | base pointer to md5 storage structure | |
58 | text pointer to next 64 bytes of subject text | |
59 | ||
60 | Returns: nothing | |
61 | */ | |
62 | ||
63 | void | |
64 | md5_mid(md5 *base, const uschar *text) | |
65 | { | |
66 | register unsigned int a = base->abcd[0]; | |
67 | register unsigned int b = base->abcd[1]; | |
68 | register unsigned int c = base->abcd[2]; | |
69 | register unsigned int d = base->abcd[3]; | |
70 | int i; | |
71 | unsigned int X[16]; | |
72 | base->length += 64; | |
73 | ||
74 | /* Load the 64 bytes into a set of working integers, treating them as 32-bit | |
75 | numbers in little-endian order. */ | |
76 | ||
77 | for (i = 0; i < 16; i++) | |
78 | { | |
79 | X[i] = (unsigned int)(text[0]) | | |
80 | ((unsigned int)(text[1]) << 8) | | |
81 | ((unsigned int)(text[2]) << 16) | | |
82 | ((unsigned int)(text[3]) << 24); | |
83 | text += 4; | |
84 | } | |
85 | ||
86 | /* For each round of processing there is a function to be applied. We define it | |
87 | as a macro each time round. */ | |
88 | ||
89 | /*********************************************** | |
90 | * Round 1 * | |
91 | * F(X,Y,Z) = XY v not(X) Z * | |
92 | * a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s) * | |
93 | ***********************************************/ | |
94 | ||
95 | #define OP(a, b, c, d, k, s, ti) \ | |
96 | a += ((b & c) | (~b & d)) + X[k] + (unsigned int)ti; \ | |
97 | a = b + ((a << s) | (a >> (32 - s))) | |
98 | ||
99 | OP(a, b, c, d, 0, 7, 0xd76aa478); | |
100 | OP(d, a, b, c, 1, 12, 0xe8c7b756); | |
101 | OP(c, d, a, b, 2, 17, 0x242070db); | |
102 | OP(b, c, d, a, 3, 22, 0xc1bdceee); | |
103 | OP(a, b, c, d, 4, 7, 0xf57c0faf); | |
104 | OP(d, a, b, c, 5, 12, 0x4787c62a); | |
105 | OP(c, d, a, b, 6, 17, 0xa8304613); | |
106 | OP(b, c, d, a, 7, 22, 0xfd469501); | |
107 | OP(a, b, c, d, 8, 7, 0x698098d8); | |
108 | OP(d, a, b, c, 9, 12, 0x8b44f7af); | |
109 | OP(c, d, a, b, 10, 17, 0xffff5bb1); | |
110 | OP(b, c, d, a, 11, 22, 0x895cd7be); | |
111 | OP(a, b, c, d, 12, 7, 0x6b901122); | |
112 | OP(d, a, b, c, 13, 12, 0xfd987193); | |
113 | OP(c, d, a, b, 14, 17, 0xa679438e); | |
114 | OP(b, c, d, a, 15, 22, 0x49b40821); | |
115 | ||
116 | #undef OP | |
117 | ||
118 | /*********************************************** | |
119 | * Round 2 * | |
120 | * F(X,Y,Z) = XZ v Y not(Z) * | |
121 | * a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s) * | |
122 | ***********************************************/ | |
123 | ||
124 | #define OP(a, b, c, d, k, s, ti) \ | |
125 | a += ((b & d) | (c & ~d)) + X[k] + (unsigned int)ti; \ | |
126 | a = b + ((a << s) | (a >> (32 - s))) | |
127 | ||
128 | OP(a, b, c, d, 1, 5, 0xf61e2562); | |
129 | OP(d, a, b, c, 6, 9, 0xc040b340); | |
130 | OP(c, d, a, b, 11, 14, 0x265e5a51); | |
131 | OP(b, c, d, a, 0, 20, 0xe9b6c7aa); | |
132 | OP(a, b, c, d, 5, 5, 0xd62f105d); | |
133 | OP(d, a, b, c, 10, 9, 0x02441453); | |
134 | OP(c, d, a, b, 15, 14, 0xd8a1e681); | |
135 | OP(b, c, d, a, 4, 20, 0xe7d3fbc8); | |
136 | OP(a, b, c, d, 9, 5, 0x21e1cde6); | |
137 | OP(d, a, b, c, 14, 9, 0xc33707d6); | |
138 | OP(c, d, a, b, 3, 14, 0xf4d50d87); | |
139 | OP(b, c, d, a, 8, 20, 0x455a14ed); | |
140 | OP(a, b, c, d, 13, 5, 0xa9e3e905); | |
141 | OP(d, a, b, c, 2, 9, 0xfcefa3f8); | |
142 | OP(c, d, a, b, 7, 14, 0x676f02d9); | |
143 | OP(b, c, d, a, 12, 20, 0x8d2a4c8a); | |
144 | ||
145 | #undef OP | |
146 | ||
147 | /*********************************************** | |
148 | * Round 3 * | |
149 | * F(X,Y,Z) = X xor Y xor Z * | |
150 | * a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s) * | |
151 | ***********************************************/ | |
152 | ||
153 | #define OP(a, b, c, d, k, s, ti) \ | |
154 | a += (b ^ c ^ d) + X[k] + (unsigned int)ti; \ | |
155 | a = b + ((a << s) | (a >> (32 - s))) | |
156 | ||
157 | OP(a, b, c, d, 5, 4, 0xfffa3942); | |
158 | OP(d, a, b, c, 8, 11, 0x8771f681); | |
159 | OP(c, d, a, b, 11, 16, 0x6d9d6122); | |
160 | OP(b, c, d, a, 14, 23, 0xfde5380c); | |
161 | OP(a, b, c, d, 1, 4, 0xa4beea44); | |
162 | OP(d, a, b, c, 4, 11, 0x4bdecfa9); | |
163 | OP(c, d, a, b, 7, 16, 0xf6bb4b60); | |
164 | OP(b, c, d, a, 10, 23, 0xbebfbc70); | |
165 | OP(a, b, c, d, 13, 4, 0x289b7ec6); | |
166 | OP(d, a, b, c, 0, 11, 0xeaa127fa); | |
167 | OP(c, d, a, b, 3, 16, 0xd4ef3085); | |
168 | OP(b, c, d, a, 6, 23, 0x04881d05); | |
169 | OP(a, b, c, d, 9, 4, 0xd9d4d039); | |
170 | OP(d, a, b, c, 12, 11, 0xe6db99e5); | |
171 | OP(c, d, a, b, 15, 16, 0x1fa27cf8); | |
172 | OP(b, c, d, a, 2, 23, 0xc4ac5665); | |
173 | ||
174 | #undef OP | |
175 | ||
176 | /*********************************************** | |
177 | * Round 4 * | |
178 | * F(X,Y,Z) = Y xor (X v not(Z)) * | |
179 | * a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s) * | |
180 | ***********************************************/ | |
181 | ||
182 | #define OP(a, b, c, d, k, s, ti) \ | |
183 | a += (c ^ (b | ~d)) + X[k] + (unsigned int)ti; \ | |
184 | a = b + ((a << s) | (a >> (32 - s))) | |
185 | ||
186 | OP(a, b, c, d, 0, 6, 0xf4292244); | |
187 | OP(d, a, b, c, 7, 10, 0x432aff97); | |
188 | OP(c, d, a, b, 14, 15, 0xab9423a7); | |
189 | OP(b, c, d, a, 5, 21, 0xfc93a039); | |
190 | OP(a, b, c, d, 12, 6, 0x655b59c3); | |
191 | OP(d, a, b, c, 3, 10, 0x8f0ccc92); | |
192 | OP(c, d, a, b, 10, 15, 0xffeff47d); | |
193 | OP(b, c, d, a, 1, 21, 0x85845dd1); | |
194 | OP(a, b, c, d, 8, 6, 0x6fa87e4f); | |
195 | OP(d, a, b, c, 15, 10, 0xfe2ce6e0); | |
196 | OP(c, d, a, b, 6, 15, 0xa3014314); | |
197 | OP(b, c, d, a, 13, 21, 0x4e0811a1); | |
198 | OP(a, b, c, d, 4, 6, 0xf7537e82); | |
199 | OP(d, a, b, c, 11, 10, 0xbd3af235); | |
200 | OP(c, d, a, b, 2, 15, 0x2ad7d2bb); | |
201 | OP(b, c, d, a, 9, 21, 0xeb86d391); | |
202 | ||
203 | #undef OP | |
204 | ||
205 | /* Add the new values back into the accumulators. */ | |
206 | ||
207 | base->abcd[0] += a; | |
208 | base->abcd[1] += b; | |
209 | base->abcd[2] += c; | |
210 | base->abcd[3] += d; | |
211 | } | |
212 | ||
213 | ||
214 | ||
215 | ||
216 | /************************************************* | |
217 | * Process the final text string * | |
218 | *************************************************/ | |
219 | ||
220 | /* The string may be of any length. It is padded out according to the rules | |
221 | for computing MD5 digests. The final result is then converted to text form | |
222 | and returned. | |
223 | ||
224 | Arguments: | |
225 | base pointer to the md5 storage structure | |
226 | text pointer to the final text vector | |
227 | length length of the final text vector | |
228 | digest points to 16 bytes in which to place the result | |
229 | ||
230 | Returns: nothing | |
231 | */ | |
232 | ||
233 | void | |
234 | md5_end(md5 *base, const uschar *text, int length, uschar *digest) | |
235 | { | |
236 | int i; | |
237 | uschar work[64]; | |
238 | ||
239 | /* Process in chunks of 64 until we have less than 64 bytes left. */ | |
240 | ||
241 | while (length >= 64) | |
242 | { | |
243 | md5_mid(base, text); | |
244 | text += 64; | |
245 | length -= 64; | |
246 | } | |
247 | ||
248 | /* If the remaining string contains more than 55 bytes, we must pad it | |
249 | out to 64, process it, and then set up the final chunk as 56 bytes of | |
250 | padding. If it has less than 56 bytes, we pad it out to 56 bytes as the | |
251 | final chunk. */ | |
252 | ||
253 | memcpy(work, text, length); | |
254 | work[length] = 0x80; | |
255 | ||
256 | if (length > 55) | |
257 | { | |
258 | memset(work+length+1, 0, 63-length); | |
259 | md5_mid(base, work); | |
260 | base->length -= 64; | |
261 | memset(work, 0, 56); | |
262 | } | |
263 | else | |
264 | { | |
265 | memset(work+length+1, 0, 55-length); | |
266 | } | |
267 | ||
268 | /* The final 8 bytes of the final chunk are a 64-bit representation of the | |
269 | length of the input string *bits*, before padding, low order word first, and | |
270 | low order bytes first in each word. This implementation is designed for short | |
271 | strings, and so operates with a single int counter only. */ | |
272 | ||
273 | length += base->length; /* Total length in bytes */ | |
274 | length <<= 3; /* Total length in bits */ | |
275 | ||
276 | work[56] = length & 0xff; | |
277 | work[57] = (length >> 8) & 0xff; | |
278 | work[58] = (length >> 16) & 0xff; | |
279 | work[59] = (length >> 24) & 0xff; | |
280 | ||
281 | memset(work+60, 0, 4); | |
282 | ||
283 | /* Process the final 64-byte chunk */ | |
284 | ||
285 | md5_mid(base, work); | |
286 | ||
287 | /* Pass back the result, low-order byte first in each word. */ | |
288 | ||
289 | for (i = 0; i < 4; i++) | |
290 | { | |
291 | register int x = base->abcd[i]; | |
292 | *digest++ = x & 0xff; | |
293 | *digest++ = (x >> 8) & 0xff; | |
294 | *digest++ = (x >> 16) & 0xff; | |
295 | *digest++ = (x >> 24) & 0xff; | |
296 | } | |
297 | } | |
298 | ||
299 | ||
300 | ||
301 | /************************************************* | |
302 | ************************************************** | |
303 | * Stand-alone test program * | |
304 | ************************************************** | |
305 | *************************************************/ | |
306 | ||
307 | #if defined STAND_ALONE & !defined CRAM_STAND_ALONE | |
308 | ||
309 | /* Test values */ | |
310 | ||
311 | static uschar *tests[] = { | |
312 | "", "d41d8cd98f00b204e9800998ecf8427e", | |
313 | ||
314 | "a", "0cc175b9c0f1b6a831c399e269772661", | |
315 | ||
316 | "abc", "900150983cd24fb0d6963f7d28e17f72", | |
317 | ||
318 | "message digest", "f96b697d7cb7938d525a2f31aaf161d0", | |
319 | ||
320 | "abcdefghijklmnopqrstuvwxyz", "c3fcd3d76192e4007dfb496cca67e13b", | |
321 | ||
322 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", | |
323 | "d174ab98d277d9f5a5611c2c9f419d9f", | |
324 | ||
325 | "1234567890123456789012345678901234567890123456789012345678901234567890" | |
326 | "1234567890", | |
327 | "57edf4a22be3c955ac49da2e2107b67a", | |
328 | ||
329 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" | |
330 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" | |
331 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", | |
332 | "a0842fcc02167127b0bb9a7c38e71ba8" | |
333 | }; | |
334 | ||
335 | int main(void) | |
336 | { | |
337 | md5 base; | |
338 | int i = 0x01020304; | |
339 | uschar *ctest = (uschar *)(&i); | |
340 | uschar buffer[256]; | |
341 | uschar digest[16]; | |
342 | printf("Checking md5: %s-endian\n", (ctest[0] == 0x04)? "little" : "big"); | |
343 | ||
344 | for (i = 0; i < sizeof(tests)/sizeof(uschar *); i += 2) | |
345 | { | |
346 | int j; | |
347 | uschar s[33]; | |
348 | printf("%s\nShould be: %s\n", tests[i], tests[i+1]); | |
349 | md5_start(&base); | |
350 | md5_end(&base, tests[i], strlen(tests[i]), digest); | |
351 | for (j = 0; j < 16; j++) sprintf(s+2*j, "%02x", digest[j]); | |
352 | printf("Computed: %s\n", s); | |
353 | if (strcmp(s, tests[i+1]) != 0) printf("*** No match ***\n"); | |
354 | printf("\n"); | |
355 | } | |
356 | } | |
357 | #endif | |
358 | ||
359 | /* End of md5.c */ |