Botan 3.0.0-alpha0
Crypto and TLS for C&
blake2b.cpp
Go to the documentation of this file.
1/*
2* BLAKE2b
3* (C) 2016 cynecx
4* (C) 2017 Jack Lloyd
5*
6* Botan is released under the Simplified BSD License (see license.txt)
7*/
8
9#include <botan/internal/blake2b.h>
10#include <botan/exceptn.h>
11#include <botan/mem_ops.h>
12#include <botan/internal/loadstor.h>
13#include <botan/internal/rotate.h>
14#include <algorithm>
15
16namespace Botan {
17
18namespace {
19
20enum blake2b_constant {
21 BLAKE2B_BLOCKBYTES = 128,
22 BLAKE2B_IVU64COUNT = 8
23};
24
25const uint64_t blake2b_IV[BLAKE2B_IVU64COUNT] = {
26 0x6a09e667f3bcc908, 0xbb67ae8584caa73b,
27 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
28 0x510e527fade682d1, 0x9b05688c2b3e6c1f,
29 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179
30};
31
32}
33
34BLAKE2b::BLAKE2b(size_t output_bits) :
35 m_output_bits(output_bits),
36 m_buffer(BLAKE2B_BLOCKBYTES),
37 m_bufpos(0),
38 m_H(BLAKE2B_IVU64COUNT),
39 m_T(),
40 m_F(),
41 m_key_size(0)
42 {
43 if(output_bits == 0 || output_bits > 512 || output_bits % 8 != 0)
44 {
45 throw Invalid_Argument("Bad output bits size for BLAKE2b");
46 }
47
48 state_init();
49 }
50
51void BLAKE2b::state_init()
52 {
53 copy_mem(m_H.data(), blake2b_IV, BLAKE2B_IVU64COUNT);
54 m_H[0] ^= (0x01010000 | (static_cast<uint8_t>(m_key_size) << 8) | static_cast<uint8_t>(output_length()));
55 m_T[0] = m_T[1] = 0;
56 m_F[0] = m_F[1] = 0;
57
58 if(m_key_size == 0)
59 {
60 m_bufpos = 0;
61 }
62 else
63 {
64 BOTAN_ASSERT_NOMSG(m_padded_key_buffer.size() == m_buffer.size());
65 copy_mem(m_buffer.data(), m_padded_key_buffer.data(), m_padded_key_buffer.size());
66 m_bufpos = m_padded_key_buffer.size();
67 }
68 }
69
70namespace {
71
72BOTAN_FORCE_INLINE void G(uint64_t& a, uint64_t& b, uint64_t& c, uint64_t& d,
73 uint64_t M0, uint64_t M1)
74 {
75 a = a + b + M0;
76 d = rotr<32>(d ^ a);
77 c = c + d;
78 b = rotr<24>(b ^ c);
79 a = a + b + M1;
80 d = rotr<16>(d ^ a);
81 c = c + d;
82 b = rotr<63>(b ^ c);
83 }
84
85template<size_t i0, size_t i1, size_t i2, size_t i3, size_t i4, size_t i5, size_t i6, size_t i7,
86 size_t i8, size_t i9, size_t iA, size_t iB, size_t iC, size_t iD, size_t iE, size_t iF>
87BOTAN_FORCE_INLINE void ROUND(uint64_t* v, const uint64_t* M)
88 {
89 G(v[ 0], v[ 4], v[ 8], v[12], M[i0], M[i1]);
90 G(v[ 1], v[ 5], v[ 9], v[13], M[i2], M[i3]);
91 G(v[ 2], v[ 6], v[10], v[14], M[i4], M[i5]);
92 G(v[ 3], v[ 7], v[11], v[15], M[i6], M[i7]);
93 G(v[ 0], v[ 5], v[10], v[15], M[i8], M[i9]);
94 G(v[ 1], v[ 6], v[11], v[12], M[iA], M[iB]);
95 G(v[ 2], v[ 7], v[ 8], v[13], M[iC], M[iD]);
96 G(v[ 3], v[ 4], v[ 9], v[14], M[iE], M[iF]);
97 }
98
99
100}
101
102void BLAKE2b::compress(const uint8_t* input, size_t blocks, uint64_t increment)
103 {
104 for(size_t b = 0; b != blocks; ++b)
105 {
106 m_T[0] += increment;
107 if(m_T[0] < increment)
108 {
109 m_T[1]++;
110 }
111
112 uint64_t M[16];
113 uint64_t v[16];
114 load_le(M, input, 16);
115
116 input += BLAKE2B_BLOCKBYTES;
117
118 for(size_t i = 0; i < 8; i++)
119 v[i] = m_H[i];
120 for(size_t i = 0; i != 8; ++i)
121 v[i + 8] = blake2b_IV[i];
122
123 v[12] ^= m_T[0];
124 v[13] ^= m_T[1];
125 v[14] ^= m_F[0];
126 v[15] ^= m_F[1];
127
128 ROUND< 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15>(v, M);
129 ROUND<14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3>(v, M);
130 ROUND<11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4>(v, M);
131 ROUND< 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8>(v, M);
132 ROUND< 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13>(v, M);
133 ROUND< 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9>(v, M);
134 ROUND<12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11>(v, M);
135 ROUND<13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10>(v, M);
136 ROUND< 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5>(v, M);
137 ROUND<10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0>(v, M);
138 ROUND< 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15>(v, M);
139 ROUND<14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3>(v, M);
140
141 for(size_t i = 0; i < 8; i++)
142 {
143 m_H[i] ^= v[i] ^ v[i + 8];
144 }
145 }
146 }
147
148void BLAKE2b::add_data(const uint8_t input[], size_t length)
149 {
150 if(length == 0)
151 return;
152
153 if(m_bufpos > 0)
154 {
155 if(m_bufpos < BLAKE2B_BLOCKBYTES)
156 {
157 const size_t take = std::min(BLAKE2B_BLOCKBYTES - m_bufpos, length);
158 copy_mem(&m_buffer[m_bufpos], input, take);
159 m_bufpos += take;
160 length -= take;
161 input += take;
162 }
163
164 if(m_bufpos == m_buffer.size() && length > 0)
165 {
166 compress(m_buffer.data(), 1, BLAKE2B_BLOCKBYTES);
167 m_bufpos = 0;
168 }
169 }
170
171 if(length > BLAKE2B_BLOCKBYTES)
172 {
173 const size_t full_blocks = ((length-1) / BLAKE2B_BLOCKBYTES);
174 compress(input, full_blocks, BLAKE2B_BLOCKBYTES);
175
176 input += full_blocks * BLAKE2B_BLOCKBYTES;
177 length -= full_blocks * BLAKE2B_BLOCKBYTES;
178 }
179
180 if(length > 0)
181 {
182 copy_mem(&m_buffer[m_bufpos], input, length);
183 m_bufpos += length;
184 }
185 }
186
187void BLAKE2b::final_result(uint8_t output[])
188 {
189 if(m_bufpos != BLAKE2B_BLOCKBYTES)
190 clear_mem(&m_buffer[m_bufpos], BLAKE2B_BLOCKBYTES - m_bufpos);
191 m_F[0] = 0xFFFFFFFFFFFFFFFF;
192 compress(m_buffer.data(), 1, m_bufpos);
193 copy_out_vec_le(output, output_length(), m_H);
194 state_init();
195 }
196
198 {
199 return Key_Length_Specification(0, 64);
200 }
201
202std::string BLAKE2b::name() const
203 {
204 return "BLAKE2b(" + std::to_string(m_output_bits) + ")";
205 }
206
207std::unique_ptr<HashFunction> BLAKE2b::new_object() const
208 {
209 return std::make_unique<BLAKE2b>(m_output_bits);
210 }
211
212std::unique_ptr<HashFunction> BLAKE2b::copy_state() const
213 {
214 return std::make_unique<BLAKE2b>(*this);
215 }
216
217void BLAKE2b::key_schedule(const uint8_t key[], size_t length)
218 {
219 BOTAN_ASSERT_NOMSG(length <= m_buffer.size());
220
221 m_key_size = length;
222 m_padded_key_buffer.resize(m_buffer.size());
223
224 if(m_padded_key_buffer.size() > length)
225 {
226 size_t padding = m_padded_key_buffer.size() - length;
227 clear_mem(m_padded_key_buffer.data() + length, padding);
228 }
229
230 copy_mem(m_padded_key_buffer.data(), key, length);
231 state_init();
232 }
233
235 {
236 zeroise(m_H);
237 zeroise(m_buffer);
238 zeroise(m_padded_key_buffer);
239 m_bufpos = 0;
240 m_key_size = 0;
241 state_init();
242 }
243
244}
#define BOTAN_ASSERT_NOMSG(expr)
Definition: assert.h:67
void key_schedule(const uint8_t key[], size_t length) override
Definition: blake2b.cpp:217
BLAKE2b(size_t output_bits=512)
Definition: blake2b.cpp:34
Key_Length_Specification key_spec() const override
Definition: blake2b.cpp:197
size_t output_length() const override
Definition: blake2b.h:32
std::unique_ptr< HashFunction > new_object() const override
Definition: blake2b.cpp:207
std::string name() const override
Definition: blake2b.cpp:202
void clear() override
Definition: blake2b.cpp:234
std::unique_ptr< HashFunction > copy_state() const override
Definition: blake2b.cpp:212
void final_result(uint8_t out[]) override
Definition: blake2b.cpp:187
void add_data(const uint8_t input[], size_t length) override
Definition: blake2b.cpp:148
#define BOTAN_FORCE_INLINE
Definition: compiler.h:128
Polynomial v
Definition: kyber.cpp:822
PolynomialVector b
Definition: kyber.cpp:821
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:209
Definition: alg_id.cpp:13
void zeroise(std::vector< T, Alloc > &vec)
Definition: secmem.h:114
void copy_out_vec_le(uint8_t out[], size_t out_bytes, const std::vector< T, Alloc > &in)
Definition: loadstor.h:705
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:126
constexpr T load_le(const uint8_t in[], size_t off)
Definition: loadstor.h:134
constexpr void clear_mem(T *ptr, size_t n)
Definition: mem_ops.h:115