/* * Public Domain C source implementation of RFC 1320 * - The MD4 Message-Digest Algorithm - * * http://www.faqs.org/rfcs/rfc1320.html * by Steven Fuller */ #include #define ROTATELEFT32(x, s) (((x)<<(s))|((x)>>(32-(s)))) #define F(X, Y, Z) (((X)&(Y)) | ((~X)&(Z))) #define G(X, Y, Z) (((X)&(Y)) | ((X)&(Z)) | ((Y)&(Z))) #define H(X, Y, Z) ((X) ^ (Y) ^ (Z)) #define S(a, b, c, d, k, s) { \ a += (F((b), (c), (d)) + X[(k)]); \ a = ROTATELEFT32(a, s); \ } #define T(a, b, c, d, k, s) { \ a += (G((b), (c), (d)) + X[(k)] + 0x5A827999); \ a = ROTATELEFT32(a, s); \ } #define U(a, b, c, d, k, s) { \ a += (H((b), (c), (d)) + X[(k)] + 0x6ED9EBA1); \ a = ROTATELEFT32(a, s); \ } static uint32_t X[16]; static uint32_t A, AA; static uint32_t B, BB; static uint32_t C, CC; static uint32_t D, DD; static void DoMD4() { AA = A; BB = B; CC = C; DD = D; S(A, B, C, D, 0, 3); S(D, A, B, C, 1, 7); S(C, D, A, B, 2, 11); S(B, C, D, A, 3, 19); S(A, B, C, D, 4, 3); S(D, A, B, C, 5, 7); S(C, D, A, B, 6, 11); S(B, C, D, A, 7, 19); S(A, B, C, D, 8, 3); S(D, A, B, C, 9, 7); S(C, D, A, B, 10, 11); S(B, C, D, A, 11, 19); S(A, B, C, D, 12, 3); S(D, A, B, C, 13, 7); S(C, D, A, B, 14, 11); S(B, C, D, A, 15, 19); T(A, B, C, D, 0, 3); T(D, A, B, C, 4, 5); T(C, D, A, B, 8, 9); T(B, C, D, A, 12, 13); T(A, B, C, D, 1, 3); T(D, A, B, C, 5, 5); T(C, D, A, B, 9, 9); T(B, C, D, A, 13, 13); T(A, B, C, D, 2, 3); T(D, A, B, C, 6, 5); T(C, D, A, B, 10, 9); T(B, C, D, A, 14, 13); T(A, B, C, D, 3, 3); T(D, A, B, C, 7, 5); T(C, D, A, B, 11, 9); T(B, C, D, A, 15, 13); U(A, B, C, D, 0, 3); U(D, A, B, C, 8, 9); U(C, D, A, B, 4, 11); U(B, C, D, A, 12, 15); U(A, B, C, D, 2, 3); U(D, A, B, C, 10, 9); U(C, D, A, B, 6, 11); U(B, C, D, A, 14, 15); U(A, B, C, D, 1, 3); U(D, A, B, C, 9, 9); U(C, D, A, B, 5, 11); U(B, C, D, A, 13, 15); U(A, B, C, D, 3, 3); U(D, A, B, C, 11, 9); U(C, D, A, B, 7, 11); U(B, C, D, A, 15, 15); A += AA; B += BB; C += CC; D += DD; } static void PerformMD4(const unsigned char *buf, int length, unsigned char *digest) { int len = length / 64; /* number of full blocks */ int rem = length % 64; /* number of left over bytes */ int i, j; const unsigned char *ptr = buf; /* initialize the MD buffer */ A = 0x67452301; B = 0xEFCDAB89; C = 0x98BADCFE; D = 0x10325476; for (i = 0; i < len; i++) { for (j = 0; j < 16; j++) { X[j] = ((ptr[0]<< 0)|(ptr[1]<< 8)| (ptr[2]<<16)|(ptr[3]<<24)); ptr += 4; } DoMD4(); } i = rem / 4; for (j = 0; j < i; j++) { X[j] = ((ptr[0]<< 0)|(ptr[1]<< 8)| (ptr[2]<<16)|(ptr[3]<<24)); ptr += 4; } switch(rem % 4) { case 0: X[j] = 0x80U; break; case 1: X[j] = ((ptr[0]<< 0)|((0x80U)<< 8)); break; case 2: X[j] = ((ptr[0]<< 0)|(ptr[1]<< 8)|((0x80U)<<16)); break; case 3: X[j] = ((ptr[0]<< 0)|(ptr[1]<< 8)|(ptr[2]<<16)|((0x80U)<<24)); break; } j++; if (j > 14) { for (; j < 16; j++) X[j] = 0; DoMD4(); j = 0; } for (; j < 14; j++) X[j] = 0; X[14] = (length & 0x1FFFFFFF) << 3; X[15] = (length & ~0x1FFFFFFF) >> 29; DoMD4(); digest[ 0] = (A & 0x000000FF) >> 0; digest[ 1] = (A & 0x0000FF00) >> 8; digest[ 2] = (A & 0x00FF0000) >> 16; digest[ 3] = (A & 0xFF000000) >> 24; digest[ 4] = (B & 0x000000FF) >> 0; digest[ 5] = (B & 0x0000FF00) >> 8; digest[ 6] = (B & 0x00FF0000) >> 16; digest[ 7] = (B & 0xFF000000) >> 24; digest[ 8] = (C & 0x000000FF) >> 0; digest[ 9] = (C & 0x0000FF00) >> 8; digest[10] = (C & 0x00FF0000) >> 16; digest[11] = (C & 0xFF000000) >> 24; digest[12] = (D & 0x000000FF) >> 0; digest[13] = (D & 0x0000FF00) >> 8; digest[14] = (D & 0x00FF0000) >> 16; digest[15] = (D & 0xFF000000) >> 24; A = AA = 0; B = BB = 0; C = CC = 0; D = DD = 0; for (j = 0; j < 16; j++) X[j] = 0; } unsigned Com_BlockChecksum (void *buffer, int length) { uint32_t digest[4]; unsigned val; PerformMD4((unsigned char *)buffer, length, (unsigned char *)digest); val = digest[0] ^ digest[1] ^ digest[2] ^ digest[3]; return val; }