summaryrefslogtreecommitdiffstats
path: root/md5.cc
diff options
context:
space:
mode:
Diffstat (limited to 'md5.cc')
-rw-r--r--md5.cc206
1 files changed, 206 insertions, 0 deletions
diff --git a/md5.cc b/md5.cc
new file mode 100644
index 0000000..7ed3e5b
--- /dev/null
+++ b/md5.cc
@@ -0,0 +1,206 @@
+/* Functions to compute MD5 message digest of memory blocks according to the
+ definition of MD5 in RFC 1321 from April 1992.
+ Copyright (C) 2020, 2021 Antonio Diaz Diaz.
+
+ This library is free software. Redistribution and use in source and
+ binary forms, with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions, and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions, and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+*/
+
+#define _FILE_OFFSET_BITS 64
+
+#include <cstring>
+#include <stdint.h>
+
+#include "md5.h"
+
+
+namespace {
+
+/* These are the four functions used in the four steps of the MD5 algorithm
+ as defined in RFC 1321. */
+#define F(x, y, z) ((x & y) | (~x & z))
+#define G(x, y, z) ((x & z) | (y & ~z))
+#define H(x, y, z) (x ^ y ^ z)
+#define I(x, y, z) (y ^ (x | ~z))
+
+/* Rotate x left n bits.
+ It is unfortunate that C++ does not provide an operator for rotation.
+ Hope the compiler is smart enough. */
+#define ROTATE_LEFT(x, n) (x = (x << n) | (x >> (32 - n)))
+
+// FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+#define FF(a, b, c, d, x, s, ac) \
+ { a += F(b, c, d) + x + ac; ROTATE_LEFT(a, s); a += b; }
+#define GG(a, b, c, d, x, s, ac) \
+ { a += G(b, c, d) + x + ac; ROTATE_LEFT(a, s); a += b; }
+#define HH(a, b, c, d, x, s, ac) \
+ { a += H(b, c, d) + x + ac; ROTATE_LEFT(a, s); a += b; }
+#define II(a, b, c, d, x, s, ac) \
+ { a += I(b, c, d) + x + ac; ROTATE_LEFT(a, s); a += b; }
+
+} // end namespace
+
+
+void MD5SUM::md5_process_block( const uint8_t block[64] )
+ {
+ uint32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ for( int i = 0, j = 0; i < 16; ++i, j += 4 ) // fill x in little endian
+ x[i] = block[j] | (block[j+1] << 8) | (block[j+2] << 16) | (block[j+3] << 24);
+
+ /* Round 1 */
+ FF (a, b, c, d, x[ 0], 7, 0xD76AA478); // 1
+ FF (d, a, b, c, x[ 1], 12, 0xE8C7B756); // 2
+ FF (c, d, a, b, x[ 2], 17, 0x242070DB); // 3
+ FF (b, c, d, a, x[ 3], 22, 0xC1BDCEEE); // 4
+ FF (a, b, c, d, x[ 4], 7, 0xF57C0FAF); // 5
+ FF (d, a, b, c, x[ 5], 12, 0x4787C62A); // 6
+ FF (c, d, a, b, x[ 6], 17, 0xA8304613); // 7
+ FF (b, c, d, a, x[ 7], 22, 0xFD469501); // 8
+ FF (a, b, c, d, x[ 8], 7, 0x698098D8); // 9
+ FF (d, a, b, c, x[ 9], 12, 0x8B44F7AF); // 10
+ FF (c, d, a, b, x[10], 17, 0xFFFF5BB1); // 11
+ FF (b, c, d, a, x[11], 22, 0x895CD7BE); // 12
+ FF (a, b, c, d, x[12], 7, 0x6B901122); // 13
+ FF (d, a, b, c, x[13], 12, 0xFD987193); // 14
+ FF (c, d, a, b, x[14], 17, 0xA679438E); // 15
+ FF (b, c, d, a, x[15], 22, 0x49B40821); // 16
+
+ /* Round 2 */
+ GG (a, b, c, d, x[ 1], 5, 0xF61E2562); // 17
+ GG (d, a, b, c, x[ 6], 9, 0xC040B340); // 18
+ GG (c, d, a, b, x[11], 14, 0x265E5A51); // 19
+ GG (b, c, d, a, x[ 0], 20, 0xE9B6C7AA); // 20
+ GG (a, b, c, d, x[ 5], 5, 0xD62F105D); // 21
+ GG (d, a, b, c, x[10], 9, 0x02441453); // 22
+ GG (c, d, a, b, x[15], 14, 0xD8A1E681); // 23
+ GG (b, c, d, a, x[ 4], 20, 0xE7D3FBC8); // 24
+ GG (a, b, c, d, x[ 9], 5, 0x21E1CDE6); // 25
+ GG (d, a, b, c, x[14], 9, 0xC33707D6); // 26
+ GG (c, d, a, b, x[ 3], 14, 0xF4D50D87); // 27
+ GG (b, c, d, a, x[ 8], 20, 0x455A14ED); // 28
+ GG (a, b, c, d, x[13], 5, 0xA9E3E905); // 29
+ GG (d, a, b, c, x[ 2], 9, 0xFCEFA3F8); // 30
+ GG (c, d, a, b, x[ 7], 14, 0x676F02D9); // 31
+ GG (b, c, d, a, x[12], 20, 0x8D2A4C8A); // 32
+
+ /* Round 3 */
+ HH (a, b, c, d, x[ 5], 4, 0xFFFA3942); // 33
+ HH (d, a, b, c, x[ 8], 11, 0x8771F681); // 34
+ HH (c, d, a, b, x[11], 16, 0x6D9D6122); // 35
+ HH (b, c, d, a, x[14], 23, 0xFDE5380C); // 36
+ HH (a, b, c, d, x[ 1], 4, 0xA4BEEA44); // 37
+ HH (d, a, b, c, x[ 4], 11, 0x4BDECFA9); // 38
+ HH (c, d, a, b, x[ 7], 16, 0xF6BB4B60); // 39
+ HH (b, c, d, a, x[10], 23, 0xBEBFBC70); // 40
+ HH (a, b, c, d, x[13], 4, 0x289B7EC6); // 41
+ HH (d, a, b, c, x[ 0], 11, 0xEAA127FA); // 42
+ HH (c, d, a, b, x[ 3], 16, 0xD4EF3085); // 43
+ HH (b, c, d, a, x[ 6], 23, 0x04881D05); // 44
+ HH (a, b, c, d, x[ 9], 4, 0xD9D4D039); // 45
+ HH (d, a, b, c, x[12], 11, 0xE6DB99E5); // 46
+ HH (c, d, a, b, x[15], 16, 0x1FA27CF8); // 47
+ HH (b, c, d, a, x[ 2], 23, 0xC4AC5665); // 48
+
+ /* Round 4 */
+ II (a, b, c, d, x[ 0], 6, 0xF4292244); // 49
+ II (d, a, b, c, x[ 7], 10, 0x432AFF97); // 50
+ II (c, d, a, b, x[14], 15, 0xAB9423A7); // 51
+ II (b, c, d, a, x[ 5], 21, 0xFC93A039); // 52
+ II (a, b, c, d, x[12], 6, 0x655B59C3); // 53
+ II (d, a, b, c, x[ 3], 10, 0x8F0CCC92); // 54
+ II (c, d, a, b, x[10], 15, 0xFFEFF47D); // 55
+ II (b, c, d, a, x[ 1], 21, 0x85845DD1); // 56
+ II (a, b, c, d, x[ 8], 6, 0x6FA87E4F); // 57
+ II (d, a, b, c, x[15], 10, 0xFE2CE6E0); // 58
+ II (c, d, a, b, x[ 6], 15, 0xA3014314); // 59
+ II (b, c, d, a, x[13], 21, 0x4E0811A1); // 60
+ II (a, b, c, d, x[ 4], 6, 0xF7537E82); // 61
+ II (d, a, b, c, x[11], 10, 0xBD3AF235); // 62
+ II (c, d, a, b, x[ 2], 15, 0x2AD7D2BB); // 63
+ II (b, c, d, a, x[ 9], 21, 0xEB86D391); // 64
+
+ // add the processed values to the context
+ state[0] += a; state[1] += b; state[2] += c; state[3] += d;
+ }
+
+
+/* Update the context for the next 'len' bytes of 'buffer'.
+ 'len' does not need to be a multiple of 64.
+*/
+void MD5SUM::md5_update( const uint8_t * const buffer, const unsigned long len )
+ {
+ unsigned index = count & 0x3F; // data length in bytes mod 64
+ count += len; // update data length
+ const unsigned rest = 64 - index;
+ unsigned long i;
+
+ if( len >= rest ) // process as many bytes as possible
+ {
+ std::memcpy( ibuf + index, buffer, rest );
+ md5_process_block( ibuf );
+ for( i = rest; i + 63 < len; i += 64 )
+ md5_process_block( buffer + i );
+ index = 0;
+ }
+ else i = 0;
+
+ std::memcpy( ibuf + index, buffer + i, len - i ); // save remaining input
+ }
+
+
+// finish computation and return the digest
+void MD5SUM::md5_finish( uint8_t digest[16] )
+ {
+ uint8_t padding[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ uint8_t bits[8];
+ uint64_t c = count << 3; // save data length in bits
+ for( int i = 0; i <= 7; ++i ) { bits[i] = (uint8_t)c; c >>= 8; }
+
+ const unsigned index = count & 0x3F; // data length in bytes mod 64
+ const unsigned len = (index < 56) ? (56 - index) : (120 - index);
+ md5_update( padding, len ); // pad to 56 mod 64
+ md5_update( bits, 8 ); // append data length in bits
+
+ for( int i = 0, j = 0; i < 4; i++, j += 4 ) // store state in digest
+ {
+ digest[j ] = (uint8_t)state[i];
+ digest[j+1] = (uint8_t)(state[i] >> 8);
+ digest[j+2] = (uint8_t)(state[i] >> 16);
+ digest[j+3] = (uint8_t)(state[i] >> 24);
+ }
+ }
+
+
+void compute_md5( const uint8_t * const buffer, const unsigned long len,
+ uint8_t digest[16] )
+ {
+ MD5SUM md5sum;
+ if( len > 0 ) md5sum.md5_update( buffer, len );
+ md5sum.md5_finish( digest );
+ }
+
+
+bool check_md5( const uint8_t * const buffer, const unsigned long len,
+ const uint8_t digest[16] )
+ {
+ uint8_t new_digest[16];
+ compute_md5( buffer, len, new_digest );
+ return ( std::memcmp( digest, new_digest, 16 ) == 0 );
+ }