diff options
Diffstat (limited to '')
-rw-r--r-- | libhashsum_init_md5_hasher.c | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/libhashsum_init_md5_hasher.c b/libhashsum_init_md5_hasher.c new file mode 100644 index 0000000..4dcd363 --- /dev/null +++ b/libhashsum_init_md5_hasher.c @@ -0,0 +1,204 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +static const uint32_t S[64] = { + 0xd76aa478UL, 0xe8c7b756UL, 0x242070dbUL, 0xc1bdceeeUL, 0xf57c0fafUL, 0x4787c62aUL, 0xa8304613UL, 0xfd469501UL, + 0x698098d8UL, 0x8b44f7afUL, 0xffff5bb1UL, 0x895cd7beUL, 0x6b901122UL, 0xfd987193UL, 0xa679438eUL, 0x49b40821UL, + 0xf61e2562UL, 0xc040b340UL, 0x265e5a51UL, 0xe9b6c7aaUL, 0xd62f105dUL, 0x02441453UL, 0xd8a1e681UL, 0xe7d3fbc8UL, + 0x21e1cde6UL, 0xc33707d6UL, 0xf4d50d87UL, 0x455a14edUL, 0xa9e3e905UL, 0xfcefa3f8UL, 0x676f02d9UL, 0x8d2a4c8aUL, + 0xfffa3942UL, 0x8771f681UL, 0x6d9d6122UL, 0xfde5380cUL, 0xa4beea44UL, 0x4bdecfa9UL, 0xf6bb4b60UL, 0xbebfbc70UL, + 0x289b7ec6UL, 0xeaa127faUL, 0xd4ef3085UL, 0x04881d05UL, 0xd9d4d039UL, 0xe6db99e5UL, 0x1fa27cf8UL, 0xc4ac5665UL, + 0xf4292244UL, 0x432aff97UL, 0xab9423a7UL, 0xfc93a039UL, 0x655b59c3UL, 0x8f0ccc92UL, 0xffeff47dUL, 0x85845dd1UL, + 0x6fa87e4fUL, 0xfe2ce6e0UL, 0xa3014314UL, 0x4e0811a1UL, 0xf7537e82UL, 0xbd3af235UL, 0x2ad7d2bbUL, 0xeb86d391UL +}; + + +static uint32_t rol32(uint32_t n, int k) { return (n << k) | (n >> (32 - k)); } /* k != 0, 32 */ + + +static void +process_block(uint32_t h[4], const uint8_t *x, uint32_t w[16]) +{ +#define F(x, y, z) (z ^ (x & (y ^ z))) +#define G(x, y, z) (y ^ (z & (y ^ x))) +#define H(x, y, z) (x ^ y ^ z) +#define I(x, y, z) (y ^ (x | ~z)) +#define FF(a, b, c, d, w, s, t) (a += F(b, c, d) + w + t, a = rol32(a, s) + b) +#define GG(a, b, c, d, w, s, t) (a += G(b, c, d) + w + t, a = rol32(a, s) + b) +#define HH(a, b, c, d, w, s, t) (a += H(b, c, d) + w + t, a = rol32(a, s) + b) +#define II(a, b, c, d, w, s, t) (a += I(b, c, d) + w + t, a = rol32(a, s) + b) + + register uint32_t a, b, c, d; + unsigned i; + + for (i = 0; i < 16U; i++) { + w[i] = (uint32_t)x[4U * i + 0U] << 0; + w[i] |= (uint32_t)x[4U * i + 1U] << 8; + w[i] |= (uint32_t)x[4U * i + 2U] << 16; + w[i] |= (uint32_t)x[4U * i + 3U] << 24; + } + + a = h[0]; + b = h[1]; + c = h[2]; + d = h[3]; + + i = 0U; + while (i < 16U) { + FF(a, b, c, d, w[i], 7, S[i]), i++; + FF(d, a, b, c, w[i], 12, S[i]), i++; + FF(c, d, a, b, w[i], 17, S[i]), i++; + FF(b, c, d, a, w[i], 22, S[i]), i++; + } + while (i < 32U) { + GG(a, b, c, d, w[(5 * i + 1) % 16], 5, S[i]), i++; + GG(d, a, b, c, w[(5 * i + 1) % 16], 9, S[i]), i++; + GG(c, d, a, b, w[(5 * i + 1) % 16], 14, S[i]), i++; + GG(b, c, d, a, w[(5 * i + 1) % 16], 20, S[i]), i++; + } + while (i < 48U) { + HH(a, b, c, d, w[(3 * i + 5) % 16], 4, S[i]), i++; + HH(d, a, b, c, w[(3 * i + 5) % 16], 11, S[i]), i++; + HH(c, d, a, b, w[(3 * i + 5) % 16], 16, S[i]), i++; + HH(b, c, d, a, w[(3 * i + 5) % 16], 23, S[i]), i++; + } + while (i < 64U) { + II(a, b, c, d, w[7 * i % 16], 6, S[i]), i++; + II(d, a, b, c, w[7 * i % 16], 10, S[i]), i++; + II(c, d, a, b, w[7 * i % 16], 15, S[i]), i++; + II(b, c, d, a, w[7 * i % 16], 21, S[i]), i++; + } + + h[0] += a; + h[1] += b; + h[2] += c; + h[3] += d; +} + + +LIBHASHSUM_1_NONNULL_ +static size_t +process(struct libhashsum_hasher *this, const void *data, size_t bytes) +{ + const uint8_t *m = data; + size_t off = 0; + + for (; bytes - off >= 64U; off += 64U) + process_block(this->state.md5.h.h32, &m[off], this->state.md5.w); + + this->state.md5.count += off; + return off; +} + + +LIBHASHSUM_1_NONNULL_ +static int +finalise_common(struct libhashsum_hasher *this, uint8_t *m, size_t bytes, unsigned extra_bits) +{ + uint8_t mask; + unsigned i; + register uint32_t hi; + + if (extra_bits > 7U) { + errno = EINVAL; + return -1; + } + + this->state.md5.count += bytes; + this->state.md5.count *= 8U; + this->state.md5.count += (size_t)extra_bits; + + mask = (uint8_t)(1U << (7U - extra_bits)); + m[bytes] |= mask; + m[bytes] &= (uint8_t)~(mask - 1U); /* keep high bits */ + bytes++; + + if (bytes > 56U) { + memset(&m[bytes], 0, 64U - bytes); + process_block(this->state.md5.h.h32, m, this->state.md5.w); + bytes = 0; + } + + memset(&m[bytes], 0, 56U - bytes); + m[56] = (uint8_t)(this->state.md5.count >> 0); + m[57] = (uint8_t)(this->state.md5.count >> 8); + m[58] = (uint8_t)(this->state.md5.count >> 16); + m[59] = (uint8_t)(this->state.md5.count >> 24); + m[60] = (uint8_t)(this->state.md5.count >> 32); + m[61] = (uint8_t)(this->state.md5.count >> 40); + m[62] = (uint8_t)(this->state.md5.count >> 48); + m[63] = (uint8_t)(this->state.md5.count >> 56); + process_block(this->state.md5.h.h32, m, this->state.md5.w); + + memset(this->state.md5.m, 0, sizeof(this->state.md5.m)); + memset(this->state.md5.w, 0, sizeof(this->state.md5.w)); + this->state.md5.count = 0; + + for (i = 0; i < 4U; i++) { + hi = this->state.md5.h.h32[i]; + this->state.md5.h.sum[i * 4U + 0U] = (uint8_t)(hi >> 0); + this->state.md5.h.sum[i * 4U + 1U] = (uint8_t)(hi >> 8); + this->state.md5.h.sum[i * 4U + 2U] = (uint8_t)(hi >> 16); + this->state.md5.h.sum[i * 4U + 3U] = (uint8_t)(hi >> 24); + } + + this->hash_output = this->state.md5.h.sum; + return 0; +} + + +LIBHASHSUM_1_NONNULL_ +static int +finalise_const(struct libhashsum_hasher *this, const void *data, unsigned extra_bits, size_t bytes) +{ + const uint8_t *m = data; + size_t r; + + r = process(this, m, bytes); + m = &m[r]; + bytes -= r; + + memcpy(this->state.md5.m, m, bytes + (size_t)(extra_bits > 0U)); + return finalise_common(this, this->state.md5.m, bytes, extra_bits); +} + + +LIBHASHSUM_1_NONNULL_ +static int +finalise(struct libhashsum_hasher *this, void *data, size_t bytes, unsigned extra_bits, size_t size) +{ + uint8_t *m = data; + size_t r; + + r = process(this, m, bytes); + m = &m[r]; + bytes -= r; + size -= r; + + if (size < 64U) { + memcpy(this->state.md5.m, m, bytes + (size_t)(extra_bits > 0U)); + m = this->state.md5.m; + } + return finalise_common(this, m, bytes, extra_bits); +} + + +int +libhashsum_init_md5_hasher(struct libhashsum_hasher *this) +{ + this->algorithm = LIBHASHSUM_MD5; + this->input_block_size = 64U; + this->hash_size = sizeof(this->state.md5.h.sum); + this->hash_output = NULL; + this->supports_non_whole_bytes = 1; + this->process = &process; + this->finalise_const = &finalise_const; + this->finalise = &finalise; + memset(&this->state.md5, 0, sizeof(this->state.md5)); + this->state.md5.h.h32[0] = UINT32_C(0x67452301); + this->state.md5.h.h32[1] = UINT32_C(0xefcdab89); + this->state.md5.h.h32[2] = UINT32_C(0x98badcfe); + this->state.md5.h.h32[3] = UINT32_C(0x10325476); + return 0; +} |