/* This file is in the public domain. */ #include #include "externs.h" #include "md5.h" typedef unsigned long int U32; /* unsigned, 32 bits */ #define LIMIT32(x) (((U32)(x))&(U32)0xffffffff) /* T[i] = floor((1<<32)*abs(sin(i+1))), where sin arg is in radians */ static U32 T[64] = { 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 }; typedef struct state STATE; struct state { U32 A; U32 B; U32 C; U32 D; U32 X[16]; unsigned int xfill; U32 bitlen_l; U32 bitlen_h; } ; /* State blocks as returned by md5_state and accepted by md5_set_state are byte sequences version (1 byte, always 1 for now) length (1 byte, total length of sequence, 22 to 94) xfill (1 byte) length of bitlen sequence (1 byte, 0-8) A, B, C, D, 4 bytes each, little-endian ceil(xfill/4) X[] values, 4 bytes each, little-endian bitlen values, 0-8 bytes, the fewest number necessary to store the 64-bit count (ie, high 0 bytes stripped), little-endian checksum, NOT of XOR of all previous values (1 byte) checksum, sum-ignoring-carries of all previous values not including the NOT-of-XOR checksum byte (1 byte) */ /* Internals. */ #define F(X,Y,Z) (((X)&(Y))|((~(X))&(Z))) #define G(X,Y,Z) (((X)&(Z))|((Y)&(~(Z)))) #define H(X,Y,Z) ((X)^(Y)^(Z)) #define I(X,Y,Z) ((Y)^((X)|(~(Z)))) inline static U32 ROTLEFT(U32 v, unsigned int nbits) { return(LIMIT32(v<>(32-nbits))); } static void crunch_block(STATE *state) { U32 A; U32 B; U32 C; U32 D; U32 *X; A = state->A; B = state->B; C = state->C; D = state->D; X = &state->X[0]; #define OP(a,b,c,d,k,s,i) a = b + ROTLEFT(a+F(b,c,d)+X[k]+T[i-1],s) OP(A,B,C,D, 0, 7, 1);OP(D,A,B,C, 1,12, 2);OP(C,D,A,B, 2,17, 3);OP(B,C,D,A, 3,22, 4); OP(A,B,C,D, 4, 7, 5);OP(D,A,B,C, 5,12, 6);OP(C,D,A,B, 6,17, 7);OP(B,C,D,A, 7,22, 8); OP(A,B,C,D, 8, 7, 9);OP(D,A,B,C, 9,12,10);OP(C,D,A,B,10,17,11);OP(B,C,D,A,11,22,12); OP(A,B,C,D,12, 7,13);OP(D,A,B,C,13,12,14);OP(C,D,A,B,14,17,15);OP(B,C,D,A,15,22,16); #undef OP #define OP(a,b,c,d,k,s,i) a = b + ROTLEFT(a+G(b,c,d)+X[k]+T[i-1],s) OP(A,B,C,D, 1, 5,17);OP(D,A,B,C, 6, 9,18);OP(C,D,A,B,11,14,19);OP(B,C,D,A, 0,20,20); OP(A,B,C,D, 5, 5,21);OP(D,A,B,C,10, 9,22);OP(C,D,A,B,15,14,23);OP(B,C,D,A, 4,20,24); OP(A,B,C,D, 9, 5,25);OP(D,A,B,C,14, 9,26);OP(C,D,A,B, 3,14,27);OP(B,C,D,A, 8,20,28); OP(A,B,C,D,13, 5,29);OP(D,A,B,C, 2, 9,30);OP(C,D,A,B, 7,14,31);OP(B,C,D,A,12,20,32); #undef OP #define OP(a,b,c,d,k,s,i) a = b + ROTLEFT(a+H(b,c,d)+X[k]+T[i-1],s) OP(A,B,C,D, 5, 4,33);OP(D,A,B,C, 8,11,34);OP(C,D,A,B,11,16,35);OP(B,C,D,A,14,23,36); OP(A,B,C,D, 1, 4,37);OP(D,A,B,C, 4,11,38);OP(C,D,A,B, 7,16,39);OP(B,C,D,A,10,23,40); OP(A,B,C,D,13, 4,41);OP(D,A,B,C, 0,11,42);OP(C,D,A,B, 3,16,43);OP(B,C,D,A, 6,23,44); OP(A,B,C,D, 9, 4,45);OP(D,A,B,C,12,11,46);OP(C,D,A,B,15,16,47);OP(B,C,D,A, 2,23,48); #undef OP #define OP(a,b,c,d,k,s,i) a = b + ROTLEFT(a+I(b,c,d)+X[k]+T[i-1],s) OP(A,B,C,D, 0, 6,49);OP(D,A,B,C, 7,10,50);OP(C,D,A,B,14,15,51);OP(B,C,D,A, 5,21,52); OP(A,B,C,D,12, 6,53);OP(D,A,B,C, 3,10,54);OP(C,D,A,B,10,15,55);OP(B,C,D,A, 1,21,56); OP(A,B,C,D, 8, 6,57);OP(D,A,B,C,15,10,58);OP(C,D,A,B, 6,15,59);OP(B,C,D,A,13,21,60); OP(A,B,C,D, 4, 6,61);OP(D,A,B,C,11,10,62);OP(C,D,A,B, 2,15,63);OP(B,C,D,A, 9,21,64); #undef OP state->A += LIMIT32(A); state->B += LIMIT32(B); state->C += LIMIT32(C); state->D += LIMIT32(D); } static void fill_u32s(const unsigned char *buf, U32 *u32s, unsigned int n) { for (;n>0;n--) { *u32s++ = buf[0] | (((U32)buf[1]) << 8) | (((U32)buf[2]) << 16) | (((U32)buf[3]) << 24); buf += 4; } } static void crunch_bytes(STATE *state, const unsigned char *buf, unsigned int nbytes) { unsigned int xfill; U32 *X; xfill = state->xfill; X = &state->X[0]; while (nbytes > 0) { if ((xfill == 0) && (nbytes >= 64)) { fill_u32s(buf,X,64/4); crunch_block(state); buf += 64; nbytes -= 64; } else { if (((xfill % 4) == 0) && (nbytes >= 4)) { unsigned int n; n = 64 - xfill; if (n > nbytes) n = nbytes; n &= ~3; fill_u32s(buf,&X[xfill/4],n/4); buf += n; nbytes -= n; xfill += n; } else { switch (xfill % 4) { case 0: X[xfill/4] = *buf; break; case 1: X[xfill/4] |= ((U32)*buf) << 8; break; case 2: X[xfill/4] |= ((U32)*buf) << 16; break; case 3: X[xfill/4] |= ((U32)*buf) << 24; break; } buf ++; nbytes --; xfill ++; } if (xfill >= 64) { crunch_block(state); xfill = 0; } } } state->xfill = xfill; } /* Interface. */ void *md5_init(void) { STATE *s; s = malloc(sizeof(STATE)); if (s == 0) return(0); s->A = 0x67452301; s->B = 0xefcdab89; s->C = 0x98badcfe; s->D = 0x10325476; s->xfill = 0; s->bitlen_l = 0; s->bitlen_h = 0; return(s); } void md5_process_bytes(void *state, const void *vbuf, unsigned int nbytes) #define s ((STATE *)state) { U32 ltmp; U32 lsum; crunch_bytes(s,vbuf,nbytes); s->bitlen_h += ((U32)nbytes) >> 29; ltmp = ((U32)nbytes) << 3; lsum = ltmp + s->bitlen_l; if ( (ltmp & s->bitlen_l & 0x80000000) || ( ((ltmp|s->bitlen_l) & 0x80000000) && !(lsum & 0x80000000) ) ) { s->bitlen_h ++; } s->bitlen_l = lsum; #undef s } void md5_result(void *state, unsigned char *result) #define s ((STATE *)state) { unsigned char lenbytes[8]; crunch_bytes(s,(const void *)"\200",1); while (s->xfill != 56) crunch_bytes(s,(const void *)"\0",1); lenbytes[0] = s->bitlen_l & 0xff; lenbytes[1] = (s->bitlen_l >> 8) & 0xff; lenbytes[2] = (s->bitlen_l >> 16) & 0xff; lenbytes[3] = (s->bitlen_l >> 24) & 0xff; lenbytes[4] = s->bitlen_h & 0xff; lenbytes[5] = (s->bitlen_h >> 8) & 0xff; lenbytes[6] = (s->bitlen_h >> 16) & 0xff; lenbytes[7] = (s->bitlen_h >> 24) & 0xff; crunch_bytes(s,&lenbytes[0],8); result[ 0] = s->A & 0xff; result[ 1] = (s->A >> 8) & 0xff; result[ 2] = (s->A >> 16) & 0xff; result[ 3] = (s->A >> 24) & 0xff; result[ 4] = s->B & 0xff; result[ 5] = (s->B >> 8) & 0xff; result[ 6] = (s->B >> 16) & 0xff; result[ 7] = (s->B >> 24) & 0xff; result[ 8] = s->C & 0xff; result[ 9] = (s->C >> 8) & 0xff; result[10] = (s->C >> 16) & 0xff; result[11] = (s->C >> 24) & 0xff; result[12] = s->D & 0xff; result[13] = (s->D >> 8) & 0xff; result[14] = (s->D >> 16) & 0xff; result[15] = (s->D >> 24) & 0xff; free(s); #undef s } void *md5_clone(const void *state) #define s ((const STATE *)state) { STATE *s2; s2 = malloc(sizeof(STATE)); if (s2 == 0) return(0); *s2 = *s; return(s2); #undef s } int md5_state(const void *state, void *buf, int buflen) #define s ((const STATE *)state) { int want; int blen; int i; unsigned char *bp; unsigned char ck_xor; unsigned char ck_sum; void sb(unsigned char b) { *bp++ = b; ck_xor ^= b; ck_sum += b; } void sb4(U32 v) { sb( v &0xff); sb((v>> 8)&0xff); sb((v>>16)&0xff); sb((v>>24)&0xff); } want = 1 + 1 + 1 + 1 + ((4 + ((s->xfill+3)/4)) * 4); if (s->bitlen_h >> 24) blen = 8; else if (s->bitlen_h >> 16) blen = 7; else if (s->bitlen_h >> 8) blen = 6; else if (s->bitlen_h ) blen = 5; else if (s->bitlen_l >> 24) blen = 4; else if (s->bitlen_l >> 16) blen = 3; else if (s->bitlen_l >> 8) blen = 2; else if (s->bitlen_l ) blen = 1; else blen = 0; want += blen + 1 + 1; if (want > buflen) return(want); bp = buf; ck_xor = 0xff; ck_sum = 0; sb(1); sb(want); sb(s->xfill); sb(blen); sb4(s->A); sb4(s->B); sb4(s->C); sb4(s->D); for (i=0;ixfill;i+=4) sb4(s->X[i>>2]); if (blen > 0) sb( s->bitlen_l &0xff); if (blen > 1) sb((s->bitlen_l>> 8)&0xff); if (blen > 2) sb((s->bitlen_l>>16)&0xff); if (blen > 3) sb((s->bitlen_l>>24)&0xff); if (blen > 4) sb( s->bitlen_h &0xff); if (blen > 5) sb((s->bitlen_h>> 8)&0xff); if (blen > 6) sb((s->bitlen_h>>16)&0xff); if (blen > 7) sb((s->bitlen_h>>24)&0xff); i = ck_sum; sb(0xff&ck_xor); sb(0xff&i); return(want); #undef s } int md5_set_state(void *state, const void *buf, int buflen) #define s ((STATE *)state) { const unsigned char *bp; int l; int xfill; int blen; int i; unsigned char ck_xor; unsigned char ck_sum; U32 get4(void) { bp += 4; return( (((U32)bp[-1]) << 24) | (((U32)bp[-2]) << 16) | (((U32)bp[-3]) << 8) | ((U32)bp[-4]) ); } if (buflen < 1) return(MD5_CORRUPT); bp = buf; if (*bp++ != 1) return(MD5_BADVERS); if (buflen < 4+16+2) return(MD5_CORRUPT); l = *bp++; if (l > buflen) return(MD5_CORRUPT); xfill = *bp++; if ((xfill < 0) || (xfill > 63)) return(MD5_CORRUPT); blen = *bp++; if ((blen < 0) || (blen > 8)) return(MD5_CORRUPT); if (l != 1+1+1+1+((4+((xfill+3)/4))*4)+blen+1+1) return(MD5_CORRUPT); ck_xor = 0xff; ck_sum = 0; for (i=l-3;i>=0;i--) { ck_xor ^= ((const unsigned char *)buf)[i]; ck_sum += ((const unsigned char *)buf)[i]; } if (((const unsigned char *)buf)[l-2] != (0xff&ck_xor)) return(MD5_CORRUPT); if (((const unsigned char *)buf)[l-1] != (0xff&ck_sum)) return(MD5_CORRUPT); s->xfill = xfill; s->A = get4(); s->B = get4(); s->C = get4(); s->D = get4(); for (i=0;iX[i>>2] = get4(); switch (blen) { case 0: s->bitlen_l = 0; s->bitlen_h = 0; break; case 1: s->bitlen_l = bp[0]; s->bitlen_h = 0; break; case 2: s->bitlen_l = bp[0] | (((U32)bp[1]) << 8); s->bitlen_h = 0; break; case 3: s->bitlen_l = bp[0] | (((U32)bp[1]) << 8) | (((U32)bp[2]) << 16); s->bitlen_h = 0; break; case 4: s->bitlen_h = 0; if (0) { case 5: s->bitlen_h = bp[4]; } if (0) { case 6: s->bitlen_h = bp[4] | (((U32)bp[5]) << 8); } if (0) { case 7: s->bitlen_h = bp[4] | (((U32)bp[5]) << 8) | (((U32)bp[6]) << 16); } if (0) { case 8: s->bitlen_h = bp[4] | (((U32)bp[5]) << 8) | (((U32)bp[6]) << 16) | (((U32)bp[7]) << 24); } s->bitlen_l = bp[0] | (((U32)bp[1]) << 8) | (((U32)bp[2]) << 16) | (((U32)bp[3]) << 24); break; } /* bp += blen; -- don't bother; it's not used further */ return(0); #undef s } void md5_drop(void *state) { free((STATE *)state); }