1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 /* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
21 /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
24 License to copy and use this software is granted provided that it
25 is identified as the "RSA Data Security, Inc. MD5 Message-Digest
26 Algorithm" in all material mentioning or referencing this software
29 License is also granted to make and use derivative works provided
30 that such works are identified as "derived from the RSA Data
31 Security, Inc. MD5 Message-Digest Algorithm" in all material
32 mentioning or referencing the derived work.
34 RSA Data Security, Inc. makes no representations concerning either
35 the merchantability of this software or the suitability of this
36 software for any particular purpose. It is provided "as is"
37 without express or implied warranty of any kind.
39 These notices must be retained in any copies of any part of this
40 documentation and/or software.
45 #include "nel/misc/md5.h"
47 #include "nel/misc/types_nl.h"
48 #include "nel/misc/debug.h"
49 #include "nel/misc/file.h"
50 #include "nel/misc/path.h"
51 #include "nel/misc/stream.h"
61 // ****************************************************************************
62 // ****************************************************************************
63 // High Level Routines
64 // ****************************************************************************
65 // ****************************************************************************
67 // ****************************************************************************
68 CHashKeyMD5
getMD5(const std::string
&filename
)
71 CHashKeyMD5 Message_Digest
;
72 Message_Digest
.clear();
75 if (!ifile
.open(CPath::lookup(filename
)))
77 nlwarning ("MD5: Can't open the file '%s'", filename
.c_str());
78 return Message_Digest
;
84 int bufferSize
= 1024;
85 sint fs
= ifile
.getFileSize();
89 //bs = (int)fread (buffer, 1, bufferSize, fp);
90 n
= std::min (bufferSize
, fs
-read
);
91 //nlinfo ("read %d bytes", n);
92 ifile
.serialBuffer((uint8
*)buffer
, n
);
94 md5ctx
.update(buffer
, n
);
102 md5ctx
.final(Message_Digest
);
104 return Message_Digest
;
107 // ****************************************************************************
108 CHashKeyMD5
getMD5(const uint8
*buffer
, uint32 size
)
111 CHashKeyMD5 Message_Digest
;
112 Message_Digest
.clear();
115 md5ctx
.update(buffer
, size
);
116 md5ctx
.final(Message_Digest
);
118 return Message_Digest
;
121 // ****************************************************************************
122 // ****************************************************************************
124 // ****************************************************************************
125 // ****************************************************************************
127 // ****************************************************************************
128 void CHashKeyMD5::clear()
130 for (uint32 i
= 0; i
< 16; ++i
)
134 // ****************************************************************************
135 string
CHashKeyMD5::toString() const
137 return toHexa(Data
, 16);
140 // ****************************************************************************
141 bool CHashKeyMD5::fromString(const std::string
&in
)
145 nlwarning("bad string size");
149 return fromHexa(in
, Data
);
152 // ****************************************************************************
153 bool CHashKeyMD5::operator!=(const CHashKeyMD5
&in
) const
155 for (uint32 i
= 0; i
< 16; ++i
)
156 if (Data
[i
] != in
.Data
[i
])
161 // ****************************************************************************
162 bool CHashKeyMD5::operator==(const CHashKeyMD5
&in
) const
164 return !operator!=(in
);
167 // ****************************************************************************
168 bool CHashKeyMD5::operator<(const CHashKeyMD5
&in
) const
170 for (uint32 i
= 0; i
< 16; ++i
)
171 if (Data
[i
] >= in
.Data
[i
])
176 // ****************************************************************************
177 void CHashKeyMD5::serial (NLMISC::IStream
&s
)
179 s
.serialBuffer(Data
,16);
183 // ****************************************************************************
184 // ****************************************************************************
186 // ****************************************************************************
187 // ****************************************************************************
189 uint8
CMD5Context::Padding
[64] = {
190 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
191 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
192 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
195 // ****************************************************************************
196 void CMD5Context::init()
198 Count
[0] = Count
[1] = 0;
199 // Load magic initialization constants.
200 State
[0] = 0x67452301;
201 State
[1] = 0xefcdab89;
202 State
[2] = 0x98badcfe;
203 State
[3] = 0x10325476;
206 // ****************************************************************************
207 void CMD5Context::update (const uint8
*pBufIn
, uint32 nBufLength
)
209 uint i
, index
, partLen
;
211 // Compute number of bytes mod 64
212 index
= (uint
)((Count
[0] >> 3) & 0x3F);
214 // Update number of bits
215 if ((Count
[0] += (nBufLength
<< 3)) < (nBufLength
<< 3))
217 Count
[1] += (nBufLength
>> 29);
219 partLen
= 64 - index
;
221 // Transform as many times as possible.
222 if (nBufLength
>= partLen
)
224 memcpy((uint8
*)&Buffer
[index
], pBufIn
, partLen
);
225 transform (State
, Buffer
);
227 for (i
= partLen
; i
+ 63 < nBufLength
; i
+= 64)
228 transform (State
, &pBufIn
[i
]);
237 // Buffer remaining input
238 memcpy((uint8
*)&Buffer
[index
], &pBufIn
[i
], nBufLength
-i
);
241 // ****************************************************************************
242 void CMD5Context::final (CHashKeyMD5
&out
)
247 // Save number of bits
248 encode (&bits
[0], Count
, 8);
250 // Pad out to 56 mod 64.
251 index
= (unsigned int)((Count
[0] >> 3) & 0x3f);
252 padLen
= (index
< 56) ? (56 - index
) : (120 - index
);
253 update (Padding
, padLen
);
255 // Append length (before padding)
256 update (&bits
[0], 8);
257 // Store state in digest
258 encode (out
.Data
, State
, 16);
260 // Zeroize sensitive information.
262 for (i
= 0; i
< 4; ++i
) State
[i
] = 0;
263 for (i
= 0; i
< 2; ++i
) Count
[i
] = 0;
264 for (i
= 0; i
< 64; ++i
) Buffer
[i
] = 0;
267 // Constants for MD5Transform routine.
268 // ****************************************************************************
286 // F, G, H and I are basic MD5 functions.
287 #define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
288 #define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
289 #define H(x, y, z) ((x) ^ (y) ^ (z))
290 #define I(x, y, z) ((y) ^ ((x) | (~z)))
292 // ROTATE_LEFT rotates x left n bits.
293 #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
295 // FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
296 // Rotation is separate from addition to prevent recomputation.
297 #define FF(a, b, c, d, x, s, ac) { \
298 (a) += F ((b), (c), (d)) + (x) + (uint32)(ac); \
299 (a) = ROTATE_LEFT ((a), (s)); \
302 #define GG(a, b, c, d, x, s, ac) { \
303 (a) += G ((b), (c), (d)) + (x) + (uint32)(ac); \
304 (a) = ROTATE_LEFT ((a), (s)); \
307 #define HH(a, b, c, d, x, s, ac) { \
308 (a) += H ((b), (c), (d)) + (x) + (uint32)(ac); \
309 (a) = ROTATE_LEFT ((a), (s)); \
312 #define II(a, b, c, d, x, s, ac) { \
313 (a) += I ((b), (c), (d)) + (x) + (uint32)(ac); \
314 (a) = ROTATE_LEFT ((a), (s)); \
319 // MD5 basic transformation. Transforms state based on block.
320 // ****************************************************************************
321 void CMD5Context::transform (uint32 state
[4], const uint8 block
[64])
323 uint32 a
= state
[0], b
= state
[1], c
= state
[2], d
= state
[3], x
[16];
325 decode (&x
[0], &block
[0], 64);
328 FF (a
, b
, c
, d
, x
[ 0], S11
, 0xd76aa478); // 1
329 FF (d
, a
, b
, c
, x
[ 1], S12
, 0xe8c7b756); // 2
330 FF (c
, d
, a
, b
, x
[ 2], S13
, 0x242070db); // 3
331 FF (b
, c
, d
, a
, x
[ 3], S14
, 0xc1bdceee); // 4
332 FF (a
, b
, c
, d
, x
[ 4], S11
, 0xf57c0faf); // 5
333 FF (d
, a
, b
, c
, x
[ 5], S12
, 0x4787c62a); // 6
334 FF (c
, d
, a
, b
, x
[ 6], S13
, 0xa8304613); // 7
335 FF (b
, c
, d
, a
, x
[ 7], S14
, 0xfd469501); // 8
336 FF (a
, b
, c
, d
, x
[ 8], S11
, 0x698098d8); // 9
337 FF (d
, a
, b
, c
, x
[ 9], S12
, 0x8b44f7af); // 10
338 FF (c
, d
, a
, b
, x
[10], S13
, 0xffff5bb1); // 11
339 FF (b
, c
, d
, a
, x
[11], S14
, 0x895cd7be); // 12
340 FF (a
, b
, c
, d
, x
[12], S11
, 0x6b901122); // 13
341 FF (d
, a
, b
, c
, x
[13], S12
, 0xfd987193); // 14
342 FF (c
, d
, a
, b
, x
[14], S13
, 0xa679438e); // 15
343 FF (b
, c
, d
, a
, x
[15], S14
, 0x49b40821); // 16
346 GG (a
, b
, c
, d
, x
[ 1], S21
, 0xf61e2562); // 17
347 GG (d
, a
, b
, c
, x
[ 6], S22
, 0xc040b340); // 18
348 GG (c
, d
, a
, b
, x
[11], S23
, 0x265e5a51); // 19
349 GG (b
, c
, d
, a
, x
[ 0], S24
, 0xe9b6c7aa); // 20
350 GG (a
, b
, c
, d
, x
[ 5], S21
, 0xd62f105d); // 21
351 GG (d
, a
, b
, c
, x
[10], S22
, 0x2441453); // 22
352 GG (c
, d
, a
, b
, x
[15], S23
, 0xd8a1e681); // 23
353 GG (b
, c
, d
, a
, x
[ 4], S24
, 0xe7d3fbc8); // 24
354 GG (a
, b
, c
, d
, x
[ 9], S21
, 0x21e1cde6); // 25
355 GG (d
, a
, b
, c
, x
[14], S22
, 0xc33707d6); // 26
356 GG (c
, d
, a
, b
, x
[ 3], S23
, 0xf4d50d87); // 27
357 GG (b
, c
, d
, a
, x
[ 8], S24
, 0x455a14ed); // 28
358 GG (a
, b
, c
, d
, x
[13], S21
, 0xa9e3e905); // 29
359 GG (d
, a
, b
, c
, x
[ 2], S22
, 0xfcefa3f8); // 30
360 GG (c
, d
, a
, b
, x
[ 7], S23
, 0x676f02d9); // 31
361 GG (b
, c
, d
, a
, x
[12], S24
, 0x8d2a4c8a); // 32
364 HH (a
, b
, c
, d
, x
[ 5], S31
, 0xfffa3942); // 33
365 HH (d
, a
, b
, c
, x
[ 8], S32
, 0x8771f681); // 34
366 HH (c
, d
, a
, b
, x
[11], S33
, 0x6d9d6122); // 35
367 HH (b
, c
, d
, a
, x
[14], S34
, 0xfde5380c); // 36
368 HH (a
, b
, c
, d
, x
[ 1], S31
, 0xa4beea44); // 37
369 HH (d
, a
, b
, c
, x
[ 4], S32
, 0x4bdecfa9); // 38
370 HH (c
, d
, a
, b
, x
[ 7], S33
, 0xf6bb4b60); // 39
371 HH (b
, c
, d
, a
, x
[10], S34
, 0xbebfbc70); // 40
372 HH (a
, b
, c
, d
, x
[13], S31
, 0x289b7ec6); // 41
373 HH (d
, a
, b
, c
, x
[ 0], S32
, 0xeaa127fa); // 42
374 HH (c
, d
, a
, b
, x
[ 3], S33
, 0xd4ef3085); // 43
375 HH (b
, c
, d
, a
, x
[ 6], S34
, 0x4881d05); // 44
376 HH (a
, b
, c
, d
, x
[ 9], S31
, 0xd9d4d039); // 45
377 HH (d
, a
, b
, c
, x
[12], S32
, 0xe6db99e5); // 46
378 HH (c
, d
, a
, b
, x
[15], S33
, 0x1fa27cf8); // 47
379 HH (b
, c
, d
, a
, x
[ 2], S34
, 0xc4ac5665); // 48
382 II (a
, b
, c
, d
, x
[ 0], S41
, 0xf4292244); // 49
383 II (d
, a
, b
, c
, x
[ 7], S42
, 0x432aff97); // 50
384 II (c
, d
, a
, b
, x
[14], S43
, 0xab9423a7); // 51
385 II (b
, c
, d
, a
, x
[ 5], S44
, 0xfc93a039); // 52
386 II (a
, b
, c
, d
, x
[12], S41
, 0x655b59c3); // 53
387 II (d
, a
, b
, c
, x
[ 3], S42
, 0x8f0ccc92); // 54
388 II (c
, d
, a
, b
, x
[10], S43
, 0xffeff47d); // 55
389 II (b
, c
, d
, a
, x
[ 1], S44
, 0x85845dd1); // 56
390 II (a
, b
, c
, d
, x
[ 8], S41
, 0x6fa87e4f); // 57
391 II (d
, a
, b
, c
, x
[15], S42
, 0xfe2ce6e0); // 58
392 II (c
, d
, a
, b
, x
[ 6], S43
, 0xa3014314); // 59
393 II (b
, c
, d
, a
, x
[13], S44
, 0x4e0811a1); // 60
394 II (a
, b
, c
, d
, x
[ 4], S41
, 0xf7537e82); // 61
395 II (d
, a
, b
, c
, x
[11], S42
, 0xbd3af235); // 62
396 II (c
, d
, a
, b
, x
[ 2], S43
, 0x2ad7d2bb); // 63
397 II (b
, c
, d
, a
, x
[ 9], S44
, 0xeb86d391); // 64
405 // Encodes input (guint32) into output (unsigned char). Assumes len is a multiple of 4.
406 // ****************************************************************************
407 void CMD5Context::encode (uint8
*output
, const uint32
*input
, uint len
)
411 for (i
= 0, j
= 0; j
< len
; i
++, j
+= 4)
413 output
[j
] = (uint8
)(input
[i
] & 0xff);
414 output
[j
+1] = (uint8
)((input
[i
] >> 8) & 0xff);
415 output
[j
+2] = (uint8
)((input
[i
] >> 16) & 0xff);
416 output
[j
+3] = (uint8
)((input
[i
] >> 24) & 0xff);
420 // Decodes input (unsigned char) into output (guint32). Assumes len is a multiple of 4.
421 // ****************************************************************************
422 void CMD5Context::decode (uint32
*output
, const uint8
*input
, uint len
)
426 for (i
= 0, j
= 0; j
< len
; i
++, j
+= 4)
427 output
[i
] = ((uint32
)input
[j
]) | (((uint32
)input
[j
+1]) << 8) |
428 (((uint32
)input
[j
+2]) << 16) | (((uint32
)input
[j
+3]) << 24);
432 } // namespace NLMISC