/src/botan/src/lib/hash/blake2s/blake2s.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * BLAKE2s |
3 | | * (C) 2023 Richard Huveneers |
4 | | * |
5 | | * Based on the RFC7693 reference implementation |
6 | | * |
7 | | * Botan is released under the Simplified BSD License (see license.txt) |
8 | | */ |
9 | | |
10 | | #include <botan/internal/blake2s.h> |
11 | | |
12 | | #include <botan/exceptn.h> |
13 | | #include <botan/internal/fmt.h> |
14 | | #include <botan/internal/loadstor.h> |
15 | | #include <botan/internal/rotate.h> |
16 | | |
17 | | namespace Botan { |
18 | | |
19 | | namespace { |
20 | | |
21 | | // Initialization Vector. |
22 | | |
23 | | const uint32_t blake2s_iv[8] = { |
24 | | 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19}; |
25 | | |
26 | | // Mixing function G. |
27 | | |
28 | 9.78M | inline void B2S_G(uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint32_t x, uint32_t y, uint32_t* v) { |
29 | 9.78M | v[a] = v[a] + v[b] + x; |
30 | 9.78M | v[d] = rotr<16>(v[d] ^ v[a]); |
31 | 9.78M | v[c] = v[c] + v[d]; |
32 | 9.78M | v[b] = rotr<12>(v[b] ^ v[c]); |
33 | 9.78M | v[a] = v[a] + v[b] + y; |
34 | 9.78M | v[d] = rotr<8>(v[d] ^ v[a]); |
35 | 9.78M | v[c] = v[c] + v[d]; |
36 | 9.78M | v[b] = rotr<7>(v[b] ^ v[c]); |
37 | 9.78M | } |
38 | | |
39 | | } // namespace |
40 | | |
41 | 7 | std::string BLAKE2s::name() const { |
42 | 7 | return fmt("BLAKE2s({})", m_outlen << 3); |
43 | 7 | } |
44 | | |
45 | | // Secret key (also <= 32 bytes) is optional (keylen = 0). |
46 | | // (keylen=0: no key) |
47 | | |
48 | 34.7k | void BLAKE2s::state_init(size_t outlen, const uint8_t* key, size_t keylen) { |
49 | 312k | for(size_t i = 0; i < 8; i++) { // state, "param block" |
50 | 277k | m_h[i] = blake2s_iv[i]; |
51 | 277k | } |
52 | 34.7k | m_h[0] ^= 0x01010000 ^ (keylen << 8) ^ outlen; |
53 | | |
54 | 34.7k | m_t[0] = 0; // input count low word |
55 | 34.7k | m_t[1] = 0; // input count high word |
56 | 34.7k | m_c = 0; // pointer within buffer |
57 | 34.7k | m_outlen = outlen; |
58 | | |
59 | 2.25M | for(size_t i = keylen; i < 64; i++) { // zero input block |
60 | 2.22M | m_b[i] = 0; |
61 | 2.22M | } |
62 | 34.7k | if(keylen > 0) { |
63 | 0 | add_data(std::span<const uint8_t>(key, keylen)); |
64 | 0 | m_c = 64; // at the end |
65 | 0 | } |
66 | 34.7k | } |
67 | | |
68 | | // Compression function. "last" flag indicates last block. |
69 | | |
70 | 122k | void BLAKE2s::compress(bool last) { |
71 | 122k | const uint8_t sigma[10][16] = {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, |
72 | 122k | {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, |
73 | 122k | {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4}, |
74 | 122k | {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8}, |
75 | 122k | {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13}, |
76 | 122k | {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9}, |
77 | 122k | {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11}, |
78 | 122k | {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10}, |
79 | 122k | {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5}, |
80 | 122k | {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0}}; |
81 | 122k | uint32_t v[16], m[16]; |
82 | | |
83 | 1.10M | for(size_t i = 0; i < 8; i++) { // init work variables |
84 | 978k | v[i] = m_h[i]; |
85 | 978k | v[i + 8] = blake2s_iv[i]; |
86 | 978k | } |
87 | | |
88 | 122k | v[12] ^= m_t[0]; // low 32 bits of offset |
89 | 122k | v[13] ^= m_t[1]; // high 32 bits |
90 | 122k | if(last) { // last block flag set ? |
91 | 34.0k | v[14] = ~v[14]; |
92 | 34.0k | } |
93 | 122k | load_le<uint32_t>(m, m_b, 16); // get little-endian words |
94 | | |
95 | 1.34M | for(size_t i = 0; i < 10; i++) { // ten rounds |
96 | 1.22M | B2S_G(0, 4, 8, 12, m[sigma[i][0]], m[sigma[i][1]], v); |
97 | 1.22M | B2S_G(1, 5, 9, 13, m[sigma[i][2]], m[sigma[i][3]], v); |
98 | 1.22M | B2S_G(2, 6, 10, 14, m[sigma[i][4]], m[sigma[i][5]], v); |
99 | 1.22M | B2S_G(3, 7, 11, 15, m[sigma[i][6]], m[sigma[i][7]], v); |
100 | 1.22M | B2S_G(0, 5, 10, 15, m[sigma[i][8]], m[sigma[i][9]], v); |
101 | 1.22M | B2S_G(1, 6, 11, 12, m[sigma[i][10]], m[sigma[i][11]], v); |
102 | 1.22M | B2S_G(2, 7, 8, 13, m[sigma[i][12]], m[sigma[i][13]], v); |
103 | 1.22M | B2S_G(3, 4, 9, 14, m[sigma[i][14]], m[sigma[i][15]], v); |
104 | 1.22M | } |
105 | | |
106 | 1.10M | for(size_t i = 0; i < 8; ++i) { |
107 | 978k | m_h[i] ^= v[i] ^ v[i + 8]; |
108 | 978k | } |
109 | 122k | } |
110 | | |
111 | | /* |
112 | | * Clear memory of sensitive data |
113 | | */ |
114 | 34.3k | void BLAKE2s::clear() { |
115 | 34.3k | state_init(m_outlen, nullptr, 0); |
116 | 34.3k | } |
117 | | |
118 | 124k | void BLAKE2s::add_data(std::span<const uint8_t> in) { |
119 | 6.68M | for(size_t i = 0; i < in.size(); i++) { |
120 | 6.56M | if(m_c == 64) { // buffer full ? |
121 | 88.2k | m_t[0] += m_c; // add counters |
122 | 88.2k | if(m_t[0] < m_c) { // carry overflow ? |
123 | 0 | m_t[1]++; // high word |
124 | 0 | } |
125 | 88.2k | compress(false); // compress (not last) |
126 | 88.2k | m_c = 0; // counter to zero |
127 | 88.2k | } |
128 | 6.56M | m_b[m_c++] = in[i]; |
129 | 6.56M | } |
130 | 124k | } |
131 | | |
132 | 34.0k | void BLAKE2s::final_result(std::span<uint8_t> out) { |
133 | 34.0k | m_t[0] += m_c; // mark last block offset |
134 | 34.0k | if(m_t[0] < m_c) { // carry overflow |
135 | 0 | m_t[1]++; // high word |
136 | 0 | } |
137 | | |
138 | 1.30M | while(m_c < 64) { // fill up with zeros |
139 | 1.27M | m_b[m_c++] = 0; |
140 | 1.27M | } |
141 | 34.0k | compress(true); // final block flag = 1 |
142 | | |
143 | | // little endian convert and store |
144 | 34.0k | copy_out_le<uint32_t>(out.data(), m_outlen, m_h); |
145 | | |
146 | 34.0k | clear(); |
147 | 34.0k | }; |
148 | | |
149 | 0 | std::unique_ptr<HashFunction> BLAKE2s::copy_state() const { |
150 | 0 | std::unique_ptr<BLAKE2s> h = std::make_unique<BLAKE2s>(m_outlen << 3); |
151 | 0 | memcpy(h->m_b, m_b, sizeof(m_b)); |
152 | 0 | memcpy(h->m_h, m_h, sizeof(m_h)); |
153 | 0 | memcpy(h->m_t, m_t, sizeof(m_t)); |
154 | 0 | h->m_c = m_c; |
155 | 0 | return h; |
156 | 0 | } |
157 | | |
158 | | /* |
159 | | * BLAKE2s Constructor |
160 | | */ |
161 | 374 | BLAKE2s::BLAKE2s(size_t output_bits) { |
162 | 374 | if(output_bits == 0 || output_bits > 256 || output_bits % 8 != 0) { |
163 | 0 | throw Invalid_Argument("Bad output bits size for BLAKE2s"); |
164 | 374 | }; |
165 | 374 | state_init(output_bits >> 3, nullptr, 0); |
166 | 374 | } |
167 | | |
168 | 374 | BLAKE2s::~BLAKE2s() { |
169 | 374 | secure_scrub_memory(m_b, sizeof(m_b)); |
170 | 374 | secure_scrub_memory(m_h, sizeof(m_h)); |
171 | 374 | secure_scrub_memory(m_t, sizeof(m_t)); |
172 | 374 | } |
173 | | |
174 | | } // namespace Botan |