sdk-world v2026.11.05
PS2 SDK - world tier (copyleft-allowed, non-essential packages)
Loading...
Searching...
No Matches
md5.cpp
1// //////////////////////////////////////////////////////////
2// md5.cpp
3// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved.
4// see http://create.stephan-brumme.com/disclaimer.html
5//
6
7#include "md5.h"
8
9#if defined(__PS2__)
10 #include <machine/endian.h>
11#elif !defined(_MSC_VER)
12 #include <endian.h>
13#endif
14
15
18{
19 reset();
20}
21
22
25{
26 m_numBytes = 0;
27 m_bufferSize = 0;
28
29 // according to RFC 1321
30 m_hash[0] = 0x67452301;
31 m_hash[1] = 0xefcdab89;
32 m_hash[2] = 0x98badcfe;
33 m_hash[3] = 0x10325476;
34}
35
36
37namespace
38{
39 // mix functions for processBlock()
40 inline uint32_t f1(uint32_t b, uint32_t c, uint32_t d)
41 {
42 return d ^ (b & (c ^ d)); // original: f = (b & c) | ((~b) & d);
43 }
44
45 inline uint32_t f2(uint32_t b, uint32_t c, uint32_t d)
46 {
47 return c ^ (d & (b ^ c)); // original: f = (b & d) | (c & (~d));
48 }
49
50 inline uint32_t f3(uint32_t b, uint32_t c, uint32_t d)
51 {
52 return b ^ c ^ d;
53 }
54
55 inline uint32_t f4(uint32_t b, uint32_t c, uint32_t d)
56 {
57 return c ^ (b | ~d);
58 }
59
60 inline uint32_t rotate(uint32_t a, uint32_t c)
61 {
62 return (a << c) | (a >> (32 - c));
63 }
64
65#if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && (__BYTE_ORDER == __BIG_ENDIAN)
66 inline uint32_t swap(uint32_t x)
67 {
68#if defined(__GNUC__) || defined(__clang__)
69 return __builtin_bswap32(x);
70#endif
71#ifdef MSC_VER
72 return _byteswap_ulong(x);
73#endif
74
75 return (x >> 24) |
76 ((x >> 8) & 0x0000FF00) |
77 ((x << 8) & 0x00FF0000) |
78 (x << 24);
79 }
80#endif
81}
82
83
85void MD5::processBlock(const void* data)
86{
87 // get last hash
88 uint32_t a = m_hash[0];
89 uint32_t b = m_hash[1];
90 uint32_t c = m_hash[2];
91 uint32_t d = m_hash[3];
92
93 // data represented as 16x 32-bit words
94 const uint32_t* words = (uint32_t*) data;
95
96 // computations are little endian, swap data if necessary
97#if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && (__BYTE_ORDER == __BIG_ENDIAN)
98#define LITTLEENDIAN(x) swap(x)
99#else
100#define LITTLEENDIAN(x) (x)
101#endif
102
103 // first round
104 uint32_t word0 = LITTLEENDIAN(words[ 0]);
105 a = rotate(a + f1(b,c,d) + word0 + 0xd76aa478, 7) + b;
106 uint32_t word1 = LITTLEENDIAN(words[ 1]);
107 d = rotate(d + f1(a,b,c) + word1 + 0xe8c7b756, 12) + a;
108 uint32_t word2 = LITTLEENDIAN(words[ 2]);
109 c = rotate(c + f1(d,a,b) + word2 + 0x242070db, 17) + d;
110 uint32_t word3 = LITTLEENDIAN(words[ 3]);
111 b = rotate(b + f1(c,d,a) + word3 + 0xc1bdceee, 22) + c;
112
113 uint32_t word4 = LITTLEENDIAN(words[ 4]);
114 a = rotate(a + f1(b,c,d) + word4 + 0xf57c0faf, 7) + b;
115 uint32_t word5 = LITTLEENDIAN(words[ 5]);
116 d = rotate(d + f1(a,b,c) + word5 + 0x4787c62a, 12) + a;
117 uint32_t word6 = LITTLEENDIAN(words[ 6]);
118 c = rotate(c + f1(d,a,b) + word6 + 0xa8304613, 17) + d;
119 uint32_t word7 = LITTLEENDIAN(words[ 7]);
120 b = rotate(b + f1(c,d,a) + word7 + 0xfd469501, 22) + c;
121
122 uint32_t word8 = LITTLEENDIAN(words[ 8]);
123 a = rotate(a + f1(b,c,d) + word8 + 0x698098d8, 7) + b;
124 uint32_t word9 = LITTLEENDIAN(words[ 9]);
125 d = rotate(d + f1(a,b,c) + word9 + 0x8b44f7af, 12) + a;
126 uint32_t word10 = LITTLEENDIAN(words[10]);
127 c = rotate(c + f1(d,a,b) + word10 + 0xffff5bb1, 17) + d;
128 uint32_t word11 = LITTLEENDIAN(words[11]);
129 b = rotate(b + f1(c,d,a) + word11 + 0x895cd7be, 22) + c;
130
131 uint32_t word12 = LITTLEENDIAN(words[12]);
132 a = rotate(a + f1(b,c,d) + word12 + 0x6b901122, 7) + b;
133 uint32_t word13 = LITTLEENDIAN(words[13]);
134 d = rotate(d + f1(a,b,c) + word13 + 0xfd987193, 12) + a;
135 uint32_t word14 = LITTLEENDIAN(words[14]);
136 c = rotate(c + f1(d,a,b) + word14 + 0xa679438e, 17) + d;
137 uint32_t word15 = LITTLEENDIAN(words[15]);
138 b = rotate(b + f1(c,d,a) + word15 + 0x49b40821, 22) + c;
139
140 // second round
141 a = rotate(a + f2(b,c,d) + word1 + 0xf61e2562, 5) + b;
142 d = rotate(d + f2(a,b,c) + word6 + 0xc040b340, 9) + a;
143 c = rotate(c + f2(d,a,b) + word11 + 0x265e5a51, 14) + d;
144 b = rotate(b + f2(c,d,a) + word0 + 0xe9b6c7aa, 20) + c;
145
146 a = rotate(a + f2(b,c,d) + word5 + 0xd62f105d, 5) + b;
147 d = rotate(d + f2(a,b,c) + word10 + 0x02441453, 9) + a;
148 c = rotate(c + f2(d,a,b) + word15 + 0xd8a1e681, 14) + d;
149 b = rotate(b + f2(c,d,a) + word4 + 0xe7d3fbc8, 20) + c;
150
151 a = rotate(a + f2(b,c,d) + word9 + 0x21e1cde6, 5) + b;
152 d = rotate(d + f2(a,b,c) + word14 + 0xc33707d6, 9) + a;
153 c = rotate(c + f2(d,a,b) + word3 + 0xf4d50d87, 14) + d;
154 b = rotate(b + f2(c,d,a) + word8 + 0x455a14ed, 20) + c;
155
156 a = rotate(a + f2(b,c,d) + word13 + 0xa9e3e905, 5) + b;
157 d = rotate(d + f2(a,b,c) + word2 + 0xfcefa3f8, 9) + a;
158 c = rotate(c + f2(d,a,b) + word7 + 0x676f02d9, 14) + d;
159 b = rotate(b + f2(c,d,a) + word12 + 0x8d2a4c8a, 20) + c;
160
161 // third round
162 a = rotate(a + f3(b,c,d) + word5 + 0xfffa3942, 4) + b;
163 d = rotate(d + f3(a,b,c) + word8 + 0x8771f681, 11) + a;
164 c = rotate(c + f3(d,a,b) + word11 + 0x6d9d6122, 16) + d;
165 b = rotate(b + f3(c,d,a) + word14 + 0xfde5380c, 23) + c;
166
167 a = rotate(a + f3(b,c,d) + word1 + 0xa4beea44, 4) + b;
168 d = rotate(d + f3(a,b,c) + word4 + 0x4bdecfa9, 11) + a;
169 c = rotate(c + f3(d,a,b) + word7 + 0xf6bb4b60, 16) + d;
170 b = rotate(b + f3(c,d,a) + word10 + 0xbebfbc70, 23) + c;
171
172 a = rotate(a + f3(b,c,d) + word13 + 0x289b7ec6, 4) + b;
173 d = rotate(d + f3(a,b,c) + word0 + 0xeaa127fa, 11) + a;
174 c = rotate(c + f3(d,a,b) + word3 + 0xd4ef3085, 16) + d;
175 b = rotate(b + f3(c,d,a) + word6 + 0x04881d05, 23) + c;
176
177 a = rotate(a + f3(b,c,d) + word9 + 0xd9d4d039, 4) + b;
178 d = rotate(d + f3(a,b,c) + word12 + 0xe6db99e5, 11) + a;
179 c = rotate(c + f3(d,a,b) + word15 + 0x1fa27cf8, 16) + d;
180 b = rotate(b + f3(c,d,a) + word2 + 0xc4ac5665, 23) + c;
181
182 // fourth round
183 a = rotate(a + f4(b,c,d) + word0 + 0xf4292244, 6) + b;
184 d = rotate(d + f4(a,b,c) + word7 + 0x432aff97, 10) + a;
185 c = rotate(c + f4(d,a,b) + word14 + 0xab9423a7, 15) + d;
186 b = rotate(b + f4(c,d,a) + word5 + 0xfc93a039, 21) + c;
187
188 a = rotate(a + f4(b,c,d) + word12 + 0x655b59c3, 6) + b;
189 d = rotate(d + f4(a,b,c) + word3 + 0x8f0ccc92, 10) + a;
190 c = rotate(c + f4(d,a,b) + word10 + 0xffeff47d, 15) + d;
191 b = rotate(b + f4(c,d,a) + word1 + 0x85845dd1, 21) + c;
192
193 a = rotate(a + f4(b,c,d) + word8 + 0x6fa87e4f, 6) + b;
194 d = rotate(d + f4(a,b,c) + word15 + 0xfe2ce6e0, 10) + a;
195 c = rotate(c + f4(d,a,b) + word6 + 0xa3014314, 15) + d;
196 b = rotate(b + f4(c,d,a) + word13 + 0x4e0811a1, 21) + c;
197
198 a = rotate(a + f4(b,c,d) + word4 + 0xf7537e82, 6) + b;
199 d = rotate(d + f4(a,b,c) + word11 + 0xbd3af235, 10) + a;
200 c = rotate(c + f4(d,a,b) + word2 + 0x2ad7d2bb, 15) + d;
201 b = rotate(b + f4(c,d,a) + word9 + 0xeb86d391, 21) + c;
202
203 // update hash
204 m_hash[0] += a;
205 m_hash[1] += b;
206 m_hash[2] += c;
207 m_hash[3] += d;
208}
209
210
212void MD5::add(const void* data, size_t numBytes)
213{
214 const uint8_t* current = (const uint8_t*) data;
215
216 if (m_bufferSize > 0)
217 {
218 while (numBytes > 0 && m_bufferSize < BlockSize)
219 {
220 m_buffer[m_bufferSize++] = *current++;
221 numBytes--;
222 }
223 }
224
225 // full buffer
226 if (m_bufferSize == BlockSize)
227 {
228 processBlock(m_buffer);
229 m_numBytes += BlockSize;
230 m_bufferSize = 0;
231 }
232
233 // no more data ?
234 if (numBytes == 0)
235 return;
236
237 // process full blocks
238 while (numBytes >= BlockSize)
239 {
240 processBlock(current);
241 current += BlockSize;
242 m_numBytes += BlockSize;
243 numBytes -= BlockSize;
244 }
245
246 // keep remaining bytes in buffer
247 while (numBytes > 0)
248 {
249 m_buffer[m_bufferSize++] = *current++;
250 numBytes--;
251 }
252}
253
254
256void MD5::processBuffer()
257{
258 // the input bytes are considered as bits strings, where the first bit is the most significant bit of the byte
259
260 // - append "1" bit to message
261 // - append "0" bits until message length in bit mod 512 is 448
262 // - append length as 64 bit integer
263
264 // number of bits
265 size_t paddedLength = m_bufferSize * 8;
266
267 // plus one bit set to 1 (always appended)
268 paddedLength++;
269
270 // number of bits must be (numBits % 512) = 448
271 size_t lower11Bits = paddedLength & 511;
272 if (lower11Bits <= 448)
273 paddedLength += 448 - lower11Bits;
274 else
275 paddedLength += 512 + 448 - lower11Bits;
276 // convert from bits to bytes
277 paddedLength /= 8;
278
279 // only needed if additional data flows over into a second block
280 unsigned char extra[BlockSize];
281
282 // append a "1" bit, 128 => binary 10000000
283 if (m_bufferSize < BlockSize)
284 m_buffer[m_bufferSize] = 128;
285 else
286 extra[0] = 128;
287
288 size_t i;
289 for (i = m_bufferSize + 1; i < BlockSize; i++)
290 m_buffer[i] = 0;
291 for (; i < paddedLength; i++)
292 extra[i - BlockSize] = 0;
293
294 // add message length in bits as 64 bit number
295 uint64_t msgBits = 8 * (m_numBytes + m_bufferSize);
296 // find right position
297 unsigned char* addLength;
298 if (paddedLength < BlockSize)
299 addLength = m_buffer + paddedLength;
300 else
301 addLength = extra + paddedLength - BlockSize;
302
303 // must be little endian
304 *addLength++ = msgBits & 0xFF; msgBits >>= 8;
305 *addLength++ = msgBits & 0xFF; msgBits >>= 8;
306 *addLength++ = msgBits & 0xFF; msgBits >>= 8;
307 *addLength++ = msgBits & 0xFF; msgBits >>= 8;
308 *addLength++ = msgBits & 0xFF; msgBits >>= 8;
309 *addLength++ = msgBits & 0xFF; msgBits >>= 8;
310 *addLength++ = msgBits & 0xFF; msgBits >>= 8;
311 *addLength++ = msgBits & 0xFF;
312
313 // process blocks
314 processBlock(m_buffer);
315 // flowed over into a second block ?
316 if (paddedLength > BlockSize)
317 processBlock(extra);
318}
319
320
322std::string MD5::getHash()
323{
324 // compute hash (as raw bytes)
325 unsigned char rawHash[HashBytes];
326 getHash(rawHash);
327
328 // convert to hex string
329 std::string result;
330 result.reserve(2 * HashBytes);
331 for (int i = 0; i < HashBytes; i++)
332 {
333 static const char dec2hex[16+1] = "0123456789abcdef";
334 result += dec2hex[(rawHash[i] >> 4) & 15];
335 result += dec2hex[ rawHash[i] & 15];
336 }
337
338 return result;
339}
340
341
343void MD5::getHash(unsigned char buffer[MD5::HashBytes])
344{
345 // save old hash if buffer is partially filled
346 uint32_t oldHash[HashValues];
347 for (int i = 0; i < HashValues; i++)
348 oldHash[i] = m_hash[i];
349
350 // process remaining bytes
351 processBuffer();
352
353 unsigned char* current = buffer;
354 for (int i = 0; i < HashValues; i++)
355 {
356 *current++ = m_hash[i] & 0xFF;
357 *current++ = (m_hash[i] >> 8) & 0xFF;
358 *current++ = (m_hash[i] >> 16) & 0xFF;
359 *current++ = (m_hash[i] >> 24) & 0xFF;
360
361 // restore old hash
362 m_hash[i] = oldHash[i];
363 }
364}
365
366
368std::string MD5::operator()(const void* data, size_t numBytes)
369{
370 reset();
371 add(data, numBytes);
372 return getHash();
373}
374
375
377std::string MD5::operator()(const std::string& text)
378{
379 reset();
380 add(text.c_str(), text.size());
381 return getHash();
382}
std::string operator()(const void *data, size_t numBytes)
compute MD5 of a memory block
Definition md5.cpp:368
std::string getHash()
return latest hash as 32 hex characters
Definition md5.cpp:322
void reset()
restart
Definition md5.cpp:24
void add(const void *data, size_t numBytes)
add arbitrary number of bytes
Definition md5.cpp:212
MD5()
same as reset()
Definition md5.cpp:17