Botan 3.10.0
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
11#include <botan/exceptn.h>
12#include <botan/mem_ops.h>
13#include <botan/internal/fmt.h>
14#include <botan/internal/loadstor.h>
15#include <botan/internal/rotate.h>
16#include <botan/internal/stl_util.h>
17#include <array>
18
19namespace Botan {
20
21namespace {
22
23constexpr std::array<uint64_t, 8> blake2b_IV{0x6a09e667f3bcc908,
24 0xbb67ae8584caa73b,
25 0x3c6ef372fe94f82b,
26 0xa54ff53a5f1d36f1,
27 0x510e527fade682d1,
28 0x9b05688c2b3e6c1f,
29 0x1f83d9abfb41bd6b,
30 0x5be0cd19137e2179};
31
32} // namespace
33
34BLAKE2b::BLAKE2b(size_t output_bits) : m_output_bits(output_bits), m_H(blake2b_IV.size()), m_T(), m_F(), m_key_size(0) {
35 if(output_bits == 0 || output_bits > 512 || output_bits % 8 != 0) {
36 throw Invalid_Argument("Bad output bits size for BLAKE2b");
37 }
38
39 state_init();
40}
41
42void BLAKE2b::state_init() {
43 copy_mem(m_H.data(), blake2b_IV.data(), blake2b_IV.size());
44 m_H[0] ^= (0x01010000 | (static_cast<uint8_t>(m_key_size) << 8) | static_cast<uint8_t>(output_length()));
45 m_T[0] = m_T[1] = 0;
46 m_F = 0;
47
48 m_buffer.clear();
49 if(m_key_size > 0) {
50 m_buffer.append(m_padded_key_buffer);
51 }
52}
53
54namespace {
55
56BOTAN_FORCE_INLINE void G(uint64_t& a, uint64_t& b, uint64_t& c, uint64_t& d, uint64_t M0, uint64_t M1) {
57 a = a + b + M0;
58 d = rotr<32>(d ^ a);
59 c = c + d;
60 b = rotr<24>(b ^ c);
61 a = a + b + M1;
62 d = rotr<16>(d ^ a);
63 c = c + d;
64 b = rotr<63>(b ^ c);
65}
66
67template <size_t i0,
68 size_t i1,
69 size_t i2,
70 size_t i3,
71 size_t i4,
72 size_t i5,
73 size_t i6,
74 size_t i7,
75 size_t i8,
76 size_t i9,
77 size_t iA,
78 size_t iB,
79 size_t iC,
80 size_t iD,
81 size_t iE,
82 size_t iF>
83BOTAN_FORCE_INLINE void ROUND(uint64_t* v, const uint64_t* M) {
84 G(v[0], v[4], v[8], v[12], M[i0], M[i1]);
85 G(v[1], v[5], v[9], v[13], M[i2], M[i3]);
86 G(v[2], v[6], v[10], v[14], M[i4], M[i5]);
87 G(v[3], v[7], v[11], v[15], M[i6], M[i7]);
88 G(v[0], v[5], v[10], v[15], M[i8], M[i9]);
89 G(v[1], v[6], v[11], v[12], M[iA], M[iB]);
90 G(v[2], v[7], v[8], v[13], M[iC], M[iD]);
91 G(v[3], v[4], v[9], v[14], M[iE], M[iF]);
92}
93
94} // namespace
95
96void BLAKE2b::compress(const uint8_t* input, size_t blocks, uint64_t increment) {
97 for(size_t b = 0; b != blocks; ++b) {
98 m_T[0] += increment;
99 if(m_T[0] < increment) {
100 m_T[1]++;
101 }
102
103 uint64_t M[16];
104 uint64_t v[16];
105 load_le(M, input, 16);
106
107 input += BLAKE2B_BLOCKBYTES;
108
109 for(size_t i = 0; i < 8; i++) {
110 v[i] = m_H[i];
111 }
112 for(size_t i = 0; i != 8; ++i) {
113 v[i + 8] = blake2b_IV[i];
114 }
115
116 v[12] ^= m_T[0];
117 v[13] ^= m_T[1];
118 v[14] ^= m_F;
119
120 ROUND<0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15>(v, M);
121 ROUND<14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3>(v, M);
122 ROUND<11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4>(v, M);
123 ROUND<7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8>(v, M);
124 ROUND<9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13>(v, M);
125 ROUND<2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9>(v, M);
126 ROUND<12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11>(v, M);
127 ROUND<13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10>(v, M);
128 ROUND<6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5>(v, M);
129 ROUND<10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0>(v, M);
130 ROUND<0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15>(v, M);
131 ROUND<14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3>(v, M);
132
133 for(size_t i = 0; i < 8; i++) {
134 m_H[i] ^= v[i] ^ v[i + 8];
135 }
136 }
137}
138
139void BLAKE2b::add_data(std::span<const uint8_t> input) {
140 BufferSlicer in(input);
141
142 while(!in.empty()) {
143 if(const auto one_block = m_buffer.handle_unaligned_data(in)) {
144 compress(one_block->data(), 1, BLAKE2B_BLOCKBYTES);
145 }
146
147 if(m_buffer.in_alignment()) {
148 const auto [aligned_data, full_blocks] = m_buffer.aligned_data_to_process(in);
149 if(full_blocks > 0) {
150 compress(aligned_data.data(), full_blocks, BLAKE2B_BLOCKBYTES);
151 }
152 }
153 }
154}
155
156void BLAKE2b::final_result(std::span<uint8_t> output) {
157 const auto pos = m_buffer.elements_in_buffer();
158 m_buffer.fill_up_with_zeros();
159
160 m_F = 0xFFFFFFFFFFFFFFFF;
161 compress(m_buffer.consume().data(), 1, pos);
162 copy_out_le(output.first(output_length()), m_H);
163 state_init();
164}
165
169
170std::string BLAKE2b::name() const {
171 return fmt("BLAKE2b({})", m_output_bits);
172}
173
174std::unique_ptr<HashFunction> BLAKE2b::new_object() const {
175 return std::make_unique<BLAKE2b>(m_output_bits);
176}
177
178std::unique_ptr<HashFunction> BLAKE2b::copy_state() const {
179 return std::make_unique<BLAKE2b>(*this);
180}
181
183 return m_key_size > 0;
184}
185
186void BLAKE2b::key_schedule(std::span<const uint8_t> key) {
187 BOTAN_ASSERT_NOMSG(key.size() <= m_buffer.size());
188
189 m_key_size = key.size();
190 m_padded_key_buffer.resize(m_buffer.size());
191
192 if(m_padded_key_buffer.size() > m_key_size) {
193 size_t padding = m_padded_key_buffer.size() - m_key_size;
194 clear_mem(m_padded_key_buffer.data() + m_key_size, padding);
195 }
196
197 copy_mem(m_padded_key_buffer.data(), key.data(), key.size());
198 state_init();
199}
200
202 zeroise(m_H);
203 m_buffer.clear();
204 zeroise(m_padded_key_buffer);
205 m_key_size = 0;
206 state_init();
207}
208
209} // namespace Botan
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
void append(std::span< const T > elements)
BLAKE2b(size_t output_bits=512)
Definition blake2b.cpp:34
Key_Length_Specification key_spec() const override
Definition blake2b.cpp:166
void key_schedule(std::span< const uint8_t > key) override
Definition blake2b.cpp:186
size_t output_length() const override
Definition blake2b.h:36
std::unique_ptr< HashFunction > new_object() const override
Definition blake2b.cpp:174
std::string name() const override
Definition blake2b.cpp:170
bool has_keying_material() const override
Definition blake2b.cpp:182
void add_data(std::span< const uint8_t > input) override
Definition blake2b.cpp:139
void clear() override
Definition blake2b.cpp:201
std::unique_ptr< HashFunction > copy_state() const override
Definition blake2b.cpp:178
void final_result(std::span< uint8_t > out) override
Definition blake2b.cpp:156
bool empty() const
Definition stl_util.h:120
#define BOTAN_FORCE_INLINE
Definition compiler.h:87
void zeroise(std::vector< T, Alloc > &vec)
Definition secmem.h:125
constexpr size_t BLAKE2B_BLOCKBYTES
Definition blake2b.h:21
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:145
std::string fmt(std::string_view format, const T &... args)
Definition fmt.h:53
void copy_out_le(std::span< uint8_t > out, const InR &in)
Definition loadstor.h:789
BOTAN_FORCE_INLINE constexpr T rotr(T input)
Definition rotate.h:35
constexpr auto load_le(ParamTs &&... params)
Definition loadstor.h:495
constexpr void clear_mem(T *ptr, size_t n)
Definition mem_ops.h:119