diff --git a/include/md5_internal.h b/include/md5_internal.h new file mode 100644 index 0000000..95b2402 --- /dev/null +++ b/include/md5_internal.h @@ -0,0 +1,8 @@ +#ifndef MD5_INTERNAL_H +#define MD5_INTERNAL_H + +#include "md5.h" + +void md5_compress(struct md5_ctx *ctx, const uint8_t block[64]); + +#endif diff --git a/src/Makefile.am b/src/Makefile.am index c2a7e07..ca5ff1c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,6 +3,7 @@ lib_LTLIBRARIES = libft_ssl.la libft_ssl_la_SOURCES = libft_ssl.c \ md5/md5.c \ md5/md5_init.c \ + md5/md5_compress.c \ md5/md5_update.c \ md5/md5_final.c \ sha256/sha256_init.c \ diff --git a/src/md5/md5_compress.c b/src/md5/md5_compress.c new file mode 100644 index 0000000..921ee9b --- /dev/null +++ b/src/md5/md5_compress.c @@ -0,0 +1,124 @@ +#include "md5_internal.h" +#include + +/* Forward declrations */ +typedef uint32_t (*md5_round_fn)(uint32_t, uint32_t, uint32_t); +typedef uint32_t (*md5_k_fn)(uint8_t); + +static uint32_t md5_f(uint32_t b, uint32_t c, uint32_t d); +static uint32_t md5_g(uint32_t b, uint32_t c, uint32_t d); +static uint32_t md5_h(uint32_t b, uint32_t c, uint32_t d); +static uint32_t md5_i(uint32_t b, uint32_t c, uint32_t d); +static uint32_t md5_k0(uint8_t i); +static uint32_t md5_k1(uint8_t i); +static uint32_t md5_k2(uint8_t i); +static uint32_t md5_k3(uint8_t i); +static uint32_t md5_leftrotate(uint32_t x, uint32_t n); +static void md5_decode(const uint8_t block[64], uint32_t m[16]); +/* ------------------- */ + +static const md5_round_fn round_fns[4] = { md5_f, md5_g, md5_h, md5_i }; +static const md5_k_fn round_k[4] = { md5_k0, md5_k1, md5_k2, md5_k3 }; + +void +md5_compress(struct md5_ctx *ctx, const uint8_t block[64]) +{ + uint32_t m[16]; + uint32_t a, b, c, d; + uint32_t temp; + + md5_decode(block, m); + + a = ctx->state[0]; + b = ctx->state[1]; + c = ctx->state[2]; + d = ctx->state[3]; + + for (uint8_t i = 0; i < 64; ++i) + { + const uint8_t idx = (i / 16) & 3; + const uint32_t k = round_k[idx](i); + + temp = a + round_fns[idx](b, c, d) + m[k] + g_md5_T[i]; + temp = md5_leftrotate(temp, g_md5_s[i]) + b; + a = d; d = c; c = b; b = temp; + } + + ctx->state[0] += a; + ctx->state[1] += b; + ctx->state[2] += c; + ctx->state[3] += d; +} + + +/* Decode 64 bytes into 16 x uint32_t words (little-endian) */ +static void +md5_decode(const uint8_t block[64], uint32_t m[16]) +{ + for (uint8_t i = 0; i < 16; ++i) + { + const uint8_t i4 = i * 4; + + m[i] = (uint32_t)block[i4 + 0] << 0 + | (uint32_t)block[i4 + 1] << 8 + | (uint32_t)block[i4 + 2] << 16 + | (uint32_t)block[i4 + 3] << 24; + } +} + +/* Round functions */ +static uint32_t +md5_f(uint32_t b, uint32_t c, uint32_t d) +{ + return (b & c) | (~b & d); +} + +static uint32_t +md5_g(uint32_t b, uint32_t c, uint32_t d) +{ + return (b & d) | (c & ~d); +} + +static uint32_t +md5_h(uint32_t b, uint32_t c, uint32_t d) +{ + return b ^ c ^ d; +} + +static uint32_t +md5_i(uint32_t b, uint32_t c, uint32_t d) +{ + return c ^ (b | ~d); +} + +/* k selectors */ +static uint32_t +md5_k0(uint8_t i) +{ + return (uint32_t)i; +} + +static uint32_t +md5_k1(uint8_t i) +{ + return (uint32_t)((1 + 5 * i) & 15); +} + +static uint32_t +md5_k2(uint8_t i) +{ + return (uint32_t)((5 + 3 * i) & 15); +} + +static uint32_t +md5_k3(uint8_t i) +{ + return (uint32_t)((7 * i) & 15); +} + + +static uint32_t +md5_leftrotate(uint32_t x, uint32_t n) +{ + return (x << n) | (x >> (32u - n)); +} diff --git a/src/md5/md5_final.c b/src/md5/md5_final.c index fc2f898..21c359f 100644 --- a/src/md5/md5_final.c +++ b/src/md5/md5_final.c @@ -1,6 +1,56 @@ -#include "compiler.h" -#include "md5.h" +#include "md5_internal.h" +#include -void md5_final(__unused void *ctx, __unused uint8_t *out) +/* Forward declarations */ +static void md5_pad(struct md5_ctx *ctx); +static inline void md5_write_len(struct md5_ctx *ctx, uint64_t bitlen); +static void md5_encode(const struct md5_ctx *ctx, uint8_t out[16]); +/* ---------------- */ + +void md5_final(void *ctx, uint8_t *out) { + struct md5_ctx *local_ctx = ctx; + + md5_pad(local_ctx); + md5_encode(local_ctx, out); +} + +static void +md5_pad(struct md5_ctx *ctx) +{ + uint64_t bitlen = ctx->count * 8; + + ctx->buf[ctx->count++ & 63] = 0x80; + if ((ctx->count & 63) > 56) + { + while ((ctx->count & 63) != 0) + ctx->buf[ctx->count++ & 63] = 0x00; + md5_compress(ctx, ctx->buf); + } + while ((ctx->count & 63) < 56) + ctx->buf[ctx->count++ & 63] = 0x00; + md5_write_len(ctx, bitlen); + md5_compress(ctx, ctx->buf); +} + +static inline void +md5_write_len(struct md5_ctx *ctx, uint64_t bitlen) +{ + for (uint8_t i = 0; i < 8; ++i) + ctx->buf[56 + i] = (uint8_t)(bitlen >> (8 * i)); +} + +static void +md5_encode(const struct md5_ctx *ctx, uint8_t out[16]) +{ + for (uint8_t i = 0; i < 4; ++i) + { + const uint8_t i4 = i * 4; + uint32_t v = ctx->state[i]; + + out[i4 + 0] = (uint8_t)(v >> 0); + out[i4 + 1] = (uint8_t)(v >> 8); + out[i4 + 2] = (uint8_t)(v >> 16); + out[i4 + 3] = (uint8_t)(v >> 24); + } } diff --git a/src/md5/md5_init.c b/src/md5/md5_init.c index 833dedf..c7ad15f 100644 --- a/src/md5/md5_init.c +++ b/src/md5/md5_init.c @@ -1,6 +1,13 @@ -#include "compiler.h" #include "md5.h" -void md5_init(__unused void *ctx) +void md5_init(void *ctx) { + struct md5_ctx *local_ctx = ctx; + + local_ctx->state[0] = 0x67452301; + local_ctx->state[1] = 0xEFCDAB89; + local_ctx->state[2] = 0x98BADCFE; + local_ctx->state[3] = 0x10325476; + + local_ctx->count = 0; } diff --git a/src/md5/md5_update.c b/src/md5/md5_update.c index e2914f2..d619798 100644 --- a/src/md5/md5_update.c +++ b/src/md5/md5_update.c @@ -1,7 +1,19 @@ -#include "compiler.h" #include "md5.h" +#include "md5_internal.h" +#include +#include -void md5_update(__unused void *ctx, __unused const uint8_t *data, - __unused size_t len) +void md5_update(void *ctx, const uint8_t *data, size_t len) { + struct md5_ctx *local_ctx = ctx; + + + for (size_t i = 0; i < len; ++i) + { + local_ctx->buf[(local_ctx->count & 63)] = data[i]; + ++local_ctx->count; + if (0 == (local_ctx->count & 63)) + md5_compress(local_ctx, local_ctx->buf); + } + }