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