libsidplayfp 3.0.0
md5.hpp
1#ifndef HASHLIB_ALL_IN_ONE
2#pragma once
3#include "core.hpp"
4#endif
5
6namespace hashlib {
7 namespace detail {
8 class md5 {
9 public:
10 static constexpr std::size_t digest_size = 16;
11
12 public:
13 auto update(span<const byte> bytes) noexcept -> void {
14 update(bytes.begin(), bytes.end());
15 }
16
17 template<typename InputIt, typename Sentinel, enable_if_t<
18 is_input_iterator<InputIt>::value &&
19 !is_random_access_iterator<InputIt>::value &&
20 is_sentinel_for<Sentinel, InputIt>::value &&
21 is_byte_like<iter_value_t<InputIt>>::value
22 >* = nullptr>
23 auto update(InputIt first, Sentinel last) -> void {
24 byte temp[128];
25 for (auto it = first; it != last;) {
26 std::size_t n = 0;
27 for (; it != last && n < sizeof(temp); ++it, ++n) {
28 temp[n] = static_cast<byte>(*it);
29 }
30 update({temp, n});
31 }
32 }
33
34 template<typename RandomAccessIt, typename Sentinel, enable_if_t<
35 is_random_access_iterator<RandomAccessIt>::value &&
36 is_sentinel_for<Sentinel, RandomAccessIt>::value &&
37 is_byte_like<iter_value_t<RandomAccessIt>>::value
38 >* = nullptr>
39 auto update(RandomAccessIt first, Sentinel last) -> void {
40 std::size_t bytes_count = last - first;
41 total_size_ += bytes_count;
42 std::size_t i = 0;
43
44 if (buffer_size_ > 0) {
45 std::size_t to_copy = std::min(bytes_count, 64 - buffer_size_);
46 std::copy_n(first, to_copy, buffer_.data() + buffer_size_);
47 buffer_size_ += to_copy;
48 i += to_copy;
49 if (buffer_size_ == 64) {
50 process_(w_table_(buffer_.data()));
51 buffer_size_ = 0;
52 }
53 }
54
55 for (; i + 63 < bytes_count; i += 64) {
56 (process_)((w_table_)(std::next(first, i)));
57 }
58
59 if (i < bytes_count) {
60 std::copy_n(std::next(first, i), bytes_count - i, buffer_.data());
61 buffer_size_ = bytes_count - i;
62 }
63 }
64
65 protected:
66 auto do_digest() noexcept -> std::array<std::uint32_t, 4> {
67 auto_restorer<md5> _{*this};
68 auto buffer_size = buffer_size_;
69 auto total_size = total_size_;
70 byte padding[128]{};
71 padding[0] = 0x80;
72 std::size_t padding_size = (buffer_size < 56) ? (56 - buffer_size) : (120 - buffer_size);
73 update({padding, padding_size});
74 std::uint64_t bits = total_size * 8;
75 for (std::size_t i = 0; i < 8; ++i) padding[i] = (bits >> (8 * i)) & 0xff;
76 update({padding, 8});
77 return {a_, b_, c_, d_};
78 }
79
80 HASHLIB_ALWAYS_INLINE
81 static auto unit_to_bytes(std::uint32_t unit) noexcept -> std::array<byte, 4> {
82 byte* byte_ptr = reinterpret_cast<byte*>(&unit);
83 if HASHLIB_CXX17_CONSTEXPR (is_little_endian()) {
84 return {byte_ptr[0], byte_ptr[1], byte_ptr[2], byte_ptr[3]};
85 }
86 else {
87 return {byte_ptr[3], byte_ptr[2], byte_ptr[1], byte_ptr[0]};
88 }
89 }
90
91 private:
92 auto process_(const std::array<std::uint32_t, 16>& w) noexcept -> void {
93 static constexpr std::uint32_t K[64]{
94 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
95 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
96 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
97 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
98 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
99 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
100 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
101 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
102 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
103 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
104 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
105 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
106 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
107 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
108 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
109 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
110 };
111 static constexpr std::uint32_t S[16]{7, 12, 17, 22, 5, 9, 14, 20, 4, 11, 16, 23, 6, 10, 15, 21};
112
113 std::uint32_t a = a_, b = b_, c = c_, d = d_;
114 for (std::size_t i = 0; i < 64; ++i) {
115 std::uint32_t F, g, cnt;
116 if (i < 16) {
117 F = (b & c) | ((~b) & d);
118 g = i;
119 cnt = S[i % 4];
120 }
121 else if (i < 32) {
122 F = (d & b) | ((~d) & c);
123 g = (5 * i + 1) % 16;
124 cnt = S[4 + i % 4];
125 }
126 else if (i < 48) {
127 F = b ^ c ^ d;
128 g = (3 * i + 5) % 16;
129 cnt = S[8 + i % 4];
130 }
131 else {
132 F = c ^ (b | (~d));
133 g = (7 * i) % 16;
134 cnt = S[12 + i % 4];
135 }
136 F = F + a + K[i] + w[g];
137 a = d;
138 d = c;
139 c = b;
140 b = b + ((F << cnt) | (F >> (32 - cnt)));
141 }
142 a_ += a;
143 b_ += b;
144 c_ += c;
145 d_ += d;
146 }
147
148 template<typename RandomAccessIt>
149 static auto w_table_(RandomAccessIt it) noexcept -> std::array<std::uint32_t, 16> {
150 static_assert(is_random_access_iterator<RandomAccessIt>::value, "unexpected");
151 std::array<std::uint32_t, 16> w; // NOLINT(*-pro-type-member-init)
152 for (std::size_t i = 0; i < 16; ++i) {
153 w[i] = (std::uint32_t(it[i * 4])) |
154 (std::uint32_t(it[i * 4 + 1]) << 8) |
155 (std::uint32_t(it[i * 4 + 2]) << 16) |
156 (std::uint32_t(it[i * 4 + 3]) << 24);
157 }
158 return w;
159 }
160
161 private:
162 std::array<byte, 64> buffer_{};
163 std::size_t buffer_size_ = 0;
164 std::uint64_t total_size_ = 0;
165 std::uint32_t a_ = 0x67452301, b_ = 0xefcdab89, c_ = 0x98badcfe, d_ = 0x10325476;
166 };
167 }
168
169 HASHLIB_MOD_EXPORT using md5 = context<detail::md5>;
170}
Definition core.hpp:434
Definition core.hpp:396
Definition md5.hpp:8
Definition core.hpp:241