diff options
Diffstat (limited to 'src/md5.c')
-rw-r--r-- | src/md5.c | 355 |
1 files changed, 355 insertions, 0 deletions
diff --git a/src/md5.c b/src/md5.c new file mode 100644 index 0000000..fdb144e --- /dev/null +++ b/src/md5.c @@ -0,0 +1,355 @@ +/************************************************* +* Exim - an Internet mail transport agent * +*************************************************/ + +/* Copyright (c) University of Cambridge 1995 - 2018 */ +/* Copyright (c) The Exim Maintainers 2020 */ +/* See the file NOTICE for conditions of use and distribution. */ + +#ifndef STAND_ALONE +#include "exim.h" + +/* For stand-alone testing, we need to have the structure defined, and +to be able to do I/O */ + +#else +#include <stdio.h> +#include "../mytypes.h" +typedef struct md5 { + unsigned int length; + unsigned int abcd[4]; + } +md5; +#endif + + + +/************************************************* +* Start off a new MD5 computation. * +*************************************************/ + +/* +Argument: pointer to md5 storage structure +Returns: nothing +*/ + +void +md5_start(md5 *base) +{ +base->abcd[0] = 0x67452301; +base->abcd[1] = 0xefcdab89; +base->abcd[2] = 0x98badcfe; +base->abcd[3] = 0x10325476; +base->length = 0; +} + + + +/************************************************* +* Process another 64-byte block * +*************************************************/ + +/* This function implements central part of the algorithm which is described +in RFC 1321. + +Arguments: + base pointer to md5 storage structure + text pointer to next 64 bytes of subject text + +Returns: nothing +*/ + +void +md5_mid(md5 *base, const uschar *text) +{ +register unsigned int a = base->abcd[0]; +register unsigned int b = base->abcd[1]; +register unsigned int c = base->abcd[2]; +register unsigned int d = base->abcd[3]; +unsigned int X[16]; +base->length += 64; + +/* Load the 64 bytes into a set of working integers, treating them as 32-bit +numbers in little-endian order. */ + +for (int i = 0; i < 16; i++) + { + X[i] = (unsigned int)(text[0]) | + ((unsigned int)(text[1]) << 8) | + ((unsigned int)(text[2]) << 16) | + ((unsigned int)(text[3]) << 24); + text += 4; + } + +/* For each round of processing there is a function to be applied. We define it +as a macro each time round. */ + +/*********************************************** +* Round 1 * +* F(X,Y,Z) = XY v not(X) Z * +* a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s) * +***********************************************/ + +#define OP(a, b, c, d, k, s, ti) \ + a += ((b & c) | (~b & d)) + X[k] + (unsigned int)ti; \ + a = b + ((a << s) | (a >> (32 - s))) + +OP(a, b, c, d, 0, 7, 0xd76aa478); +OP(d, a, b, c, 1, 12, 0xe8c7b756); +OP(c, d, a, b, 2, 17, 0x242070db); +OP(b, c, d, a, 3, 22, 0xc1bdceee); +OP(a, b, c, d, 4, 7, 0xf57c0faf); +OP(d, a, b, c, 5, 12, 0x4787c62a); +OP(c, d, a, b, 6, 17, 0xa8304613); +OP(b, c, d, a, 7, 22, 0xfd469501); +OP(a, b, c, d, 8, 7, 0x698098d8); +OP(d, a, b, c, 9, 12, 0x8b44f7af); +OP(c, d, a, b, 10, 17, 0xffff5bb1); +OP(b, c, d, a, 11, 22, 0x895cd7be); +OP(a, b, c, d, 12, 7, 0x6b901122); +OP(d, a, b, c, 13, 12, 0xfd987193); +OP(c, d, a, b, 14, 17, 0xa679438e); +OP(b, c, d, a, 15, 22, 0x49b40821); + +#undef OP + +/*********************************************** +* Round 2 * +* F(X,Y,Z) = XZ v Y not(Z) * +* a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s) * +***********************************************/ + +#define OP(a, b, c, d, k, s, ti) \ + a += ((b & d) | (c & ~d)) + X[k] + (unsigned int)ti; \ + a = b + ((a << s) | (a >> (32 - s))) + +OP(a, b, c, d, 1, 5, 0xf61e2562); +OP(d, a, b, c, 6, 9, 0xc040b340); +OP(c, d, a, b, 11, 14, 0x265e5a51); +OP(b, c, d, a, 0, 20, 0xe9b6c7aa); +OP(a, b, c, d, 5, 5, 0xd62f105d); +OP(d, a, b, c, 10, 9, 0x02441453); +OP(c, d, a, b, 15, 14, 0xd8a1e681); +OP(b, c, d, a, 4, 20, 0xe7d3fbc8); +OP(a, b, c, d, 9, 5, 0x21e1cde6); +OP(d, a, b, c, 14, 9, 0xc33707d6); +OP(c, d, a, b, 3, 14, 0xf4d50d87); +OP(b, c, d, a, 8, 20, 0x455a14ed); +OP(a, b, c, d, 13, 5, 0xa9e3e905); +OP(d, a, b, c, 2, 9, 0xfcefa3f8); +OP(c, d, a, b, 7, 14, 0x676f02d9); +OP(b, c, d, a, 12, 20, 0x8d2a4c8a); + +#undef OP + +/*********************************************** +* Round 3 * +* F(X,Y,Z) = X xor Y xor Z * +* a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s) * +***********************************************/ + +#define OP(a, b, c, d, k, s, ti) \ + a += (b ^ c ^ d) + X[k] + (unsigned int)ti; \ + a = b + ((a << s) | (a >> (32 - s))) + +OP(a, b, c, d, 5, 4, 0xfffa3942); +OP(d, a, b, c, 8, 11, 0x8771f681); +OP(c, d, a, b, 11, 16, 0x6d9d6122); +OP(b, c, d, a, 14, 23, 0xfde5380c); +OP(a, b, c, d, 1, 4, 0xa4beea44); +OP(d, a, b, c, 4, 11, 0x4bdecfa9); +OP(c, d, a, b, 7, 16, 0xf6bb4b60); +OP(b, c, d, a, 10, 23, 0xbebfbc70); +OP(a, b, c, d, 13, 4, 0x289b7ec6); +OP(d, a, b, c, 0, 11, 0xeaa127fa); +OP(c, d, a, b, 3, 16, 0xd4ef3085); +OP(b, c, d, a, 6, 23, 0x04881d05); +OP(a, b, c, d, 9, 4, 0xd9d4d039); +OP(d, a, b, c, 12, 11, 0xe6db99e5); +OP(c, d, a, b, 15, 16, 0x1fa27cf8); +OP(b, c, d, a, 2, 23, 0xc4ac5665); + +#undef OP + +/*********************************************** +* Round 4 * +* F(X,Y,Z) = Y xor (X v not(Z)) * +* a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s) * +***********************************************/ + +#define OP(a, b, c, d, k, s, ti) \ + a += (c ^ (b | ~d)) + X[k] + (unsigned int)ti; \ + a = b + ((a << s) | (a >> (32 - s))) + +OP(a, b, c, d, 0, 6, 0xf4292244); +OP(d, a, b, c, 7, 10, 0x432aff97); +OP(c, d, a, b, 14, 15, 0xab9423a7); +OP(b, c, d, a, 5, 21, 0xfc93a039); +OP(a, b, c, d, 12, 6, 0x655b59c3); +OP(d, a, b, c, 3, 10, 0x8f0ccc92); +OP(c, d, a, b, 10, 15, 0xffeff47d); +OP(b, c, d, a, 1, 21, 0x85845dd1); +OP(a, b, c, d, 8, 6, 0x6fa87e4f); +OP(d, a, b, c, 15, 10, 0xfe2ce6e0); +OP(c, d, a, b, 6, 15, 0xa3014314); +OP(b, c, d, a, 13, 21, 0x4e0811a1); +OP(a, b, c, d, 4, 6, 0xf7537e82); +OP(d, a, b, c, 11, 10, 0xbd3af235); +OP(c, d, a, b, 2, 15, 0x2ad7d2bb); +OP(b, c, d, a, 9, 21, 0xeb86d391); + +#undef OP + +/* Add the new values back into the accumulators. */ + +base->abcd[0] += a; +base->abcd[1] += b; +base->abcd[2] += c; +base->abcd[3] += d; +} + + + + +/************************************************* +* Process the final text string * +*************************************************/ + +/* The string may be of any length. It is padded out according to the rules +for computing MD5 digests. The final result is then converted to text form +and returned. + +Arguments: + base pointer to the md5 storage structure + text pointer to the final text vector + length length of the final text vector + digest points to 16 bytes in which to place the result + +Returns: nothing +*/ + +void +md5_end(md5 *base, const uschar *text, int length, uschar *digest) +{ +uschar work[64]; + +/* Process in chunks of 64 until we have less than 64 bytes left. */ + +while (length >= 64) + { + md5_mid(base, text); + text += 64; + length -= 64; + } + +/* If the remaining string contains more than 55 bytes, we must pad it +out to 64, process it, and then set up the final chunk as 56 bytes of +padding. If it has less than 56 bytes, we pad it out to 56 bytes as the +final chunk. */ + +memcpy(work, text, length); +work[length] = 0x80; + +if (length > 55) + { + memset(work+length+1, 0, 63-length); + md5_mid(base, work); + base->length -= 64; + memset(work, 0, 56); + } +else + { + memset(work+length+1, 0, 55-length); + } + +/* The final 8 bytes of the final chunk are a 64-bit representation of the +length of the input string *bits*, before padding, low order word first, and +low order bytes first in each word. This implementation is designed for short +strings, and so operates with a single int counter only. */ + +length += base->length; /* Total length in bytes */ +length <<= 3; /* Total length in bits */ + +work[56] = length & 0xff; +work[57] = (length >> 8) & 0xff; +work[58] = (length >> 16) & 0xff; +work[59] = (length >> 24) & 0xff; + +memset(work+60, 0, 4); + +/* Process the final 64-byte chunk */ + +md5_mid(base, work); + +/* Pass back the result, low-order byte first in each word. */ + +for (int i = 0; i < 4; i++) + { + register int x = base->abcd[i]; + *digest++ = x & 0xff; + *digest++ = (x >> 8) & 0xff; + *digest++ = (x >> 16) & 0xff; + *digest++ = (x >> 24) & 0xff; + } +} + + + +/************************************************* +************************************************** +* Stand-alone test program * +************************************************** +*************************************************/ + +#if defined STAND_ALONE & !defined CRAM_STAND_ALONE + +/* Test values */ + +static uschar *tests[] = { + "", "d41d8cd98f00b204e9800998ecf8427e", + + "a", "0cc175b9c0f1b6a831c399e269772661", + + "abc", "900150983cd24fb0d6963f7d28e17f72", + + "message digest", "f96b697d7cb7938d525a2f31aaf161d0", + + "abcdefghijklmnopqrstuvwxyz", "c3fcd3d76192e4007dfb496cca67e13b", + + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + "d174ab98d277d9f5a5611c2c9f419d9f", + + "1234567890123456789012345678901234567890123456789012345678901234567890" + "1234567890", + "57edf4a22be3c955ac49da2e2107b67a", + + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + "a0842fcc02167127b0bb9a7c38e71ba8" +}; + +int main(void) +{ +md5 base; +int i = 0x01020304; +uschar *ctest = US (&i); +uschar buffer[256]; +uschar digest[16]; +printf("Checking md5: %s-endian\n", (ctest[0] == 0x04)? "little" : "big"); + +for (i = 0; i < sizeof(tests)/sizeof(uschar *); i += 2) + { + uschar s[33]; + printf("%s\nShould be: %s\n", tests[i], tests[i+1]); + md5_start(&base); + md5_end(&base, tests[i], strlen(tests[i]), digest); + for (int j = 0; j < 16; j++) sprintf(s+2*j, "%02x", digest[j]); + printf("Computed: %s\n", s); + if (strcmp(s, tests[i+1]) != 0) printf("*** No match ***\n"); + printf("\n"); + } +} +#endif + +/* End of md5.c */ |