1//
2// MD5Engine.cpp
3//
4// Library: Foundation
5// Package: Crypt
6// Module: MD5Engine
7//
8// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
9// and Contributors.
10//
11// SPDX-License-Identifier: BSL-1.0
12//
13//
14// MD5 (RFC 1321) algorithm:
15// Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
16// rights reserved.
17//
18// License to copy and use this software is granted provided that it
19// is identified as the "RSA Data Security, Inc. MD5 Message-Digest
20// Algorithm" in all material mentioning or referencing this software
21// or this function.
22//
23// License is also granted to make and use derivative works provided
24// that such works are identified as "derived from the RSA Data
25// Security, Inc. MD5 Message-Digest Algorithm" in all material
26// mentioning or referencing the derived work.
27//
28// RSA Data Security, Inc. makes no representations concerning either
29// the merchantability of this software or the suitability of this
30// software for any particular purpose. It is provided "as is"
31// without express or implied warranty of any kind.
32//
33// These notices must be retained in any copies of any part of this
34// documentation and/or software.
35//
36
37
38#include "Poco/MD5Engine.h"
39#include <cstring>
40
41
42namespace Poco {
43
44
45MD5Engine::MD5Engine()
46{
47 _digest.reserve(16);
48 reset();
49}
50
51
52MD5Engine::~MD5Engine()
53{
54 reset();
55}
56
57
58void MD5Engine::updateImpl(const void* input_, std::size_t inputLen)
59{
60 const unsigned char* input = (const unsigned char*) input_;
61 unsigned int i, index, partLen;
62
63 /* Compute number of bytes mod 64 */
64 index = (unsigned int)((_context.count[0] >> 3) & 0x3F);
65
66 /* Update number of bits */
67 if ((_context.count[0] += ((UInt32) inputLen << 3)) < ((UInt32) inputLen << 3))
68 _context.count[1]++;
69 _context.count[1] += ((UInt32) inputLen >> 29);
70
71 partLen = 64 - index;
72
73 /* Transform as many times as possible. */
74 if (inputLen >= partLen)
75 {
76 std::memcpy(&_context.buffer[index], input, partLen);
77 transform(_context.state, _context.buffer);
78
79 for (i = partLen; i + 63 < inputLen; i += 64)
80 transform(_context.state, &input[i]);
81
82 index = 0;
83 }
84 else i = 0;
85
86 /* Buffer remaining input */
87 std::memcpy(&_context.buffer[index], &input[i],inputLen-i);
88}
89
90
91std::size_t MD5Engine::digestLength() const
92{
93 return DIGEST_SIZE;
94}
95
96
97void MD5Engine::reset()
98{
99 std::memset(&_context, 0, sizeof(_context));
100 _context.count[0] = _context.count[1] = 0;
101 _context.state[0] = 0x67452301;
102 _context.state[1] = 0xefcdab89;
103 _context.state[2] = 0x98badcfe;
104 _context.state[3] = 0x10325476;
105}
106
107
108const DigestEngine::Digest& MD5Engine::digest()
109{
110 static const unsigned char PADDING[64] =
111 {
112 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
113 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
114 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
115 };
116 unsigned char bits[8];
117 unsigned int index, padLen;
118
119 /* Save number of bits */
120 encode(bits, _context.count, 8);
121
122 /* Pad out to 56 mod 64. */
123 index = (unsigned int)((_context.count[0] >> 3) & 0x3f);
124 padLen = (index < 56) ? (56 - index) : (120 - index);
125 update(PADDING, padLen);
126
127 /* Append length (before padding) */
128 update(bits, 8);
129
130 /* Store state in digestArray */
131 unsigned char digestArray[16];
132 encode(digestArray, _context.state, 16);
133 _digest.clear();
134 _digest.insert(_digest.begin(), digestArray, digestArray + sizeof(digestArray));
135
136 /* Zeroize sensitive information. */
137 std::memset(&_context, 0, sizeof (_context));
138 reset();
139 return _digest;
140}
141
142
143/* Constants for MD5Transform routine. */
144#define S11 7
145#define S12 12
146#define S13 17
147#define S14 22
148#define S21 5
149#define S22 9
150#define S23 14
151#define S24 20
152#define S31 4
153#define S32 11
154#define S33 16
155#define S34 23
156#define S41 6
157#define S42 10
158#define S43 15
159#define S44 21
160
161
162/* F, G, H and I are basic MD5 functions. */
163#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
164#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
165#define H(x, y, z) ((x) ^ (y) ^ (z))
166#define I(x, y, z) ((y) ^ ((x) | (~z)))
167
168
169/* ROTATE_LEFT rotates x left n bits. */
170#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
171
172
173/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
174 Rotation is separate from addition to prevent recomputation. */
175#define FF(a, b, c, d, x, s, ac) { \
176 (a) += F ((b), (c), (d)) + (x) + (UInt32)(ac); \
177 (a) = ROTATE_LEFT ((a), (s)); \
178 (a) += (b); \
179 }
180#define GG(a, b, c, d, x, s, ac) { \
181 (a) += G ((b), (c), (d)) + (x) + (UInt32)(ac); \
182 (a) = ROTATE_LEFT ((a), (s)); \
183 (a) += (b); \
184 }
185#define HH(a, b, c, d, x, s, ac) { \
186 (a) += H ((b), (c), (d)) + (x) + (UInt32)(ac); \
187 (a) = ROTATE_LEFT ((a), (s)); \
188 (a) += (b); \
189 }
190#define II(a, b, c, d, x, s, ac) { \
191 (a) += I ((b), (c), (d)) + (x) + (UInt32)(ac); \
192 (a) = ROTATE_LEFT ((a), (s)); \
193 (a) += (b); \
194 }
195
196
197void MD5Engine::transform (UInt32 state[4], const unsigned char block[64])
198{
199 UInt32 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
200
201 decode(x, block, 64);
202
203 /* Round 1 */
204 FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
205 FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
206 FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
207 FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
208 FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
209 FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
210 FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
211 FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
212 FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
213 FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
214 FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
215 FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
216 FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
217 FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
218 FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
219 FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
220
221 /* Round 2 */
222 GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
223 GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
224 GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
225 GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
226 GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
227 GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
228 GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
229 GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
230 GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
231 GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
232 GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
233 GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
234 GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
235 GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
236 GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
237 GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
238
239 /* Round 3 */
240 HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
241 HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
242 HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
243 HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
244 HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
245 HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
246 HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
247 HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
248 HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
249 HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
250 HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
251 HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
252 HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
253 HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
254 HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
255 HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
256
257 /* Round 4 */
258 II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
259 II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
260 II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
261 II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
262 II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
263 II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
264 II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
265 II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
266 II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
267 II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
268 II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
269 II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
270 II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
271 II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
272 II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
273 II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
274
275 state[0] += a;
276 state[1] += b;
277 state[2] += c;
278 state[3] += d;
279
280 /* Zeroize sensitive information. */
281 std::memset(x, 0, sizeof(x));
282}
283
284
285void MD5Engine::encode(unsigned char* output, const UInt32* input, std::size_t len)
286{
287 unsigned int i, j;
288
289 for (i = 0, j = 0; j < len; i++, j += 4)
290 {
291 output[j] = (unsigned char)(input[i] & 0xff);
292 output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
293 output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
294 output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
295 }
296}
297
298
299void MD5Engine::decode(UInt32* output, const unsigned char* input, std::size_t len)
300{
301 unsigned int i, j;
302
303 for (i = 0, j = 0; j < len; i++, j += 4)
304 output[i] = ((UInt32)input[j]) | (((UInt32)input[j+1]) << 8) |
305 (((UInt32)input[j+2]) << 16) | (((UInt32)input[j+3]) << 24);
306}
307
308
309} // namespace Poco
310