| 1 | /* |
| 2 | ** Copyright 1998 - 2000 Double Precision, Inc. |
| 3 | ** See COPYING for distribution information. |
| 4 | */ |
| 5 | |
| 6 | #define MD5_INTERNAL |
| 7 | #include "md5.h" |
| 8 | #include <string.h> |
| 9 | #include <stdlib.h> |
| 10 | |
| 11 | static const char rcsid[]="$Id: md5.c,v 1.7 2000/07/30 01:08:09 mrsam Exp $"; |
| 12 | |
| 13 | #define MD5_BYTE unsigned char |
| 14 | |
| 15 | #define MD5_ROL(w,n) \ |
| 16 | ( (w) << (n) | ( (w) >> (32-(n)) ) ) |
| 17 | |
| 18 | static MD5_WORD T[64]={ |
| 19 | 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, |
| 20 | 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, |
| 21 | 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, |
| 22 | 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, |
| 23 | 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, |
| 24 | 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8, |
| 25 | 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, |
| 26 | 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, |
| 27 | 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, |
| 28 | 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, |
| 29 | 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05, |
| 30 | 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, |
| 31 | 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, |
| 32 | 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, |
| 33 | 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, |
| 34 | 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391}; |
| 35 | |
| 36 | void md5_context_init(struct MD5_CONTEXT *c) |
| 37 | { |
| 38 | if (sizeof(MD5_WORD) != 4) abort(); |
| 39 | |
| 40 | c->A=0x67452301; |
| 41 | c->B=0xefcdab89; |
| 42 | c->C=0x98badcfe; |
| 43 | c->D=0x10325476; |
| 44 | |
| 45 | c->blk_ptr=0; |
| 46 | } |
| 47 | |
| 48 | void md5_context_hash(struct MD5_CONTEXT *c, |
| 49 | const unsigned char blk[MD5_BLOCK_SIZE]) |
| 50 | { |
| 51 | MD5_WORD x[16]; |
| 52 | unsigned i, j; |
| 53 | MD5_WORD A, B, C, D; |
| 54 | MD5_WORD zz; |
| 55 | |
| 56 | for (i=j=0; i<16; i++) |
| 57 | { |
| 58 | MD5_WORD w=(MD5_WORD)blk[j++]; |
| 59 | |
| 60 | w |= (MD5_WORD)blk[j++] << 8; |
| 61 | w |= (MD5_WORD)blk[j++] << 16; |
| 62 | w |= (MD5_WORD)blk[j++] << 24; |
| 63 | x[i]= w; |
| 64 | } |
| 65 | |
| 66 | #define F(X,Y,Z) ( ((X) & (Y)) | ( (~(X)) & (Z))) |
| 67 | #define G(X,Y,Z) ( ((X) & (Z)) | ( (Y) & (~(Z)))) |
| 68 | #define H(X,Y,Z) ( (X) ^ (Y) ^ (Z) ) |
| 69 | #define I(X,Y,Z) ( (Y) ^ ( (X) | (~(Z)))) |
| 70 | |
| 71 | A=c->A; |
| 72 | B=c->B; |
| 73 | C=c->C; |
| 74 | D=c->D; |
| 75 | |
| 76 | #define ROUND1(a,b,c,d,k,s,i) \ |
| 77 | { zz=(a + F(b,c,d) + x[k] + T[i]); a=b+MD5_ROL(zz,s); } |
| 78 | |
| 79 | ROUND1(A,B,C,D,0,7,0); |
| 80 | ROUND1(D,A,B,C,1,12,1); |
| 81 | ROUND1(C,D,A,B,2,17,2); |
| 82 | ROUND1(B,C,D,A,3,22,3); |
| 83 | ROUND1(A,B,C,D,4,7,4); |
| 84 | ROUND1(D,A,B,C,5,12,5); |
| 85 | ROUND1(C,D,A,B,6,17,6); |
| 86 | ROUND1(B,C,D,A,7,22,7); |
| 87 | ROUND1(A,B,C,D,8,7,8); |
| 88 | ROUND1(D,A,B,C,9,12,9); |
| 89 | ROUND1(C,D,A,B,10,17,10); |
| 90 | ROUND1(B,C,D,A,11,22,11); |
| 91 | ROUND1(A,B,C,D,12,7,12); |
| 92 | ROUND1(D,A,B,C,13,12,13); |
| 93 | ROUND1(C,D,A,B,14,17,14); |
| 94 | ROUND1(B,C,D,A,15,22,15); |
| 95 | |
| 96 | #define ROUND2(a,b,c,d,k,s,i) \ |
| 97 | { zz=(a + G(b,c,d) + x[k] + T[i]); a = b + MD5_ROL(zz,s); } |
| 98 | |
| 99 | ROUND2(A,B,C,D,1,5,16); |
| 100 | ROUND2(D,A,B,C,6,9,17); |
| 101 | ROUND2(C,D,A,B,11,14,18); |
| 102 | ROUND2(B,C,D,A,0,20,19); |
| 103 | ROUND2(A,B,C,D,5,5,20); |
| 104 | ROUND2(D,A,B,C,10,9,21); |
| 105 | ROUND2(C,D,A,B,15,14,22); |
| 106 | ROUND2(B,C,D,A,4,20,23); |
| 107 | ROUND2(A,B,C,D,9,5,24); |
| 108 | ROUND2(D,A,B,C,14,9,25); |
| 109 | ROUND2(C,D,A,B,3,14,26); |
| 110 | ROUND2(B,C,D,A,8,20,27); |
| 111 | ROUND2(A,B,C,D,13,5,28); |
| 112 | ROUND2(D,A,B,C,2,9,29); |
| 113 | ROUND2(C,D,A,B,7,14,30); |
| 114 | ROUND2(B,C,D,A,12,20,31); |
| 115 | |
| 116 | #define ROUND3(a,b,c,d,k,s,i) \ |
| 117 | { zz=(a + H(b,c,d) + x[k] + T[i]); a = b + MD5_ROL(zz,s); } |
| 118 | |
| 119 | ROUND3(A,B,C,D,5,4,32); |
| 120 | ROUND3(D,A,B,C,8,11,33); |
| 121 | ROUND3(C,D,A,B,11,16,34); |
| 122 | ROUND3(B,C,D,A,14,23,35); |
| 123 | ROUND3(A,B,C,D,1,4,36); |
| 124 | ROUND3(D,A,B,C,4,11,37); |
| 125 | ROUND3(C,D,A,B,7,16,38); |
| 126 | ROUND3(B,C,D,A,10,23,39); |
| 127 | ROUND3(A,B,C,D,13,4,40); |
| 128 | ROUND3(D,A,B,C,0,11,41); |
| 129 | ROUND3(C,D,A,B,3,16,42); |
| 130 | ROUND3(B,C,D,A,6,23,43); |
| 131 | ROUND3(A,B,C,D,9,4,44); |
| 132 | ROUND3(D,A,B,C,12,11,45); |
| 133 | ROUND3(C,D,A,B,15,16,46); |
| 134 | ROUND3(B,C,D,A,2,23,47); |
| 135 | |
| 136 | #define ROUND4(a,b,c,d,k,s,i) \ |
| 137 | { zz=(a + I(b,c,d) + x[k] + T[i]); a = b + MD5_ROL(zz,s); } |
| 138 | |
| 139 | ROUND4(A,B,C,D,0,6,48); |
| 140 | ROUND4(D,A,B,C,7,10,49); |
| 141 | ROUND4(C,D,A,B,14,15,50); |
| 142 | ROUND4(B,C,D,A,5,21,51); |
| 143 | ROUND4(A,B,C,D,12,6,52); |
| 144 | ROUND4(D,A,B,C,3,10,53); |
| 145 | ROUND4(C,D,A,B,10,15,54); |
| 146 | ROUND4(B,C,D,A,1,21,55); |
| 147 | ROUND4(A,B,C,D,8,6,56); |
| 148 | ROUND4(D,A,B,C,15,10,57); |
| 149 | ROUND4(C,D,A,B,6,15,58); |
| 150 | ROUND4(B,C,D,A,13,21,59); |
| 151 | ROUND4(A,B,C,D,4,6,60); |
| 152 | ROUND4(D,A,B,C,11,10,61); |
| 153 | ROUND4(C,D,A,B,2,15,62); |
| 154 | ROUND4(B,C,D,A,9,21,63); |
| 155 | |
| 156 | c->A += A; |
| 157 | c->B += B; |
| 158 | c->C += C; |
| 159 | c->D += D; |
| 160 | } |
| 161 | |
| 162 | void md5_context_hashstream(struct MD5_CONTEXT *c, const void *p, unsigned l) |
| 163 | { |
| 164 | const unsigned char *cp=(const unsigned char *)p; |
| 165 | unsigned ll; |
| 166 | |
| 167 | while (l) |
| 168 | { |
| 169 | if (c->blk_ptr == 0 && l >= MD5_BLOCK_SIZE) |
| 170 | { |
| 171 | md5_context_hash(c, cp); |
| 172 | cp += MD5_BLOCK_SIZE; |
| 173 | l -= MD5_BLOCK_SIZE; |
| 174 | continue; |
| 175 | } |
| 176 | |
| 177 | ll=l; |
| 178 | if (ll > MD5_BLOCK_SIZE - c->blk_ptr) |
| 179 | ll=MD5_BLOCK_SIZE - c->blk_ptr; |
| 180 | memcpy(c->blk + c->blk_ptr, cp, ll); |
| 181 | c->blk_ptr += ll; |
| 182 | cp += ll; |
| 183 | l -= ll; |
| 184 | if (c->blk_ptr >= MD5_BLOCK_SIZE) |
| 185 | { |
| 186 | md5_context_hash(c, c->blk); |
| 187 | c->blk_ptr=0; |
| 188 | } |
| 189 | } |
| 190 | } |
| 191 | |
| 192 | void md5_context_endstream(struct MD5_CONTEXT *c, unsigned long ll) |
| 193 | { |
| 194 | unsigned char buf[8]; |
| 195 | |
| 196 | static unsigned char zero[MD5_BLOCK_SIZE-8]; |
| 197 | MD5_WORD l; |
| 198 | |
| 199 | buf[0]=0x80; |
| 200 | md5_context_hashstream(c, buf, 1); |
| 201 | while (c->blk_ptr != MD5_BLOCK_SIZE - 8) |
| 202 | { |
| 203 | if (c->blk_ptr > MD5_BLOCK_SIZE - 8) |
| 204 | { |
| 205 | md5_context_hashstream(c, zero, |
| 206 | MD5_BLOCK_SIZE - c->blk_ptr); |
| 207 | continue; |
| 208 | } |
| 209 | md5_context_hashstream(c, zero, |
| 210 | MD5_BLOCK_SIZE - 8 - c->blk_ptr); |
| 211 | } |
| 212 | |
| 213 | l= ll; |
| 214 | |
| 215 | l <<= 3; |
| 216 | |
| 217 | buf[0]=l; |
| 218 | l >>= 8; |
| 219 | buf[1]=l; |
| 220 | l >>= 8; |
| 221 | buf[2]=l; |
| 222 | l >>= 8; |
| 223 | buf[3]=l; |
| 224 | |
| 225 | l= ll; |
| 226 | l >>= 29; |
| 227 | buf[4]=l; |
| 228 | l >>= 8; |
| 229 | buf[5]=l; |
| 230 | l >>= 8; |
| 231 | buf[6]=l; |
| 232 | l >>= 8; |
| 233 | buf[7]=l; |
| 234 | |
| 235 | md5_context_hashstream(c, buf, 8); |
| 236 | } |
| 237 | |
| 238 | void md5_context_digest(struct MD5_CONTEXT *c, MD5_DIGEST d) |
| 239 | { |
| 240 | unsigned char *dp=d; |
| 241 | MD5_WORD w; |
| 242 | |
| 243 | #define PUT(c) (w=(c), *dp++ = w, w >>= 8, *dp++ = w, w >>= 8, *dp++ = w, w >>= 8, *dp++ = w) |
| 244 | |
| 245 | PUT(c->A); |
| 246 | PUT(c->B); |
| 247 | PUT(c->C); |
| 248 | PUT(c->D); |
| 249 | #undef PUT |
| 250 | } |
| 251 | |
| 252 | void md5_context_restore(struct MD5_CONTEXT *c, const MD5_DIGEST d) |
| 253 | { |
| 254 | const unsigned char *dp=(unsigned char *)d+MD5_DIGEST_SIZE; |
| 255 | MD5_WORD w; |
| 256 | |
| 257 | #define GET \ |
| 258 | w=*--dp; w=(w << 8) | *--dp; w=(w << 8) | *--dp; w=(w << 8) | *--dp; |
| 259 | |
| 260 | GET |
| 261 | c->D=w; |
| 262 | GET |
| 263 | c->C=w; |
| 264 | GET |
| 265 | c->B=w; |
| 266 | GET |
| 267 | c->A=w; |
| 268 | c->blk_ptr=0; |
| 269 | } |
| 270 | |
| 271 | void md5_digest(const void *msg, unsigned int len, MD5_DIGEST d) |
| 272 | { |
| 273 | struct MD5_CONTEXT c; |
| 274 | |
| 275 | md5_context_init(&c); |
| 276 | md5_context_hashstream(&c, msg, len); |
| 277 | md5_context_endstream(&c, len); |
| 278 | md5_context_digest(&c, d); |
| 279 | } |