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>
18
19namespace 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
30namespace digest_detail {
31
32static inline uint32_t min(uint32_t x, uint32_t y) {
33 return x < y ? x : y;
34}
35
36static 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
43static 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
48static 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
53static inline
54uint32_t F(const uint32_t& x, const uint32_t& y, const uint32_t& z) {
55 return (z ^ (x & (y ^ z)));
56}
57static inline
58uint32_t G(const uint32_t& x, const uint32_t& y, const uint32_t& z) {
59 return (y ^ (z & (y ^ x)));
60}
61static inline
62uint32_t H(const uint32_t& x, const uint32_t& y, const uint32_t& z) {
63 return (x ^ y ^ z);
64}
65static inline
66uint32_t I(const uint32_t& x, const uint32_t& y, const uint32_t& z) {
67 return (y ^ (x | (~z)));
68}
69
70static 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
76static 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
82static 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
88static 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
94static 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
101static 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
108static 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
124static 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
175MD5::MD5(const void* data, uint32_t size) : MD5() {
176 process(data, size);
177}
178
179MD5::MD5(const std::string& str) : MD5() {
180 process(str);
181}
182
183void 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
217void MD5::process(const std::string& str) {
218 return process(str.data(), str.size());
219}
220
221void 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
253std::string MD5::digest() {
254 std::string out(kDigestLength, '0');
255 finalize(const_cast<char*>(out.data()));
256 return out;
257}
258
259std::string MD5::digest_hex() {
260 uint8_t digest[kDigestLength];
263}
264
265std::string MD5::digest_hex_uc() {
266 uint8_t digest[kDigestLength];
269}
270
271std::string md5_hex(const void* data, uint32_t size) {
272 return MD5(data, size).digest_hex();
273}
274
275std::string md5_hex(const std::string& str) {
276 return MD5(str).digest_hex();
277}
278
279std::string md5_hex_uc(const void* data, uint32_t size) {
280 return MD5(data, size).digest_hex_uc();
281}
282
283std::string md5_hex_uc(const std::string& str) {
284 return MD5(str).digest_hex_uc();
285}
286
287} // namespace tlx
288
289/******************************************************************************/
MD-5 processor without external dependencies.
Definition: md5.hpp:29
uint32_t state_[4]
Definition: md5.hpp:58
void finalize(void *digest)
finalize computation and output 16 byte (128 bit) digest
Definition: md5.cpp:221
std::string digest_hex()
finalize computation and return 16 byte (128 bit) digest hex encoded
Definition: md5.cpp:259
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
void process(const void *data, uint32_t size)
process more data
Definition: md5.cpp:183
MD5()
construct empty object.
Definition: md5.cpp:166
static constexpr size_t kDigestLength
digest length in bytes
Definition: md5.hpp:44
uint64_t length_
Definition: md5.hpp:57
uint32_t curlen_
Definition: md5.hpp:59
uint8_t buf_[64]
Definition: md5.hpp:60
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
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 uint32_t rol32(const uint32_t &x, int i)
rol32 - generic
Definition: rol.hpp:55
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
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 const uint8_t Worder[64]
Definition: md5.cpp:94
static uint32_t min(uint32_t x, uint32_t y)
Definition: md5.cpp:32
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
static uint32_t F(const uint32_t &x, const uint32_t &y, const uint32_t &z)
Definition: md5.cpp:54
static const uint8_t Rorder[64]
Definition: md5.cpp:101
static const uint32_t Korder[64]
Definition: md5.cpp:108
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 md5_compress(uint32_t state[4], const uint8_t *buf)
Definition: md5.cpp:124
static uint32_t H(const uint32_t &x, const uint32_t &y, const uint32_t &z)
Definition: md5.cpp:62
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 load32l(const uint8_t *y)
Definition: md5.cpp:36
static uint32_t I(const uint32_t &x, const uint32_t &y, const uint32_t &z)
Definition: md5.cpp:66
static void store32l(uint32_t x, uint8_t *y)
Definition: md5.cpp:43
static uint32_t G(const uint32_t &x, const uint32_t &y, const uint32_t &z)
Definition: md5.cpp:58
static void store64l(uint64_t x, uint8_t *y)
Definition: md5.cpp:48
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