/*
 * md5 signatures, written from the spec (rfc1321)
 *
 * Written May 21-22, 1998 by orc@pell.chi.il.us (david parsons)
 *
 * This code is released into the public domain.
 */

#include <assert.h>
#include <malloc.h>
#include <string.h>

#define INT32	unsigned long

struct md5buffer {
    INT32 sums[4];

#define a	sums[0]
#define b	sums[1]
#define c	sums[2]
#define d	sums[3]

    unsigned char bytes[64];		/* text we're processing */
    int len;				/* how many bytes we've clocked into the */
					/* bytes[] array */
    long total;				/* how many bytes in this message? */
} ;

typedef struct md5buffer *JH;

#define _IN_MD5LIB
#include "md5lib.h"


/*
 * md5_init() -- the easy part of generating an md5 signature
 */
JH
md5_init()
{
    JH target = (JH)malloc(sizeof *target);

    if (target != 0) {
	target->a = 0x67452301;	/* seed the four accumulators */
	target->b = 0xefcdab89;	/* in intel byte order */
	target->c = 0x98badcfe;
	target->d = 0x10325476;

				/* zero out the buffer */
	memset(target->bytes, 0, sizeof target->bytes);
	target->len = 0;	/* with nothing in it */
	target->total = 0;
    }
    return target;
} /* md5_init */


#include "md5_tarray.h"

/*
 * md5_munch() encodes 512 bits (==64 bytes) into the ongoing md5
 * signature.
 */
static void
md5_munch(JH target)
{
    INT32 aa = target->a,
	  bb = target->b,
	  cc = target->c,
	  dd = target->d;

    INT32 coder[16];
    int ix;

    for (ix = 0; ix < 16; ix++)
	coder[ix] = target->bytes[ix*4] + (target->bytes[1+(ix*4)] << 8)
					+ (target->bytes[2+(ix*4)] << 16)
					+ (target->bytes[3+(ix*4)] << 24);

#define BARREL(val,s)	( (val << s) | (val >> (32-s)) )

    /* gross iteration time: round 1 */
#define F(x,y,z)	((x & y) | (z & ~x))
#define R1(A,B,C,D,k,s,i)	A += F(B,C,D) + coder[k] + T[i-1]; \
				A = B + BARREL(A, s)

    R1(aa,bb,cc,dd,0,7,1);	R1(dd,aa,bb,cc,1,12,2);
    R1(cc,dd,aa,bb,2,17,3);	R1(bb,cc,dd,aa,3,22,4);
    R1(aa,bb,cc,dd,4,7,5);	R1(dd,aa,bb,cc,5,12,6);
    R1(cc,dd,aa,bb,6,17,7);	R1(bb,cc,dd,aa,7,22,8);
    R1(aa,bb,cc,dd,8,7,9);	R1(dd,aa,bb,cc,9,12,10);
    R1(cc,dd,aa,bb,10,17,11);	R1(bb,cc,dd,aa,11,22,12);
    R1(aa,bb,cc,dd,12,7,13);	R1(dd,aa,bb,cc,13,12,14);
    R1(cc,dd,aa,bb,14,17,15);	R1(bb,cc,dd,aa,15,22,16);

    /* round 2 */
#define	G(x,y,z)	((x & z) | (y & ~z))
#define R2(A,B,C,D,k,s,i)	A += G(B,C,D) + coder[k] + T[i-1]; \
				A = B + BARREL(A, s)

    R2(aa,bb,cc,dd,1,5,17);	R2(dd,aa,bb,cc,6,9,18);
    R2(cc,dd,aa,bb,11,14,19);	R2(bb,cc,dd,aa,0,20,20);
    R2(aa,bb,cc,dd,5,5,21);	R2(dd,aa,bb,cc,10,9,22);
    R2(cc,dd,aa,bb,15,14,23);	R2(bb,cc,dd,aa,4,20,24);
    R2(aa,bb,cc,dd,9,5,25);	R2(dd,aa,bb,cc,14,9,26);
    R2(cc,dd,aa,bb,3,14,27);	R2(bb,cc,dd,aa,8,20,28);
    R2(aa,bb,cc,dd,13,5,29);	R2(dd,aa,bb,cc,2,9,30);
    R2(cc,dd,aa,bb,7,14,31);	R2(bb,cc,dd,aa,12,20,32);

     /* Round 3. */
#define	H(x,y,z)	(x ^ y ^ z)
#define R3(a,b,c,d,k,s,t)	a += H(b,c,d) + coder[k] + T[t-1]; \
				a = b + BARREL(a, s)

    R3(aa,bb,cc,dd,5,4,33);	R3(dd,aa,bb,cc,8,11,34);
    R3(cc,dd,aa,bb,11,16,35);	R3(bb,cc,dd,aa,14,23,36);
    R3(aa,bb,cc,dd,1,4,37);	R3(dd,aa,bb,cc,4,11,38);
    R3(cc,dd,aa,bb,7,16,39);	R3(bb,cc,dd,aa,10,23,40);
    R3(aa,bb,cc,dd,13,4,41);	R3(dd,aa,bb,cc,0,11,42);
    R3(cc,dd,aa,bb,3,16,43);	R3(bb,cc,dd,aa,6,23,44);
    R3(aa,bb,cc,dd,9,4,45);	R3(dd,aa,bb,cc,12,11,46);
    R3(cc,dd,aa,bb,15,16,47);	R3(bb,cc,dd,aa,2,23,48);

     /* Round 4. */
#define	I(x,y,z)	(y ^ (x | ~z))
#define R4(a,b,c,d,k,s,t)	a += I(b,c,d) + coder[k] + T[t-1]; \
				a = b + BARREL(a, s)

    R4(aa,bb,cc,dd,0,6,49);	R4(dd,aa,bb,cc,7,10,50);
    R4(cc,dd,aa,bb,14,15,51);	R4(bb,cc,dd,aa,5,21,52);
    R4(aa,bb,cc,dd,12,6,53);	R4(dd,aa,bb,cc,3,10,54);
    R4(cc,dd,aa,bb,10,15,55);	R4(bb,cc,dd,aa,1,21,56);
    R4(aa,bb,cc,dd,8,6,57);	R4(dd,aa,bb,cc,15,10,58);
    R4(cc,dd,aa,bb,6,15,59);	R4(bb,cc,dd,aa,13,21,60);
    R4(aa,bb,cc,dd,4,6,61);	R4(dd,aa,bb,cc,11,10,62);
    R4(cc,dd,aa,bb,2,15,63);	R4(bb,cc,dd,aa,9,21,64);

    target->a += aa;
    target->b += bb;
    target->c += cc;
    target->d += dd;
} /* md5_munch */


/*
 * md5_put() processes bytes of data into an md5 signature
 */
void
md5_put(unsigned char* buf, int len, JH target)
{
    register ix;

    for (ix = 0; ix < len; ix++) {
	/* clock bytes into the buffer nice and slowly, one by one
	 */
	target->bytes[target->len++] = *buf++;

	/* then process away when we've got enough
	 */
	if (target->len >= 64) {
	    md5_munch(target);
	    target->len = 0;
	    memset(target->bytes, 0, sizeof target->bytes);
	}
    }
    target->total += (len * 8);
} /* md5_put */


char *
md5_finish(JH target, unsigned char *sig)
{
    static unsigned char pad[64] = { 0x80 };	/* rest filled with 0x00... */
    static unsigned char signature[16];
    int siz;
    unsigned char total[8];
    int ix;

    if (sig == 0)
	sig = signature;

    /* pad out to the end of this block, then spit out the accumulators. */

    if (target->len != 56) {	/* need to pad out to 56 bytes, so we
				 * can then add the length (8 bytes) in
				 * and end up with 512 bits.
				 */
	if (target->len > 56)
	    siz = (64 - target->len) + 56;
	else
	    siz = 56 - target->len;

	memset(total, 0, 8);
	total[0] = target->total;
	total[1] = (target->total >> 8);
	total[2] = (target->total >> 16);
	total[3] = (target->total >> 24);

	memset(pad+1, 0, (sizeof pad)-1);
	md5_put(pad, siz, target);
	md5_put(total, 8, target);

	assert(target->len == 0);	/* a little bit of paranoia */
    }
    for (ix = 0; ix < 4; ix++) {
	sig[   ix*4 ] = target->sums[ix];
	sig[1+(ix*4)] = target->sums[ix] >> 8;
	sig[2+(ix*4)] = target->sums[ix] >> 16;
	sig[3+(ix*4)] = target->sums[ix] >> 24;
    }
#ifdef CRYPTO_CAN_ROT_YOUR_BRAIN
    memset(target, 0, sizeof *target);
#endif
    free(target);
    return sig;
} /* md5_finish */
