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