summaryrefslogtreecommitdiffstats
path: root/src/lib/md4.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/md4.c')
-rw-r--r--src/lib/md4.c310
1 files changed, 310 insertions, 0 deletions
diff --git a/src/lib/md4.c b/src/lib/md4.c
new file mode 100644
index 0000000..7169000
--- /dev/null
+++ b/src/lib/md4.c
@@ -0,0 +1,310 @@
+/**
+ * $Id$
+ *
+ * @note license is LGPL, but largely derived from a public domain source.
+ *
+ * @file md4.c
+ * @brief md4 digest functions.
+ */
+
+RCSID("$Id$")
+
+/*
+ * FORCE MD4 TO USE OUR MD4 HEADER FILE!
+ * If we don't do this, it might pick up the systems broken MD4.
+ */
+#include <freeradius-devel/md4.h>
+
+/** Calculate the MD4 hash of the contents of a buffer
+ *
+ * @param[out] out Where to write the MD4 digest. Must be a minimum of MD4_DIGEST_LENGTH.
+ * @param[in] in Data to hash.
+ * @param[in] inlen Length of the data.
+ */
+void fr_md4_calc(uint8_t out[MD4_DIGEST_LENGTH], uint8_t const *in, size_t inlen)
+{
+ FR_MD4_CTX ctx;
+
+ fr_md4_init(&ctx);
+ fr_md4_update(&ctx, in, inlen);
+ fr_md4_final(out, &ctx);
+ fr_md4_destroy(&ctx);
+}
+
+#ifndef HAVE_OPENSSL_MD4_H
+/*
+ * 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 fr_md4_init, call fr_md4_update as
+ * needed on buffers full of bytes, and then call fr_md4_final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+#ifdef FR_LITTLE_ENDIAN
+# define htole32_4(buf) /* Nothing */
+# define htole32_14(buf) /* Nothing */
+# define htole32_16(buf) /* Nothing */
+#else
+/* Sometimes defined by endian.h */
+# ifndef htole32
+# define htole32(x)\
+ (((((uint32_t)x) & 0xff000000) >> 24) |\
+ ((((uint32_t)x) & 0x00ff0000) >> 8) |\
+ ((((uint32_t)x) & 0x0000ff00) << 8) |\
+ ((((uint32_t)x) & 0x000000ff) << 24))
+# endif
+# 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
+
+/** Initialise a new MD4 context
+ *
+ * Set bit count to 0 and buffer to mysterious initialization constants.
+ *
+ * @param[out] ctx to initialise.
+ */
+void fr_md4_init(FR_MD4_CTX *ctx)
+{
+ ctx->count[0] = 0;
+ ctx->count[1] = 0;
+ ctx->state[0] = 0x67452301;
+ ctx->state[1] = 0xefcdab89;
+ ctx->state[2] = 0x98badcfe;
+ ctx->state[3] = 0x10325476;
+}
+
+/** Feed additional data into the MD4 hashing function
+ *
+ * @param[in,out] ctx to update.
+ * @param[in] in Data to hash.
+ * @param[in] inlen Length of the data.
+ */
+void fr_md4_update(FR_MD4_CTX *ctx, uint8_t const *in, size_t inlen)
+{
+ uint32_t count;
+
+ /* Bytes already stored in ctx->buffer */
+ count = (uint32_t)((ctx->count[0] >> 3) & 0x3f);
+
+ /* Update bitcount */
+/* ctx->count += (uint64_t)inlen << 3;*/
+ if ((ctx->count[0] += ((uint32_t)inlen << 3)) < (uint32_t)inlen) {
+ /* Overflowed ctx->count[0] */
+ ctx->count[1]++;
+ }
+ ctx->count[1] += ((uint32_t)inlen >> 29);
+
+ /* Handle any leading odd-sized chunks */
+ if (count) {
+ unsigned char *p = (unsigned char *)ctx->buffer + count;
+
+ count = MD4_BLOCK_LENGTH - count;
+ if (inlen < count) {
+ memcpy(p, in, inlen);
+ return;
+ }
+ memcpy(p, in, count);
+ htole32_16((uint32_t *)ctx->buffer);
+ fr_md4_transform(ctx->state, ctx->buffer);
+ in += count;
+ inlen -= count;
+ }
+
+ /* Process data in MD4_BLOCK_LENGTH-byte chunks */
+ while (inlen >= MD4_BLOCK_LENGTH) {
+ memcpy(ctx->buffer, in, MD4_BLOCK_LENGTH);
+ htole32_16((uint32_t *)ctx->buffer);
+ fr_md4_transform(ctx->state, ctx->buffer);
+ in += MD4_BLOCK_LENGTH;
+ inlen -= MD4_BLOCK_LENGTH;
+ }
+
+ /* Handle any remaining bytes of data. */
+ memcpy(ctx->buffer, in, inlen);
+}
+
+/** Finalise the MD4 context and write out the hash
+ *
+ * Final wrapup - pad to 64-byte boundary with the bit pattern 1 0*
+ * (64-bit count of bits processed, MSB-first).
+ *
+ * @param[out] out Where to write the MD4 digest. Minimum length of MD4_DIGEST_LENGTH.
+ * @param[in,out] ctx to finalise.
+ */
+void fr_md4_final(uint8_t out[MD4_DIGEST_LENGTH], FR_MD4_CTX *ctx)
+{
+ uint32_t count;
+ unsigned char *p;
+
+ /* number of bytes mod 64 */
+ count = (uint32_t)(ctx->count[0] >> 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((uint32_t *)ctx->buffer);
+ fr_md4_transform(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((uint32_t *)ctx->buffer);
+
+ /* Append bit count and transform */
+ ((uint32_t *)ctx->buffer)[14] = ctx->count[0];
+ ((uint32_t *)ctx->buffer)[15] = ctx->count[1];
+
+ fr_md4_transform(ctx->state, ctx->buffer);
+ htole32_4(ctx->state);
+ memcpy(out, 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) (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. fr_md4_update blocks the data and converts bytes
+ * into longwords for this routine.
+ *
+ * @param[in] state 16 bytes of data to feed into the hashing function.
+ * @param[in,out] block MD4 digest block to update.
+ */
+void fr_md4_transform(uint32_t state[4], uint8_t const block[MD4_BLOCK_LENGTH])
+{
+ uint32_t a, b, c, d;
+ uint32_t const *in = (uint32_t const *)block;
+
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[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);
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+}
+#endif