1 /*
2 This code is written by kerukuro and released into public domain.
3 */
4 
5 #ifndef DIGESTPP_PROVIDERS_MD5_HPP
6 #define DIGESTPP_PROVIDERS_MD5_HPP
7 
8 #include "../../detail/functions.hpp"
9 #include "../../detail/absorb_data.hpp"
10 #include "constants/md5_constants.hpp"
11 #include <array>
12 
13 namespace digestpp
14 {
15 
16 namespace detail
17 {
18 
19 namespace md5_functions
20 {
roundf(int round,uint32_t & a,uint32_t & b,uint32_t & c,uint32_t & d,const uint32_t * M)21 	static inline void roundf(int round, uint32_t& a, uint32_t& b, uint32_t& c, uint32_t& d, const uint32_t* M)
22 	{
23 		a = b + rotate_left(a + (d ^ (b & (c ^ d))) + md5_constants<void>::K[round] + M[round],
24 				md5_constants<void>::S[round]);
25 	}
26 
roundg(int round,uint32_t & a,uint32_t & b,uint32_t & c,uint32_t & d,const uint32_t * M)27 	static inline void roundg(int round, uint32_t& a, uint32_t& b, uint32_t& c, uint32_t& d, const uint32_t* M)
28 	{
29 		a = b + rotate_left(a + (c ^ (d & (b ^ c))) + md5_constants<void>::K[round] + M[(5 * round + 1) % 16],
30 				md5_constants<void>::S[round]);
31 	}
32 
roundh(int round,uint32_t & a,uint32_t & b,uint32_t & c,uint32_t & d,const uint32_t * M)33 	static inline void roundh(int round, uint32_t& a, uint32_t& b, uint32_t& c, uint32_t& d, const uint32_t* M)
34 	{
35 		a = b + rotate_left(a + (b ^ c ^ d) + md5_constants<void>::K[round] + M[(3 * round + 5) % 16],
36 				md5_constants<void>::S[round]);
37 	}
38 
roundi(int round,uint32_t & a,uint32_t & b,uint32_t & c,uint32_t & d,const uint32_t * M)39 	static inline void roundi(int round, uint32_t& a, uint32_t& b, uint32_t& c, uint32_t& d, const uint32_t* M)
40 	{
41 		a = b + rotate_left(a + (c ^ (b | ~d)) + md5_constants<void>::K[round] + M[(7 * round) % 16],
42 				md5_constants<void>::S[round]);
43 	}
44 
45 }
46 
47 class md5_provider
48 {
49 public:
50 	static const bool is_xof = false;
51 
md5_provider()52 	md5_provider()
53 	{
54 	}
55 
~md5_provider()56 	~md5_provider()
57 	{
58 		clear();
59 	}
60 
init()61 	inline void init()
62 	{
63 		H[0] = 0x67452301;
64 		H[1] = 0xefcdab89;
65 		H[2] = 0x98badcfe;
66 		H[3] = 0x10325476;
67 		pos = 0;
68 		total = 0;
69 	}
70 
update(const unsigned char * data,size_t len)71 	inline void update(const unsigned char* data, size_t len)
72 	{
73 		detail::absorb_bytes(data, len, 64, 64, m.data(), pos, total,
74 			[this](const unsigned char* data, size_t len) { transform(data, len); });
75 	}
76 
final(unsigned char * hash)77 	inline void final(unsigned char* hash)
78 	{
79 		total += pos * 8;
80 		m[pos++] = 0x80;
81 		if (pos > 56)
82 		{
83 			if (pos != 64)
84 				memset(&m[pos], 0, 64 - pos);
85 			transform(&m[0], 1);
86 			pos = 0;
87 		}
88 		memset(&m[0] + pos, 0, 56 - pos);
89 		memcpy(&m[0] + (64 - 8), &total, 64 / 8);
90 		transform(&m[0], 1);
91 		memcpy(hash, H.data(), 16);
92 	}
93 
clear()94 	inline void clear()
95 	{
96 		zero_memory(H);
97 		zero_memory(m);
98 	}
99 
hash_size() const100 	inline size_t hash_size() const { return 128; }
101 
102 private:
transform(const unsigned char * data,size_t num_blks)103 	inline void transform(const unsigned char* data, size_t num_blks)
104 	{
105 		const uint32_t* M = reinterpret_cast<const uint32_t*>(data);
106 		for (uint64_t blk = 0; blk < num_blks; blk++, M += 16)
107 		{
108 			uint32_t a = H[0];
109 			uint32_t b = H[1];
110 			uint32_t c = H[2];
111 			uint32_t d = H[3];
112 
113 			md5_functions::roundf(0, a, b, c, d, M);
114 			md5_functions::roundf(1, d, a, b, c, M);
115 			md5_functions::roundf(2, c, d, a, b, M);
116 			md5_functions::roundf(3, b, c, d, a, M);
117 			md5_functions::roundf(4, a, b, c, d, M);
118 			md5_functions::roundf(5, d, a, b, c, M);
119 			md5_functions::roundf(6, c, d, a, b, M);
120 			md5_functions::roundf(7, b, c, d, a, M);
121 			md5_functions::roundf(8, a, b, c, d, M);
122 			md5_functions::roundf(9, d, a, b, c, M);
123 			md5_functions::roundf(10, c, d, a, b, M);
124 			md5_functions::roundf(11, b, c, d, a, M);
125 			md5_functions::roundf(12, a, b, c, d, M);
126 			md5_functions::roundf(13, d, a, b, c, M);
127 			md5_functions::roundf(14, c, d, a, b, M);
128 			md5_functions::roundf(15, b, c, d, a, M);
129 
130 			md5_functions::roundg(16, a, b, c, d, M);
131 			md5_functions::roundg(17, d, a, b, c, M);
132 			md5_functions::roundg(18, c, d, a, b, M);
133 			md5_functions::roundg(19, b, c, d, a, M);
134 			md5_functions::roundg(20, a, b, c, d, M);
135 			md5_functions::roundg(21, d, a, b, c, M);
136 			md5_functions::roundg(22, c, d, a, b, M);
137 			md5_functions::roundg(23, b, c, d, a, M);
138 			md5_functions::roundg(24, a, b, c, d, M);
139 			md5_functions::roundg(25, d, a, b, c, M);
140 			md5_functions::roundg(26, c, d, a, b, M);
141 			md5_functions::roundg(27, b, c, d, a, M);
142 			md5_functions::roundg(28, a, b, c, d, M);
143 			md5_functions::roundg(29, d, a, b, c, M);
144 			md5_functions::roundg(30, c, d, a, b, M);
145 			md5_functions::roundg(31, b, c, d, a, M);
146 
147 			md5_functions::roundh(32, a, b, c, d, M);
148 			md5_functions::roundh(33, d, a, b, c, M);
149 			md5_functions::roundh(34, c, d, a, b, M);
150 			md5_functions::roundh(35, b, c, d, a, M);
151 			md5_functions::roundh(36, a, b, c, d, M);
152 			md5_functions::roundh(37, d, a, b, c, M);
153 			md5_functions::roundh(38, c, d, a, b, M);
154 			md5_functions::roundh(39, b, c, d, a, M);
155 			md5_functions::roundh(40, a, b, c, d, M);
156 			md5_functions::roundh(41, d, a, b, c, M);
157 			md5_functions::roundh(42, c, d, a, b, M);
158 			md5_functions::roundh(43, b, c, d, a, M);
159 			md5_functions::roundh(44, a, b, c, d, M);
160 			md5_functions::roundh(45, d, a, b, c, M);
161 			md5_functions::roundh(46, c, d, a, b, M);
162 			md5_functions::roundh(47, b, c, d, a, M);
163 
164 			md5_functions::roundi(48, a, b, c, d, M);
165 			md5_functions::roundi(49, d, a, b, c, M);
166 			md5_functions::roundi(50, c, d, a, b, M);
167 			md5_functions::roundi(51, b, c, d, a, M);
168 			md5_functions::roundi(52, a, b, c, d, M);
169 			md5_functions::roundi(53, d, a, b, c, M);
170 			md5_functions::roundi(54, c, d, a, b, M);
171 			md5_functions::roundi(55, b, c, d, a, M);
172 			md5_functions::roundi(56, a, b, c, d, M);
173 			md5_functions::roundi(57, d, a, b, c, M);
174 			md5_functions::roundi(58, c, d, a, b, M);
175 			md5_functions::roundi(59, b, c, d, a, M);
176 			md5_functions::roundi(60, a, b, c, d, M);
177 			md5_functions::roundi(61, d, a, b, c, M);
178 			md5_functions::roundi(62, c, d, a, b, M);
179 			md5_functions::roundi(63, b, c, d, a, M);
180 
181 			H[0] += a;
182 			H[1] += b;
183 			H[2] += c;
184 			H[3] += d;
185 		}
186 	}
187 
188 	std::array<uint32_t, 4> H;
189 	std::array<unsigned char, 64> m;
190 	size_t pos;
191 	uint64_t total;
192 };
193 
194 } // namespace detail
195 
196 } // namespace digestpp
197 
198 #endif