diff --git a/src/include/md4.h b/src/include/md4.h index 4dc26c04..5f43cdba 100644 --- a/src/include/md4.h +++ b/src/include/md4.h @@ -1,56 +1,49 @@ -/* MD4.H - header file for MD4C.C - * $OpenBSD: md4.h,v 1.11 2003/10/07 22:17:27 avsm Exp $ - */ - -/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All - rights reserved. - - License to copy and use this software is granted provided that it - is identified as the "RSA Data Security, Inc. MD4 Message-Digest - Algorithm" in all material mentioning or referencing this software - or this function. - License is also granted to make and use derivative works provided - that such works are identified as "derived from the RSA Data - Security, Inc. MD4 Message-Digest Algorithm" in all material - mentioning or referencing the derived work. - - RSA Data Security, Inc. makes no representations concerning either - the merchantability of this software or the suitability of this - software for any particular purpose. It is provided "as is" - without express or implied warranty of any kind. - - These notices must be retained in any copies of any part of this - documentation and/or software. +/* $OpenBSD: md4.h,v 1.12 2004/04/28 16:54:00 millert Exp $ */ + +/* + * This code implements the MD4 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * Todd C. Miller modified the MD5 code to do MD4 based on RFC 1186. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. */ #ifndef _MD4_H_ #define _MD4_H_ -/* MD4 context. */ +#define MD4_BLOCK_LENGTH 64 +#define MD4_DIGEST_LENGTH 16 +#define MD4_DIGEST_STRING_LENGTH (MD4_DIGEST_LENGTH * 2 + 1) + typedef struct MD4Context { - u_int32_t state[4]; /* state (ABCD) */ - u_int64_t count; /* number of bits, modulo 2^64 */ - unsigned char buffer[64]; /* input buffer */ + u_int32_t state[4]; /* state */ + u_int64_t count; /* number of bits, mod 2^64 */ + u_int8_t buffer[MD4_BLOCK_LENGTH]; /* input buffer */ } MD4_CTX; #include __BEGIN_DECLS -void MD4Init(MD4_CTX *); -void MD4Update(MD4_CTX *, const unsigned char *, size_t) +void MD4Init(MD4_CTX *); +void MD4Update(MD4_CTX *, const u_int8_t *, size_t) __attribute__((__bounded__(__string__,2,3))); -void MD4Final(unsigned char [16], MD4_CTX *) - __attribute__((__bounded__(__minbytes__,1,16))); -void MD4Transform(u_int32_t [4], const unsigned char [64]) +void MD4Final(u_int8_t [MD4_DIGEST_LENGTH], MD4_CTX *) + __attribute__((__bounded__(__minbytes__,1,MD4_DIGEST_LENGTH))); +void MD4Transform(u_int32_t [4], const u_int8_t [MD4_BLOCK_LENGTH]) __attribute__((__bounded__(__minbytes__,1,4))) - __attribute__((__bounded__(__minbytes__,2,64))); -char * MD4End(MD4_CTX *, char *) - __attribute__((__bounded__(__minbytes__,2,33))); -char * MD4File(char *, char *) - __attribute__((__bounded__(__minbytes__,2,33))); -char * MD4Data(const unsigned char *, size_t, char *) + __attribute__((__bounded__(__minbytes__,2,MD4_BLOCK_LENGTH))); +char *MD4End(MD4_CTX *, char [MD4_DIGEST_STRING_LENGTH]) + __attribute__((__bounded__(__minbytes__,2,MD4_DIGEST_STRING_LENGTH))); +char *MD4File(char *, char [MD4_DIGEST_STRING_LENGTH]) + __attribute__((__bounded__(__minbytes__,2,MD4_DIGEST_STRING_LENGTH))); +char *MD4Data(const u_int8_t *, size_t, char [MD4_DIGEST_STRING_LENGTH]) __attribute__((__bounded__(__string__,1,2))) - __attribute__((__bounded__(__minbytes__,3,33))); + __attribute__((__bounded__(__minbytes__,3,MD4_DIGEST_STRING_LENGTH))); __END_DECLS #endif /* _MD4_H_ */ diff --git a/src/lib/libc/hash/md4.c b/src/lib/libc/hash/md4.c new file mode 100644 index 00000000..9b8385dd --- /dev/null +++ b/src/lib/libc/hash/md4.c @@ -0,0 +1,271 @@ +/* $OpenBSD: md4.c,v 1.1 2004/04/28 16:54:00 millert Exp $ */ + +/* + * This code implements the MD4 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * Todd C. Miller modified the MD5 code to do MD4 based on RFC 1186. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD4Context structure, pass it to MD4Init, call MD4Update as + * needed on buffers full of bytes, and then call MD4Final, which + * will fill a supplied 16-byte array with the digest. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$OpenBSD: md4.c,v 1.1 2004/04/28 16:54:00 millert Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include + +#if BYTE_ORDER == LITTLE_ENDIAN + +#define htole32_4(buf) /* Nothing */ +#define htole32_14(buf) /* Nothing */ +#define htole32_16(buf) /* Nothing */ + +#else + +#define htole32_4(buf) do { \ + (buf)[ 0] = htole32((buf)[ 0]); \ + (buf)[ 1] = htole32((buf)[ 1]); \ + (buf)[ 2] = htole32((buf)[ 2]); \ + (buf)[ 3] = htole32((buf)[ 3]); \ +} while (0) + +#define htole32_14(buf) do { \ + (buf)[ 0] = htole32((buf)[ 0]); \ + (buf)[ 1] = htole32((buf)[ 1]); \ + (buf)[ 2] = htole32((buf)[ 2]); \ + (buf)[ 3] = htole32((buf)[ 3]); \ + (buf)[ 4] = htole32((buf)[ 4]); \ + (buf)[ 5] = htole32((buf)[ 5]); \ + (buf)[ 6] = htole32((buf)[ 6]); \ + (buf)[ 7] = htole32((buf)[ 7]); \ + (buf)[ 8] = htole32((buf)[ 8]); \ + (buf)[ 9] = htole32((buf)[ 9]); \ + (buf)[10] = htole32((buf)[10]); \ + (buf)[11] = htole32((buf)[11]); \ + (buf)[12] = htole32((buf)[12]); \ + (buf)[13] = htole32((buf)[13]); \ +} while (0) + +#define htole32_16(buf) do { \ + (buf)[ 0] = htole32((buf)[ 0]); \ + (buf)[ 1] = htole32((buf)[ 1]); \ + (buf)[ 2] = htole32((buf)[ 2]); \ + (buf)[ 3] = htole32((buf)[ 3]); \ + (buf)[ 4] = htole32((buf)[ 4]); \ + (buf)[ 5] = htole32((buf)[ 5]); \ + (buf)[ 6] = htole32((buf)[ 6]); \ + (buf)[ 7] = htole32((buf)[ 7]); \ + (buf)[ 8] = htole32((buf)[ 8]); \ + (buf)[ 9] = htole32((buf)[ 9]); \ + (buf)[10] = htole32((buf)[10]); \ + (buf)[11] = htole32((buf)[11]); \ + (buf)[12] = htole32((buf)[12]); \ + (buf)[13] = htole32((buf)[13]); \ + (buf)[14] = htole32((buf)[14]); \ + (buf)[15] = htole32((buf)[15]); \ +} while (0) + +#endif + +/* + * Start MD4 accumulation. + * Set bit count to 0 and buffer to mysterious initialization constants. + */ +void +MD4Init(MD4_CTX *ctx) +{ + ctx->count = 0; + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xefcdab89; + ctx->state[2] = 0x98badcfe; + ctx->state[3] = 0x10325476; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void +MD4Update(MD4_CTX *ctx, const unsigned char *buf, size_t len) +{ + u_int32_t count; + + /* Bytes already stored in ctx->buffer */ + count = (u_int32_t)((ctx->count >> 3) & 0x3f); + + /* Update bitcount */ + ctx->count += (u_int64_t)len << 3; + + /* Handle any leading odd-sized chunks */ + if (count) { + unsigned char *p = (unsigned char *)ctx->buffer + count; + + count = MD4_BLOCK_LENGTH - count; + if (len < count) { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, count); + htole32_16((u_int32_t *)ctx->buffer); + MD4Transform(ctx->state, ctx->buffer); + buf += count; + len -= count; + } + + /* Process data in MD4_BLOCK_LENGTH-byte chunks */ + while (len >= MD4_BLOCK_LENGTH) { + memcpy(ctx->buffer, buf, MD4_BLOCK_LENGTH); + htole32_16((u_int32_t *)ctx->buffer); + MD4Transform(ctx->state, ctx->buffer); + buf += MD4_BLOCK_LENGTH; + len -= MD4_BLOCK_LENGTH; + } + + /* Handle any remaining bytes of data. */ + memcpy(ctx->buffer, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void +MD4Final(unsigned char digest[MD4_DIGEST_LENGTH], MD4_CTX *ctx) +{ + u_int32_t count; + unsigned char *p; + + /* number of bytes mod 64 */ + count = (u_int32_t)(ctx->count >> 3) & 0x3f; + + /* + * Set the first char of padding to 0x80. + * This is safe since there is always at least one byte free. + */ + p = ctx->buffer + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + htole32_16((u_int32_t *)ctx->buffer); + MD4Transform(ctx->state, ctx->buffer); + + /* Now fill the next block with 56 bytes */ + memset(ctx->buffer, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset(p, 0, count - 8); + } + htole32_14((u_int32_t *)ctx->buffer); + + /* Append bit count and transform */ + ((u_int32_t *)ctx->buffer)[14] = ctx->count & 0xffffffff; + ((u_int32_t *)ctx->buffer)[15] = (u_int32_t)(ctx->count >> 32); + + MD4Transform(ctx->state, ctx->buffer); + htole32_4(ctx->state); + memcpy(digest, ctx->state, MD4_DIGEST_LENGTH); + memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + + +/* The three core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) ((x & y) | (x & z) | (y & z)) +#define F3(x, y, z) (x ^ y ^ z) + +/* This is the central step in the MD4 algorithm. */ +#define MD4STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<>(32-s) ) + +/* + * The core of the MD4 algorithm, this alters an existing MD4 hash to + * reflect the addition of 16 longwords of new data. MD4Update blocks + * the data and converts bytes into longwords for this routine. + */ +void +MD4Transform(u_int32_t buf[4], const unsigned char inc[MD4_BLOCK_LENGTH]) +{ + u_int32_t a, b, c, d; + const u_int32_t *in = (const u_int32_t *)inc; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD4STEP(F1, a, b, c, d, in[ 0], 3); + MD4STEP(F1, d, a, b, c, in[ 1], 7); + MD4STEP(F1, c, d, a, b, in[ 2], 11); + MD4STEP(F1, b, c, d, a, in[ 3], 19); + MD4STEP(F1, a, b, c, d, in[ 4], 3); + MD4STEP(F1, d, a, b, c, in[ 5], 7); + MD4STEP(F1, c, d, a, b, in[ 6], 11); + MD4STEP(F1, b, c, d, a, in[ 7], 19); + MD4STEP(F1, a, b, c, d, in[ 8], 3); + MD4STEP(F1, d, a, b, c, in[ 9], 7); + MD4STEP(F1, c, d, a, b, in[10], 11); + MD4STEP(F1, b, c, d, a, in[11], 19); + MD4STEP(F1, a, b, c, d, in[12], 3); + MD4STEP(F1, d, a, b, c, in[13], 7); + MD4STEP(F1, c, d, a, b, in[14], 11); + MD4STEP(F1, b, c, d, a, in[15], 19); + + MD4STEP(F2, a, b, c, d, in[ 0] + 0x5a827999, 3); + MD4STEP(F2, d, a, b, c, in[ 4] + 0x5a827999, 5); + MD4STEP(F2, c, d, a, b, in[ 8] + 0x5a827999, 9); + MD4STEP(F2, b, c, d, a, in[12] + 0x5a827999, 13); + MD4STEP(F2, a, b, c, d, in[ 1] + 0x5a827999, 3); + MD4STEP(F2, d, a, b, c, in[ 5] + 0x5a827999, 5); + MD4STEP(F2, c, d, a, b, in[ 9] + 0x5a827999, 9); + MD4STEP(F2, b, c, d, a, in[13] + 0x5a827999, 13); + MD4STEP(F2, a, b, c, d, in[ 2] + 0x5a827999, 3); + MD4STEP(F2, d, a, b, c, in[ 6] + 0x5a827999, 5); + MD4STEP(F2, c, d, a, b, in[10] + 0x5a827999, 9); + MD4STEP(F2, b, c, d, a, in[14] + 0x5a827999, 13); + MD4STEP(F2, a, b, c, d, in[ 3] + 0x5a827999, 3); + MD4STEP(F2, d, a, b, c, in[ 7] + 0x5a827999, 5); + MD4STEP(F2, c, d, a, b, in[11] + 0x5a827999, 9); + MD4STEP(F2, b, c, d, a, in[15] + 0x5a827999, 13); + + MD4STEP(F3, a, b, c, d, in[ 0] + 0x6ed9eba1, 3); + MD4STEP(F3, d, a, b, c, in[ 8] + 0x6ed9eba1, 9); + MD4STEP(F3, c, d, a, b, in[ 4] + 0x6ed9eba1, 11); + MD4STEP(F3, b, c, d, a, in[12] + 0x6ed9eba1, 15); + MD4STEP(F3, a, b, c, d, in[ 2] + 0x6ed9eba1, 3); + MD4STEP(F3, d, a, b, c, in[10] + 0x6ed9eba1, 9); + MD4STEP(F3, c, d, a, b, in[ 6] + 0x6ed9eba1, 11); + MD4STEP(F3, b, c, d, a, in[14] + 0x6ed9eba1, 15); + MD4STEP(F3, a, b, c, d, in[ 1] + 0x6ed9eba1, 3); + MD4STEP(F3, d, a, b, c, in[ 9] + 0x6ed9eba1, 9); + MD4STEP(F3, c, d, a, b, in[ 5] + 0x6ed9eba1, 11); + MD4STEP(F3, b, c, d, a, in[13] + 0x6ed9eba1, 15); + MD4STEP(F3, a, b, c, d, in[ 3] + 0x6ed9eba1, 3); + MD4STEP(F3, d, a, b, c, in[11] + 0x6ed9eba1, 9); + MD4STEP(F3, c, d, a, b, in[ 7] + 0x6ed9eba1, 11); + MD4STEP(F3, b, c, d, a, in[15] + 0x6ed9eba1, 15); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +}