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