xoreos  0.0.5
md5.cpp
Go to the documentation of this file.
1 /* xoreos - A reimplementation of BioWare's Aurora engine
2  *
3  * xoreos is the legal property of its developers, whose names
4  * can be found in the AUTHORS file distributed with this source
5  * distribution.
6  *
7  * xoreos is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 3
10  * of the License, or (at your option) any later version.
11  *
12  * xoreos is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with xoreos. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
25 #include <cstring>
26 
27 #include "src/common/md5.h"
28 #include "src/common/ustring.h"
29 #include "src/common/readstream.h"
30 
31 namespace Common {
32 
33 /* .--- MD5, based on the implementation by Alexander Peslyak ---.
34  *
35  * This is an MD5 digesting implementation based on the implementation by
36  * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>.
37  * Alexander Peslyak's implementation was released to the public domain.
38  *
39  * <http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5>
40  *
41  * The original copyright note on md5.c reads as follows:
42  *
43  * This software was written by Alexander Peslyak in 2001. No copyright is
44  * claimed, and the software is hereby placed in the public domain.
45  * In case this attempt to disclaim copyright and place the software in the
46  * public domain is deemed null and void, then the software is
47  * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
48  * general public under the following terms:
49  *
50  * Redistribution and use in source and binary forms, with or without
51  * modification, are permitted.
52  *
53  * There's ABSOLUTELY NO WARRANTY, express or implied.
54  *
55  * (This is a heavily cut-down "BSD license".)
56  *
57  * This differs from Colin Plumb's older public domain implementation in that
58  * no exactly 32-bit integer data type is required (any 32-bit or wider
59  * unsigned integer data type will do), there's no compile-time endianness
60  * configuration, and the function prototypes match OpenSSL's. No code from
61  * Colin Plumb's implementation has been reused; this comment merely compares
62  * the properties of the two independent implementations.
63  *
64  * The primary goals of this implementation are portability and ease of use.
65  * It is meant to be fast, but not as fast as possible. Some known
66  * optimizations are not included to reduce source code size and avoid
67  * compile-time configuration.
68  */
69 struct MD5Context {
71  uint32 a, b, c, d;
72  byte buffer[64];
74 
75  MD5Context() : lo(0), hi(0), a(0x67452301), b(0xEFCDAB89), c(0x98BADCFE), d(0x10325476) {
76  }
77 
79  /* We don't care about security here, so we do *not* zeroize the buffers.
80  * Residuals of the hashing *will* be left in memory!
81  *
82  * WARNING: DO NOT USE THIS CODE IN SECURITY RELEVANT SITUATIONS!
83  */
84  }
85 };
86 
87 /*
88  * The basic MD5 functions.
89  *
90  * F and G are optimized compared to their RFC 1321 definitions for
91  * architectures that lack an AND-NOT instruction, just like in Colin Plumb's
92  * implementation.
93  */
94 #define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
95 #define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
96 #define H(x, y, z) (((x) ^ (y)) ^ (z))
97 #define H2(x, y, z) ((x) ^ ((y) ^ (z)))
98 #define I(x, y, z) ((y) ^ ((x) | ~(z)))
99 
100 /*
101  * The MD5 transformation for all four rounds.
102  */
103 #define STEP(f, a, b, c, d, x, t, s) \
104  (a) += f((b), (c), (d)) + (x) + (t); \
105  (a) = (((a) << (s)) | (((a) & 0xFFFFFFFF) >> (32 - (s)))); \
106  (a) += (b);
107 
108 /*
109  * SET reads 4 input bytes in little-endian byte order and stores them
110  * in a properly aligned word in host byte order.
111  *
112  * The check for little-endian architectures that tolerate unaligned
113  * memory accesses is just an optimization. Nothing will break if it
114  * doesn't work.
115  */
116 #if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
117 #define SET(n) \
118  (*const_cast<uint32 *>(reinterpret_cast<const uint32 *>(&ptr[(n) * 4])))
119 #define GET(n) \
120  SET(n)
121 #else
122 #define SET(n) \
123  (ctx.block[(n)] = \
124  (uint32)ptr[(n) * 4] | \
125  ((uint32)ptr[(n) * 4 + 1] << 8) | \
126  ((uint32)ptr[(n) * 4 + 2] << 16) | \
127  ((uint32)ptr[(n) * 4 + 3] << 24))
128 #define GET(n) \
129  (ctx.block[(n)])
130 #endif
131 
132 /*
133  * This processes one or more 64-byte data blocks, but does NOT update
134  * the bit counters. There are no alignment requirements.
135  */
136 static const byte *md5Body(MD5Context &ctx, const byte *data, size_t size) {
137  uint32 a = ctx.a;
138  uint32 b = ctx.b;
139  uint32 c = ctx.c;
140  uint32 d = ctx.d;
141 
142  const byte *ptr = data;
143 
144  do {
145  uint32 saved_a = a;
146  uint32 saved_b = b;
147  uint32 saved_c = c;
148  uint32 saved_d = d;
149 
150 /* Round 1 */
151  STEP(F, a, b, c, d, SET(0), 0xD76AA478, 7)
152  STEP(F, d, a, b, c, SET(1), 0xE8C7B756, 12)
153  STEP(F, c, d, a, b, SET(2), 0x242070DB, 17)
154  STEP(F, b, c, d, a, SET(3), 0xC1BDCEEE, 22)
155  STEP(F, a, b, c, d, SET(4), 0xF57C0FAF, 7)
156  STEP(F, d, a, b, c, SET(5), 0x4787C62A, 12)
157  STEP(F, c, d, a, b, SET(6), 0xA8304613, 17)
158  STEP(F, b, c, d, a, SET(7), 0xFD469501, 22)
159  STEP(F, a, b, c, d, SET(8), 0x698098D8, 7)
160  STEP(F, d, a, b, c, SET(9), 0x8B44F7AF, 12)
161  STEP(F, c, d, a, b, SET(10), 0xFFFF5BB1, 17)
162  STEP(F, b, c, d, a, SET(11), 0x895CD7BE, 22)
163  STEP(F, a, b, c, d, SET(12), 0x6B901122, 7)
164  STEP(F, d, a, b, c, SET(13), 0xFD987193, 12)
165  STEP(F, c, d, a, b, SET(14), 0xA679438E, 17)
166  STEP(F, b, c, d, a, SET(15), 0x49B40821, 22)
167 
168 /* Round 2 */
169  STEP(G, a, b, c, d, GET(1), 0xF61E2562, 5)
170  STEP(G, d, a, b, c, GET(6), 0xC040B340, 9)
171  STEP(G, c, d, a, b, GET(11), 0x265E5A51, 14)
172  STEP(G, b, c, d, a, GET(0), 0xE9B6C7AA, 20)
173  STEP(G, a, b, c, d, GET(5), 0xD62F105D, 5)
174  STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
175  STEP(G, c, d, a, b, GET(15), 0xD8A1E681, 14)
176  STEP(G, b, c, d, a, GET(4), 0xE7D3FBC8, 20)
177  STEP(G, a, b, c, d, GET(9), 0x21E1CDE6, 5)
178  STEP(G, d, a, b, c, GET(14), 0xC33707D6, 9)
179  STEP(G, c, d, a, b, GET(3), 0xF4D50D87, 14)
180  STEP(G, b, c, d, a, GET(8), 0x455A14ED, 20)
181  STEP(G, a, b, c, d, GET(13), 0xA9E3E905, 5)
182  STEP(G, d, a, b, c, GET(2), 0xFCEFA3F8, 9)
183  STEP(G, c, d, a, b, GET(7), 0x676F02D9, 14)
184  STEP(G, b, c, d, a, GET(12), 0x8D2A4C8A, 20)
185 
186 /* Round 3 */
187  STEP(H, a, b, c, d, GET(5), 0xFFFA3942, 4)
188  STEP(H2, d, a, b, c, GET(8), 0x8771F681, 11)
189  STEP(H, c, d, a, b, GET(11), 0x6D9D6122, 16)
190  STEP(H2, b, c, d, a, GET(14), 0xFDE5380C, 23)
191  STEP(H, a, b, c, d, GET(1), 0xA4BEEA44, 4)
192  STEP(H2, d, a, b, c, GET(4), 0x4BDECFA9, 11)
193  STEP(H, c, d, a, b, GET(7), 0xF6BB4B60, 16)
194  STEP(H2, b, c, d, a, GET(10), 0xBEBFBC70, 23)
195  STEP(H, a, b, c, d, GET(13), 0x289B7EC6, 4)
196  STEP(H2, d, a, b, c, GET(0), 0xEAA127FA, 11)
197  STEP(H, c, d, a, b, GET(3), 0xD4EF3085, 16)
198  STEP(H2, b, c, d, a, GET(6), 0x04881D05, 23)
199  STEP(H, a, b, c, d, GET(9), 0xD9D4D039, 4)
200  STEP(H2, d, a, b, c, GET(12), 0xE6DB99E5, 11)
201  STEP(H, c, d, a, b, GET(15), 0x1FA27CF8, 16)
202  STEP(H2, b, c, d, a, GET(2), 0xC4AC5665, 23)
203 
204 /* Round 4 */
205  STEP(I, a, b, c, d, GET(0), 0xF4292244, 6)
206  STEP(I, d, a, b, c, GET(7), 0x432AFF97, 10)
207  STEP(I, c, d, a, b, GET(14), 0xAB9423A7, 15)
208  STEP(I, b, c, d, a, GET(5), 0xFC93A039, 21)
209  STEP(I, a, b, c, d, GET(12), 0x655B59C3, 6)
210  STEP(I, d, a, b, c, GET(3), 0x8F0CCC92, 10)
211  STEP(I, c, d, a, b, GET(10), 0xFFEFF47D, 15)
212  STEP(I, b, c, d, a, GET(1), 0x85845DD1, 21)
213  STEP(I, a, b, c, d, GET(8), 0x6FA87E4F, 6)
214  STEP(I, d, a, b, c, GET(15), 0xFE2CE6E0, 10)
215  STEP(I, c, d, a, b, GET(6), 0xA3014314, 15)
216  STEP(I, b, c, d, a, GET(13), 0x4E0811A1, 21)
217  STEP(I, a, b, c, d, GET(4), 0xF7537E82, 6)
218  STEP(I, d, a, b, c, GET(11), 0xBD3AF235, 10)
219  STEP(I, c, d, a, b, GET(2), 0x2AD7D2BB, 15)
220  STEP(I, b, c, d, a, GET(9), 0xEB86D391, 21)
221 
222  a += saved_a;
223  b += saved_b;
224  c += saved_c;
225  d += saved_d;
226 
227  ptr += 64;
228  } while (size -= 64);
229 
230  ctx.a = a;
231  ctx.b = b;
232  ctx.c = c;
233  ctx.d = d;
234 
235  return ptr;
236 }
237 
238 static void md5Update(MD5Context &ctx, const byte *data, size_t size) {
239  uint32 saved_lo = ctx.lo;
240  if ((ctx.lo = (saved_lo + size) & 0x1FFFFFFF) < saved_lo)
241  ctx.hi++;
242  ctx.hi += size >> 29;
243 
244  size_t used = saved_lo & 0x3F;
245 
246  if (used) {
247  size_t available = 64 - used;
249  if (size < available) {
250  std::memcpy(&ctx.buffer[used], data, size);
251  return;
252  }
253 
254  std::memcpy(&ctx.buffer[used], data, available);
255  data = data + available;
256  size -= available;
257  md5Body(ctx, ctx.buffer, 64);
258  }
259 
260  if (size >= 64) {
261  data = md5Body(ctx, data, size & ~(size_t)0x3F);
262  size &= 0x3F;
263  }
264 
265  std::memcpy(ctx.buffer, data, size);
266 }
267 
268 static void md5Final(byte *result, MD5Context &ctx) {
269  size_t used = ctx.lo & 0x3F;
270 
271  ctx.buffer[used++] = 0x80;
272 
273  size_t available = 64 - used;
274 
275  if (available < 8) {
276  std::memset(&ctx.buffer[used], 0, available);
277  md5Body(ctx, ctx.buffer, 64);
278  used = 0;
279  available = 64;
280  }
281 
282  std::memset(&ctx.buffer[used], 0, available - 8);
283 
284  ctx.lo <<= 3;
285  ctx.buffer[56] = ctx.lo;
286  ctx.buffer[57] = ctx.lo >> 8;
287  ctx.buffer[58] = ctx.lo >> 16;
288  ctx.buffer[59] = ctx.lo >> 24;
289  ctx.buffer[60] = ctx.hi;
290  ctx.buffer[61] = ctx.hi >> 8;
291  ctx.buffer[62] = ctx.hi >> 16;
292  ctx.buffer[63] = ctx.hi >> 24;
293 
294  md5Body(ctx, ctx.buffer, 64);
295 
296  result[0] = ctx.a;
297  result[1] = ctx.a >> 8;
298  result[2] = ctx.a >> 16;
299  result[3] = ctx.a >> 24;
300  result[4] = ctx.b;
301  result[5] = ctx.b >> 8;
302  result[6] = ctx.b >> 16;
303  result[7] = ctx.b >> 24;
304  result[8] = ctx.c;
305  result[9] = ctx.c >> 8;
306  result[10] = ctx.c >> 16;
307  result[11] = ctx.c >> 24;
308  result[12] = ctx.d;
309  result[13] = ctx.d >> 8;
310  result[14] = ctx.d >> 16;
311  result[15] = ctx.d >> 24;
312 }
313 // '--- MD5, based on the implementation by Alexander Peslyak ---'
314 
315 
316 void hashMD5(ReadStream &stream, std::vector<byte> &digest) {
317  MD5Context ctx;
318 
319  byte buf[4096];
320  while (!stream.eos()) {
321  size_t bufRead = stream.read(buf, 4096);
322 
323  md5Update(ctx, buf, bufRead);
324  }
325 
326  digest.resize(kMD5Length);
327  md5Final(&digest[0], ctx);
328 }
329 
330 void hashMD5(const byte *data, size_t dataLength, std::vector<byte> &digest) {
331  MD5Context ctx;
332 
333  md5Update(ctx, data, dataLength);
334 
335  digest.resize(kMD5Length);
336  md5Final(&digest[0], ctx);
337 }
338 
339 void hashMD5(const UString &string, std::vector<byte> &digest) {
340  hashMD5(reinterpret_cast<const byte *>(string.c_str()), std::strlen(string.c_str()), digest);
341 }
342 
343 void hashMD5(const std::vector<byte> &data, std::vector<byte> &digest) {
344  hashMD5(&data[0], data.size(), digest);
345 }
346 
347 
348 bool compareMD5Digest(ReadStream &stream, const std::vector<byte> &digest) {
349  if (digest.size() != kMD5Length)
350  return false;
351 
352  std::vector<byte> newDigest;
353  hashMD5(stream, newDigest);
354 
355  return std::memcmp(&digest[0], &newDigest[0], kMD5Length) == 0;
356 }
357 
358 bool compareMD5Digest(const byte *data, size_t dataLength, const std::vector<byte> &digest) {
359  if (digest.size() != kMD5Length)
360  return false;
361 
362  std::vector<byte> newDigest;
363  hashMD5(data, dataLength, newDigest);
364 
365  return std::memcmp(&digest[0], &newDigest[0], kMD5Length) == 0;
366 }
367 
368 bool compareMD5Digest(const UString &string, const std::vector<byte> &digest) {
369  return compareMD5Digest(reinterpret_cast<const byte *>(string.c_str()), std::strlen(string.c_str()), digest);
370 }
371 
372 bool compareMD5Digest(const std::vector<byte> &data, const std::vector<byte> &digest) {
373  return compareMD5Digest(&data[0], data.size(), digest);
374 }
375 
376 } // End of namespace Common
void hashMD5(ReadStream &stream, std::vector< byte > &digest)
Hash the stream into an MD5 digest of 16 bytes.
Definition: md5.cpp:248
Definition: 2dafile.h:39
static void md5Update(MD5Context &ctx, const byte *data, size_t size)
Definition: md5.cpp:170
uint32 block[16]
Definition: md5.cpp:73
static const byte * md5Body(MD5Context &ctx, const byte *data, size_t size)
Definition: md5.cpp:136
#define GET(n)
Definition: md5.cpp:128
#define H2(x, y, z)
Definition: md5.cpp:97
#define SET(n)
Definition: md5.cpp:122
Basic reading stream interfaces.
bool compareMD5Digest(ReadStream &stream, const std::vector< byte > &digest)
Hash the stream and compare the digests, returning true if they match.
Definition: md5.cpp:280
Unicode string handling.
byte buffer[64]
Definition: md5.cpp:72
#define I(x, y, z)
Definition: md5.cpp:98
uint32_t uint32
Definition: types.h:204
#define H(x, y, z)
Definition: md5.cpp:96
static void md5Final(byte *result, MD5Context &ctx)
Definition: md5.cpp:200
Hashing/digesting using the MD5 algorithm.
static const size_t kMD5Length
The length of an MD5 digest in bytes.
Definition: md5.h:38
#define STEP(f, a, b, c, d, x, t, s)
Definition: md5.cpp:103
uint8 byte
Definition: types.h:209
static uint32 F(const BlowfishContext &ctx, uint32 x)
Definition: blowfish.cpp:235
#define G(x, y, z)
Definition: md5.cpp:95