summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd C. Miller <millert@cvs.openbsd.org>2004-04-28 16:54:01 +0000
committerTodd C. Miller <millert@cvs.openbsd.org>2004-04-28 16:54:01 +0000
commit4949c60b1187aec824b55600dc5b69667a866d94 (patch)
tree9415720695c56eea72f200bb1a04485e0728f98c
parent861f7626f7da706f339a901b351e4398597a383d (diff)
PD md4 code derived from Colin Plumb's md5 routines.
-rw-r--r--include/md4.h71
-rw-r--r--lib/libc/hash/md4.c271
2 files changed, 303 insertions, 39 deletions
diff --git a/include/md4.h b/include/md4.h
index 4dc26c04697..5f43cdba2ed 100644
--- a/include/md4.h
+++ b/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 <sys/cdefs.h>
__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/lib/libc/hash/md4.c b/lib/libc/hash/md4.c
new file mode 100644
index 00000000000..9b8385dd566
--- /dev/null
+++ b/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 <sys/types.h>
+#include <string.h>
+#include <md4.h>
+
+#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<<s | 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;
+}