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