yquake2remaster/src/common/md4.c
2012-04-30 08:25:59 +02:00

209 lines
4.1 KiB
C

/*
* Public Domain C source implementation of RFC 1320
* - The MD4 Message-Digest Algorithm -
*
* http://www.faqs.org/rfcs/rfc1320.html
* by Steven Fuller
*/
#include <inttypes.h>
#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;
}