/* See LICENSE file for copyright and license details. */ #include "common.h" #ifdef SUPPORT_MD5 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; if (extra_bits) m[bytes] = libhashsum_reverse_byte__(m[bytes]); mask = (uint8_t)(1U << (7U - extra_bits)); m[bytes] |= mask; m[bytes] &= (uint8_t)~(mask - 1U); /* keep high bits (original value was reversed) */ 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; if (!this->hash_output) this->hash_output = this->state.md5.h.sum; for (i = 0; i < 4U; i++) { hi = this->state.md5.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.md5.m[bytes] = 0; 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->algorithm_string = "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->standard_partial_byte_input_encoding = LIBHASHSUM_MOST_SIGNIFICANT; this->standard_partial_byte_output_encoding = LIBHASHSUM_UNSUPPORTED; this->hash_excess_bits = 0; this->relative_performance = 28263143931935570ULL; this->process = &process; this->finalise_const = &finalise_const; this->finalise = &finalise; this->stretch = NULL; this->destroy = NULL; 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; } #else int libhashsum_init_md5_hasher(struct libhashsum_hasher *this) { (void) this; errno = ENOSYS; return -1; } #endif