Thrill  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
md5.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  * tlx/digest/md5.cpp
3  *
4  * Public domain implementation of MD-5 processor. Based on LibTomCrypt from
5  * https://github.com/libtom/libtomcrypt.git
6  *
7  * Part of tlx - http://panthema.net/tlx
8  *
9  * Copyright (C) 2018 Timo Bingmann <[email protected]>
10  *
11  * All rights reserved. Published under the Boost Software License, Version 1.0
12  ******************************************************************************/
13 
14 #include <tlx/digest/md5.hpp>
15 
16 #include <tlx/math/rol.hpp>
17 #include <tlx/string/hexdump.hpp>
18 
19 #include <algorithm>
20 
21 namespace tlx {
22 
23 /*
24  * LibTomCrypt, modular cryptographic library -- Tom St Denis
25  *
26  * LibTomCrypt is a library that provides various cryptographic algorithms in a
27  * highly modular and flexible manner.
28  *
29  * The library is free for all purposes without any express guarantee it works.
30  */
31 
32 typedef uint32_t u32;
33 typedef uint64_t u64;
34 
35 namespace {
36 
37 static inline u32 min(u32 x, u32 y) {
38  return x < y ? x : y;
39 }
40 
41 static inline u32 load32l(const uint8_t* y) {
42  u32 res = 0;
43  for (size_t i = 0; i != 4; ++i)
44  res |= u32(y[i]) << (i * 8);
45  return res;
46 }
47 
48 static inline void store32l(u32 x, uint8_t* y) {
49  for (size_t i = 0; i != 4; ++i)
50  y[i] = (x >> (i * 8)) & 255;
51 }
52 
53 static inline void store64l(u64 x, uint8_t* y) {
54  for (size_t i = 0; i != 8; ++i)
55  y[i] = (x >> (i * 8)) & 255;
56 }
57 
58 static inline u32 F(const u32& x, const u32& y, const u32& z) {
59  return (z ^ (x & (y ^ z)));
60 }
61 static inline u32 G(const u32& x, const u32& y, const u32& z) {
62  return (y ^ (z & (y ^ x)));
63 }
64 static inline u32 H(const u32& x, const u32& y, const u32& z) {
65  return (x ^ y ^ z);
66 }
67 static inline u32 I(const u32& x, const u32& y, const u32& z) {
68  return (y ^ (x | (~z)));
69 }
70 
71 static inline void FF(u32& a, u32& b, u32& c, u32& d, u32 M, u32 s, u32 t) {
72  a = (a + F(b, c, d) + M + t);
73  a = rol32(a, s) + b;
74 }
75 
76 static inline void GG(u32& a, u32& b, u32& c, u32& d, u32 M, u32 s, u32 t) {
77  a = (a + G(b, c, d) + M + t);
78  a = rol32(a, s) + b;
79 }
80 
81 static inline void HH(u32& a, u32& b, u32& c, u32& d, u32 M, u32 s, u32 t) {
82  a = (a + H(b, c, d) + M + t);
83  a = rol32(a, s) + b;
84 }
85 
86 static inline void II(u32& a, u32& b, u32& c, u32& d, u32 M, u32 s, u32 t) {
87  a = (a + I(b, c, d) + M + t);
88  a = rol32(a, s) + b;
89 }
90 
91 static const uint8_t Worder[64] = {
92  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
93  1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12,
94  5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2,
95  0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9
96 };
97 
98 static const uint8_t Rorder[64] = {
99  7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
100  5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
101  4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
102  6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21
103 };
104 
105 static const u32 Korder[64] = {
106  0xd76aa478UL, 0xe8c7b756UL, 0x242070dbUL, 0xc1bdceeeUL, 0xf57c0fafUL,
107  0x4787c62aUL, 0xa8304613UL, 0xfd469501UL, 0x698098d8UL, 0x8b44f7afUL,
108  0xffff5bb1UL, 0x895cd7beUL, 0x6b901122UL, 0xfd987193UL, 0xa679438eUL,
109  0x49b40821UL, 0xf61e2562UL, 0xc040b340UL, 0x265e5a51UL, 0xe9b6c7aaUL,
110  0xd62f105dUL, 0x02441453UL, 0xd8a1e681UL, 0xe7d3fbc8UL, 0x21e1cde6UL,
111  0xc33707d6UL, 0xf4d50d87UL, 0x455a14edUL, 0xa9e3e905UL, 0xfcefa3f8UL,
112  0x676f02d9UL, 0x8d2a4c8aUL, 0xfffa3942UL, 0x8771f681UL, 0x6d9d6122UL,
113  0xfde5380cUL, 0xa4beea44UL, 0x4bdecfa9UL, 0xf6bb4b60UL, 0xbebfbc70UL,
114  0x289b7ec6UL, 0xeaa127faUL, 0xd4ef3085UL, 0x04881d05UL, 0xd9d4d039UL,
115  0xe6db99e5UL, 0x1fa27cf8UL, 0xc4ac5665UL, 0xf4292244UL, 0x432aff97UL,
116  0xab9423a7UL, 0xfc93a039UL, 0x655b59c3UL, 0x8f0ccc92UL, 0xffeff47dUL,
117  0x85845dd1UL, 0x6fa87e4fUL, 0xfe2ce6e0UL, 0xa3014314UL, 0x4e0811a1UL,
118  0xf7537e82UL, 0xbd3af235UL, 0x2ad7d2bbUL, 0xeb86d391UL
119 };
120 
121 static void md5_compress(uint32_t state[4], const uint8_t* buf) {
122  u32 i, W[16], a, b, c, d, t;
123 
124  // copy the state into 512-bits into W[0..15]
125  for (i = 0; i < 16; i++) {
126  W[i] = load32l(buf + (4 * i));
127  }
128 
129  // copy state
130  a = state[0];
131  b = state[1];
132  c = state[2];
133  d = state[3];
134 
135  for (i = 0; i < 16; ++i) {
136  FF(a, b, c, d, W[Worder[i]], Rorder[i], Korder[i]);
137  t = d, d = c, c = b, b = a, a = t;
138  }
139 
140  for ( ; i < 32; ++i) {
141  GG(a, b, c, d, W[Worder[i]], Rorder[i], Korder[i]);
142  t = d, d = c, c = b, b = a, a = t;
143  }
144 
145  for ( ; i < 48; ++i) {
146  HH(a, b, c, d, W[Worder[i]], Rorder[i], Korder[i]);
147  t = d, d = c, c = b, b = a, a = t;
148  }
149 
150  for ( ; i < 64; ++i) {
151  II(a, b, c, d, W[Worder[i]], Rorder[i], Korder[i]);
152  t = d, d = c, c = b, b = a, a = t;
153  }
154 
155  state[0] = state[0] + a;
156  state[1] = state[1] + b;
157  state[2] = state[2] + c;
158  state[3] = state[3] + d;
159 }
160 
161 } // namespace
162 
164  curlen_ = 0;
165  length_ = 0;
166  state_[0] = 0x67452301UL;
167  state_[1] = 0xefcdab89UL;
168  state_[2] = 0x98badcfeUL;
169  state_[3] = 0x10325476UL;
170 }
171 
172 MD5::MD5(const void* data, uint32_t size)
173  : MD5() {
174  process(data, size);
175 }
176 
178  : MD5() {
179  process(str);
180 }
181 
182 void MD5::process(const void* data, u32 size) {
183  const u32 block_size = sizeof(MD5::buf_);
184  auto in = static_cast<const uint8_t*>(data);
185 
186  while (size > 0)
187  {
188  if (curlen_ == 0 && size >= block_size)
189  {
190  md5_compress(state_, in);
191  length_ += block_size * 8;
192  in += block_size;
193  size -= block_size;
194  }
195  else
196  {
197  u32 n = min(size, (block_size - curlen_));
198  std::copy(in, in + n, buf_ + curlen_);
199  curlen_ += n;
200  in += n;
201  size -= n;
202 
203  if (curlen_ == block_size)
204  {
205  md5_compress(state_, buf_);
206  length_ += 8 * block_size;
207  curlen_ = 0;
208  }
209  }
210  }
211 }
212 
213 void MD5::process(const std::string& str) {
214  return process(str.data(), str.size());
215 }
216 
217 void MD5::finalize(void* digest) {
218  // Increase the length of the message
219  length_ += curlen_ * 8;
220 
221  // Append the '1' bit
222  buf_[curlen_++] = static_cast<uint8_t>(0x80);
223 
224  // If the length_ is currently above 56 bytes we append zeros then
225  // md5_compress(). Then we can fall back to padding zeros and length
226  // encoding like normal.
227  if (curlen_ > 56) {
228  while (curlen_ < 64)
229  buf_[curlen_++] = 0;
230  md5_compress(state_, buf_);
231  curlen_ = 0;
232  }
233 
234  // Pad up to 56 bytes of zeroes
235  while (curlen_ < 56)
236  buf_[curlen_++] = 0;
237 
238  // Store length
239  store64l(length_, buf_ + 56);
240  md5_compress(state_, buf_);
241 
242  // Copy output
243  for (size_t i = 0; i < 4; i++)
244  store32l(state_[i], static_cast<uint8_t*>(digest) + (4 * i));
245 }
246 
248  std::string out(kDigestLength, '0');
249  finalize(const_cast<char*>(out.data()));
250  return out;
251 }
252 
254  uint8_t digest[kDigestLength];
255  finalize(digest);
256  return hexdump_lc(digest, kDigestLength);
257 }
258 
260  uint8_t digest[kDigestLength];
261  finalize(digest);
262  return hexdump(digest, kDigestLength);
263 }
264 
265 std::string md5_hex(const void* data, uint32_t size) {
266  return MD5(data, size).digest_hex();
267 }
268 
270  return MD5(str).digest_hex();
271 }
272 
273 std::string md5_hex_uc(const void* data, uint32_t size) {
274  return MD5(data, size).digest_hex_uc();
275 }
276 
278  return MD5(str).digest_hex_uc();
279 }
280 
281 } // namespace tlx
282 
283 /******************************************************************************/
std::string md5_hex_uc(const void *data, uint32_t size)
process data and return 16 byte (128 bit) digest upper-case hex encoded
Definition: md5.cpp:273
uint8_t buf_[64]
Definition: md5.hpp:60
uint32_t state_[4]
Definition: md5.hpp:58
std::string digest_hex()
finalize computation and return 16 byte (128 bit) digest hex encoded
Definition: md5.cpp:253
void process(const void *data, uint32_t size)
process more data
Definition: md5.cpp:182
uint64_t u64
Definition: md5.cpp:33
std::string hexdump_lc(const void *const data, size_t size)
Dump a (binary) string as a sequence of lowercase hexadecimal pairs.
Definition: hexdump.cpp:95
uint64_t length_
Definition: md5.hpp:57
std::string digest()
finalize computation and return 16 byte (128 bit) digest
Definition: md5.cpp:247
std::string digest_hex_uc()
finalize computation and return 16 byte (128 bit) digest upper-case hex
Definition: md5.cpp:259
list x
Definition: gen_data.py:39
uint32_t curlen_
Definition: md5.hpp:59
std::basic_string< char, std::char_traits< char >, Allocator< char > > string
string with Manager tracking
Definition: allocator.hpp:220
static uint32_t rol32(const uint32_t &x, int i)
rol32 - generic
Definition: rol.hpp:55
static uint_pair min()
return an uint_pair instance containing the smallest value possible
Definition: uint_types.hpp:217
uint32_t u32
Definition: md5.cpp:32
std::string hexdump(const void *const data, size_t size)
Dump a (binary) string as a sequence of uppercase hexadecimal pairs.
Definition: hexdump.cpp:21
MD5()
construct empty object.
Definition: md5.cpp:163
static constexpr size_t kDigestLength
digest length in bytes
Definition: md5.hpp:44
std::string md5_hex(const void *data, uint32_t size)
process data and return 16 byte (128 bit) digest hex encoded
Definition: md5.cpp:265
void finalize(void *digest)
finalize computation and output 16 byte (128 bit) digest
Definition: md5.cpp:217
MD-5 processor without external dependencies.
Definition: md5.hpp:28