aboutsummaryrefslogblamecommitdiffstats
path: root/libhashsum_init_md5_hasher.c
blob: dd74ebb9df505730d3963f7cd3379b0fd971ae10 (plain) (tree)
1
2
3

                                                         
                  












































































































                                                                                                                       

                                                               

                                                  
                                                                                             






















                                                                           


                                                          

                                              



                                                                     

         





                     
                                                                                                   







                                    
                                     




























                                                                                                    
                                       



                                                        

                                                                                 
                                   
                                                          


                                               
                             
                             






                                                             










                                                          
/* 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