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