masqmail

annotate src/md5/md5.c @ 281:ea5f86e0a81c

modes are now enforced exclusive Other MTAs (exim, postfix) are more relaxing, but as combinations of exclusive modes are senseless we behave more obvious if we fail early. This makes understanding the behavior easier too.
author markus schnalke <meillo@marmaro.de>
date Tue, 07 Dec 2010 14:04:56 -0300
parents
children
rev   line source
meillo@209 1 /*
meillo@209 2 * This is an OpenSSL-compatible implementation of the RSA Data Security,
meillo@209 3 * Inc. MD5 Message-Digest Algorithm (RFC 1321).
meillo@209 4 *
meillo@209 5 * Written by Solar Designer <solar at openwall.com> in 2001, and placed
meillo@209 6 * in the public domain. There's absolutely no warranty.
meillo@209 7 *
meillo@209 8 * This differs from Colin Plumb's older public domain implementation in
meillo@209 9 * that no 32-bit integer data type is required, there's no compile-time
meillo@209 10 * endianness configuration, and the function prototypes match OpenSSL's.
meillo@209 11 * The primary goals are portability and ease of use.
meillo@209 12 *
meillo@209 13 * This implementation is meant to be fast, but not as fast as possible.
meillo@209 14 * Some known optimizations are not included to reduce source code size
meillo@209 15 * and avoid compile-time configuration.
meillo@209 16 */
meillo@209 17
meillo@209 18 #ifndef HAVE_OPENSSL
meillo@209 19
meillo@209 20 #include <string.h>
meillo@209 21
meillo@209 22 #include "md5.h"
meillo@209 23
meillo@209 24 /*
meillo@209 25 * The basic MD5 functions.
meillo@209 26 *
meillo@209 27 * F and G are optimized compared to their RFC 1321 definitions for
meillo@209 28 * architectures that lack an AND-NOT instruction, just like in Colin Plumb's
meillo@209 29 * implementation.
meillo@209 30 */
meillo@209 31 #define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
meillo@209 32 #define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
meillo@209 33 #define H(x, y, z) ((x) ^ (y) ^ (z))
meillo@209 34 #define I(x, y, z) ((y) ^ ((x) | ~(z)))
meillo@209 35
meillo@209 36 /*
meillo@209 37 * The MD5 transformation for all four rounds.
meillo@209 38 */
meillo@209 39 #define STEP(f, a, b, c, d, x, t, s) \
meillo@209 40 (a) += f((b), (c), (d)) + (x) + (t); \
meillo@209 41 (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
meillo@209 42 (a) += (b);
meillo@209 43
meillo@209 44 /*
meillo@209 45 * SET reads 4 input bytes in little-endian byte order and stores them
meillo@209 46 * in a properly aligned word in host byte order.
meillo@209 47 *
meillo@209 48 * The check for little-endian architectures that tolerate unaligned
meillo@209 49 * memory accesses is just an optimization. Nothing will break if it
meillo@209 50 * doesn't work.
meillo@209 51 */
meillo@209 52 #if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
meillo@209 53 #define SET(n) \
meillo@209 54 (*(MD5_u32plus *)&ptr[(n) * 4])
meillo@209 55 #define GET(n) \
meillo@209 56 SET(n)
meillo@209 57 #else
meillo@209 58 #define SET(n) \
meillo@209 59 (ctx->block[(n)] = \
meillo@209 60 (MD5_u32plus)ptr[(n) * 4] | \
meillo@209 61 ((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \
meillo@209 62 ((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \
meillo@209 63 ((MD5_u32plus)ptr[(n) * 4 + 3] << 24))
meillo@209 64 #define GET(n) \
meillo@209 65 (ctx->block[(n)])
meillo@209 66 #endif
meillo@209 67
meillo@209 68 /*
meillo@209 69 * This processes one or more 64-byte data blocks, but does NOT update
meillo@209 70 * the bit counters. There are no alignment requirements.
meillo@209 71 */
meillo@209 72 static void *body(MD5_CTX *ctx, void *data, unsigned long size)
meillo@209 73 {
meillo@209 74 unsigned char *ptr;
meillo@209 75 MD5_u32plus a, b, c, d;
meillo@209 76 MD5_u32plus saved_a, saved_b, saved_c, saved_d;
meillo@209 77
meillo@209 78 ptr = data;
meillo@209 79
meillo@209 80 a = ctx->a;
meillo@209 81 b = ctx->b;
meillo@209 82 c = ctx->c;
meillo@209 83 d = ctx->d;
meillo@209 84
meillo@209 85 do {
meillo@209 86 saved_a = a;
meillo@209 87 saved_b = b;
meillo@209 88 saved_c = c;
meillo@209 89 saved_d = d;
meillo@209 90
meillo@209 91 /* Round 1 */
meillo@209 92 STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
meillo@209 93 STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
meillo@209 94 STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
meillo@209 95 STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
meillo@209 96 STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
meillo@209 97 STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
meillo@209 98 STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
meillo@209 99 STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
meillo@209 100 STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
meillo@209 101 STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
meillo@209 102 STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
meillo@209 103 STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
meillo@209 104 STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
meillo@209 105 STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
meillo@209 106 STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
meillo@209 107 STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
meillo@209 108
meillo@209 109 /* Round 2 */
meillo@209 110 STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
meillo@209 111 STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
meillo@209 112 STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
meillo@209 113 STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
meillo@209 114 STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
meillo@209 115 STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
meillo@209 116 STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
meillo@209 117 STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
meillo@209 118 STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
meillo@209 119 STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
meillo@209 120 STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
meillo@209 121 STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
meillo@209 122 STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
meillo@209 123 STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
meillo@209 124 STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
meillo@209 125 STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
meillo@209 126
meillo@209 127 /* Round 3 */
meillo@209 128 STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
meillo@209 129 STEP(H, d, a, b, c, GET(8), 0x8771f681, 11)
meillo@209 130 STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
meillo@209 131 STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23)
meillo@209 132 STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
meillo@209 133 STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11)
meillo@209 134 STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
meillo@209 135 STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23)
meillo@209 136 STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
meillo@209 137 STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11)
meillo@209 138 STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
meillo@209 139 STEP(H, b, c, d, a, GET(6), 0x04881d05, 23)
meillo@209 140 STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
meillo@209 141 STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11)
meillo@209 142 STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
meillo@209 143 STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23)
meillo@209 144
meillo@209 145 /* Round 4 */
meillo@209 146 STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
meillo@209 147 STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
meillo@209 148 STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
meillo@209 149 STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
meillo@209 150 STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
meillo@209 151 STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
meillo@209 152 STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
meillo@209 153 STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
meillo@209 154 STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
meillo@209 155 STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
meillo@209 156 STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
meillo@209 157 STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
meillo@209 158 STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
meillo@209 159 STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
meillo@209 160 STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
meillo@209 161 STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
meillo@209 162
meillo@209 163 a += saved_a;
meillo@209 164 b += saved_b;
meillo@209 165 c += saved_c;
meillo@209 166 d += saved_d;
meillo@209 167
meillo@209 168 ptr += 64;
meillo@209 169 } while (size -= 64);
meillo@209 170
meillo@209 171 ctx->a = a;
meillo@209 172 ctx->b = b;
meillo@209 173 ctx->c = c;
meillo@209 174 ctx->d = d;
meillo@209 175
meillo@209 176 return ptr;
meillo@209 177 }
meillo@209 178
meillo@209 179 void MD5_Init(MD5_CTX *ctx)
meillo@209 180 {
meillo@209 181 ctx->a = 0x67452301;
meillo@209 182 ctx->b = 0xefcdab89;
meillo@209 183 ctx->c = 0x98badcfe;
meillo@209 184 ctx->d = 0x10325476;
meillo@209 185
meillo@209 186 ctx->lo = 0;
meillo@209 187 ctx->hi = 0;
meillo@209 188 }
meillo@209 189
meillo@209 190 void MD5_Update(MD5_CTX *ctx, void *data, unsigned long size)
meillo@209 191 {
meillo@209 192 MD5_u32plus saved_lo;
meillo@209 193 unsigned long used, free;
meillo@209 194
meillo@209 195 saved_lo = ctx->lo;
meillo@209 196 if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
meillo@209 197 ctx->hi++;
meillo@209 198 ctx->hi += size >> 29;
meillo@209 199
meillo@209 200 used = saved_lo & 0x3f;
meillo@209 201
meillo@209 202 if (used) {
meillo@209 203 free = 64 - used;
meillo@209 204
meillo@209 205 if (size < free) {
meillo@209 206 memcpy(&ctx->buffer[used], data, size);
meillo@209 207 return;
meillo@209 208 }
meillo@209 209
meillo@209 210 memcpy(&ctx->buffer[used], data, free);
meillo@209 211 data = (unsigned char *)data + free;
meillo@209 212 size -= free;
meillo@209 213 body(ctx, ctx->buffer, 64);
meillo@209 214 }
meillo@209 215
meillo@209 216 if (size >= 64) {
meillo@209 217 data = body(ctx, data, size & ~(unsigned long)0x3f);
meillo@209 218 size &= 0x3f;
meillo@209 219 }
meillo@209 220
meillo@209 221 memcpy(ctx->buffer, data, size);
meillo@209 222 }
meillo@209 223
meillo@209 224 void MD5_Final(unsigned char *result, MD5_CTX *ctx)
meillo@209 225 {
meillo@209 226 unsigned long used, free;
meillo@209 227
meillo@209 228 used = ctx->lo & 0x3f;
meillo@209 229
meillo@209 230 ctx->buffer[used++] = 0x80;
meillo@209 231
meillo@209 232 free = 64 - used;
meillo@209 233
meillo@209 234 if (free < 8) {
meillo@209 235 memset(&ctx->buffer[used], 0, free);
meillo@209 236 body(ctx, ctx->buffer, 64);
meillo@209 237 used = 0;
meillo@209 238 free = 64;
meillo@209 239 }
meillo@209 240
meillo@209 241 memset(&ctx->buffer[used], 0, free - 8);
meillo@209 242
meillo@209 243 ctx->lo <<= 3;
meillo@209 244 ctx->buffer[56] = ctx->lo;
meillo@209 245 ctx->buffer[57] = ctx->lo >> 8;
meillo@209 246 ctx->buffer[58] = ctx->lo >> 16;
meillo@209 247 ctx->buffer[59] = ctx->lo >> 24;
meillo@209 248 ctx->buffer[60] = ctx->hi;
meillo@209 249 ctx->buffer[61] = ctx->hi >> 8;
meillo@209 250 ctx->buffer[62] = ctx->hi >> 16;
meillo@209 251 ctx->buffer[63] = ctx->hi >> 24;
meillo@209 252
meillo@209 253 body(ctx, ctx->buffer, 64);
meillo@209 254
meillo@209 255 result[0] = ctx->a;
meillo@209 256 result[1] = ctx->a >> 8;
meillo@209 257 result[2] = ctx->a >> 16;
meillo@209 258 result[3] = ctx->a >> 24;
meillo@209 259 result[4] = ctx->b;
meillo@209 260 result[5] = ctx->b >> 8;
meillo@209 261 result[6] = ctx->b >> 16;
meillo@209 262 result[7] = ctx->b >> 24;
meillo@209 263 result[8] = ctx->c;
meillo@209 264 result[9] = ctx->c >> 8;
meillo@209 265 result[10] = ctx->c >> 16;
meillo@209 266 result[11] = ctx->c >> 24;
meillo@209 267 result[12] = ctx->d;
meillo@209 268 result[13] = ctx->d >> 8;
meillo@209 269 result[14] = ctx->d >> 16;
meillo@209 270 result[15] = ctx->d >> 24;
meillo@209 271
meillo@209 272 memset(ctx, 0, sizeof(*ctx));
meillo@209 273 }
meillo@209 274
meillo@209 275 #endif