/* See LICENSE file for copyright and license details. */ #include "common.h" #ifdef SUPPORT_MD4 #define LETO32(X)\ (((uint32_t)(X)[0] << 0) |\ ((uint32_t)(X)[1] << 8) |\ ((uint32_t)(X)[2] << 16) |\ ((uint32_t)(X)[3] << 24)) 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 uint32_t *x) { #define FGH(A, BCD, I, C, S) (A = rol32(x[I] + A + (BCD) + UINT32_C(C), S)) #define F(A, B, C, D, I, S) FGH(A, (B & C) | (~B & D), I, 0x00000000, S) #define G(A, B, C, D, I, S) FGH(A, (B & C) | (B & D) | (C & D), I, 0x5a827999, S) #define H(A, B, C, D, I, S) FGH(A, B ^ C ^ D, I, 0x6ed9eba1, S) #define FOUR(M, I1, S1, I2, S2, I3, S3, I4, S4)\ (M(a, b, c, d, I1, S1),\ M(d, a, b, c, I2, S2),\ M(c, d, a, b, I3, S3),\ M(b, c, d, a, I4, S4)) #define SIXTEEN(F, S1, S2, S3, S4, I11, I12, I13, I14,\ I21, I22, I23, I24,\ I31, I32, I33, I34,\ I41, I42, I43, I44)\ (FOUR(F, I11, S1, I12, S2, I13, S3, I14, S4),\ FOUR(F, I21, S1, I22, S2, I23, S3, I24, S4),\ FOUR(F, I31, S1, I32, S2, I33, S3, I34, S4),\ FOUR(F, I41, S1, I42, S2, I43, S3, I44, S4)) uint32_t a = h[0]; uint32_t b = h[1]; uint32_t c = h[2]; uint32_t d = h[3]; SIXTEEN(F, 3, 7, 11, 19, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); SIXTEEN(G, 3, 5, 9, 13, 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15); SIXTEEN(H, 3, 9, 11, 15, 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15); 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; size_t i; for (; bytes - off >= 64U; off += 64U) { for (i = 0; i < 16U; i++) this->state.md4.m.m32[i] = LETO32(&m[off + i * 4U]); process_block(this->state.md4.h.h32, this->state.md4.m.m32); } this->state.md4.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.md4.count += bytes; this->state.md4.count *= 8U; this->state.md4.count += (size_t)extra_bits; if (extra_bits) m[bytes] = libhashsum_reverse_byte__(m[bytes]); memset(&m[bytes + 1U], 0, 63U - bytes); mask = (uint8_t)(1U << (7U - extra_bits)); m[bytes] |= mask; m[bytes] &= (uint8_t)~(mask - 1U); /* keep high bits (original value was reversed) */ for (i = 0; i < 14; i++) this->state.md4.m.m32[i] = LETO32(&m[i * 4U]); if (bytes > 55U) { this->state.md4.m.m32[14] = LETO32(&m[14U * 4U]); this->state.md4.m.m32[15] = LETO32(&m[15U * 4U]); process_block(this->state.md4.h.h32, this->state.md4.m.m32); memset(this->state.md4.m.m32, 0, 56U); } this->state.md4.m.m32[14] = (uint32_t)(this->state.md4.count >> 0); this->state.md4.m.m32[15] = (uint32_t)(this->state.md4.count >> 32); process_block(this->state.md4.h.h32, this->state.md4.m.m32); memset(&this->state.md4.m, 0, sizeof(this->state.md4.m)); this->state.md4.count = 0; if (!this->hash_output) this->hash_output = this->state.md4.h.sum; for (i = 0; i < 4U; i++) { hi = this->state.md4.h.h32[i]; this->hash_output[i * 4U + 0U] = (uint8_t)(hi >> 0); this->hash_output[i * 4U + 1U] = (uint8_t)(hi >> 8); this->hash_output[i * 4U + 2U] = (uint8_t)(hi >> 16); this->hash_output[i * 4U + 3U] = (uint8_t)(hi >> 24); } return 0; } LIBHASHSUM_1_NONNULL_ static int finalise_const(struct libhashsum_hasher *this, const void *data, size_t bytes, unsigned extra_bits) { const uint8_t *m = data; size_t r; r = process(this, m, bytes); m = &m[r]; bytes -= r; this->state.md4.m.m8[bytes] = 0; memcpy(this->state.md4.m.m8, m, bytes + (size_t)(extra_bits > 0U)); return finalise_common(this, this->state.md4.m.m8, 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) { this->state.md4.m.m8[bytes] = 0; memcpy(this->state.md4.m.m8, m, bytes + (size_t)(extra_bits > 0U)); m = this->state.md4.m.m8; } return finalise_common(this, m, bytes, extra_bits); } int libhashsum_init_md4_hasher(struct libhashsum_hasher *this) { this->algorithm = LIBHASHSUM_MD4; this->algorithm_string = "MD4"; this->input_block_size = 64U; this->hash_size = sizeof(this->state.md4.h.sum); this->hash_output = NULL; this->supports_non_whole_bytes = 1; this->standard_partial_byte_input_encoding = LIBHASHSUM_MOST_SIGNIFICANT; this->standard_partial_byte_output_encoding = LIBHASHSUM_UNSUPPORTED; this->hash_excess_bits = 0; this->process = &process; this->finalise_const = &finalise_const; this->finalise = &finalise; this->stretch = NULL; this->destroy = NULL; memset(&this->state.md4, 0, sizeof(this->state.md4)); this->state.md4.h.h32[0] = UINT32_C(0x67452301); this->state.md4.h.h32[1] = UINT32_C(0xefcdab89); this->state.md4.h.h32[2] = UINT32_C(0x98badcfe); this->state.md4.h.h32[3] = UINT32_C(0x10325476); return 0; } #else int libhashsum_init_md4_hasher(struct libhashsum_hasher *this) { (void) this; errno = ENOSYS; return -1; } #endif