Botan  2.7.0
Crypto and TLS for C++11
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/blake2b.h>
10 #include <botan/exceptn.h>
11 #include <botan/mem_ops.h>
12 #include <botan/loadstor.h>
13 #include <botan/rotate.h>
14 #include <algorithm>
15 
16 namespace Botan {
17 
18 namespace {
19 
21  BLAKE2B_BLOCKBYTES = 128,
22  BLAKE2B_IVU64COUNT = 8
23 };
24 
25 const uint64_t blake2b_IV[BLAKE2B_IVU64COUNT] = {
26  0x6a09e667f3bcc908, 0xbb67ae8584caa73b,
27  0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
28  0x510e527fade682d1, 0x9b05688c2b3e6c1f,
29  0x1f83d9abfb41bd6b, 0x5be0cd19137e2179
30 };
31 
32 }
33 
34 Blake2b::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  {
40  if(output_bits == 0 || output_bits > 512 || output_bits % 8 != 0)
41  {
42  throw Invalid_Argument("Bad output bits size for Blake2b");
43  }
44 
45  state_init();
46  }
47 
48 void Blake2b::state_init()
49  {
50  copy_mem(m_H.data(), blake2b_IV, BLAKE2B_IVU64COUNT);
51  m_H[0] ^= 0x01010000 ^ static_cast<uint8_t>(output_length());
52  m_T[0] = m_T[1] = 0;
53  m_F[0] = m_F[1] = 0;
54  }
55 
56 namespace {
57 
58 inline void G(uint64_t& a, uint64_t& b, uint64_t& c, uint64_t& d,
59  uint64_t M0, uint64_t M1)
60  {
61  a = a + b + M0;
62  d = rotr<32>(d ^ a);
63  c = c + d;
64  b = rotr<24>(b ^ c);
65  a = a + b + M1;
66  d = rotr<16>(d ^ a);
67  c = c + d;
68  b = rotr<63>(b ^ c);
69  }
70 
71 template<size_t i0, size_t i1, size_t i2, size_t i3, size_t i4, size_t i5, size_t i6, size_t i7,
72  size_t i8, size_t i9, size_t iA, size_t iB, size_t iC, size_t iD, size_t iE, size_t iF>
73 inline void ROUND(uint64_t* v, const uint64_t* M)
74  {
75  G(v[ 0], v[ 4], v[ 8], v[12], M[i0], M[i1]);
76  G(v[ 1], v[ 5], v[ 9], v[13], M[i2], M[i3]);
77  G(v[ 2], v[ 6], v[10], v[14], M[i4], M[i5]);
78  G(v[ 3], v[ 7], v[11], v[15], M[i6], M[i7]);
79  G(v[ 0], v[ 5], v[10], v[15], M[i8], M[i9]);
80  G(v[ 1], v[ 6], v[11], v[12], M[iA], M[iB]);
81  G(v[ 2], v[ 7], v[ 8], v[13], M[iC], M[iD]);
82  G(v[ 3], v[ 4], v[ 9], v[14], M[iE], M[iF]);
83  }
84 
85 
86 }
87 
88 void Blake2b::compress(const uint8_t* input, size_t blocks, uint64_t increment)
89  {
90  for(size_t b = 0; b != blocks; ++b)
91  {
92  m_T[0] += increment;
93  if(m_T[0] < increment)
94  {
95  m_T[1]++;
96  }
97 
98  uint64_t M[16];
99  uint64_t v[16];
100  load_le(M, input, 16);
101 
102  input += BLAKE2B_BLOCKBYTES;
103 
104  for(size_t i = 0; i < 8; i++)
105  v[i] = m_H[i];
106  for(size_t i = 0; i != 8; ++i)
107  v[i + 8] = blake2b_IV[i];
108 
109  v[12] ^= m_T[0];
110  v[13] ^= m_T[1];
111  v[14] ^= m_F[0];
112  v[15] ^= m_F[1];
113 
114  ROUND< 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15>(v, M);
115  ROUND<14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3>(v, M);
116  ROUND<11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4>(v, M);
117  ROUND< 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8>(v, M);
118  ROUND< 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13>(v, M);
119  ROUND< 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9>(v, M);
120  ROUND<12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11>(v, M);
121  ROUND<13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10>(v, M);
122  ROUND< 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5>(v, M);
123  ROUND<10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0>(v, M);
124  ROUND< 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15>(v, M);
125  ROUND<14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3>(v, M);
126 
127  for(size_t i = 0; i < 8; i++)
128  {
129  m_H[i] ^= v[i] ^ v[i + 8];
130  }
131  }
132  }
133 
134 void Blake2b::add_data(const uint8_t input[], size_t length)
135  {
136  if(length == 0)
137  return;
138 
139  if(m_bufpos > 0)
140  {
141  if(m_bufpos < BLAKE2B_BLOCKBYTES)
142  {
143  const size_t take = std::min(BLAKE2B_BLOCKBYTES - m_bufpos, length);
144  copy_mem(&m_buffer[m_bufpos], input, take);
145  m_bufpos += take;
146  length -= take;
147  input += take;
148  }
149 
150  if(m_bufpos == m_buffer.size() && length > 0)
151  {
152  compress(m_buffer.data(), 1, BLAKE2B_BLOCKBYTES);
153  m_bufpos = 0;
154  }
155  }
156 
157  if(length > BLAKE2B_BLOCKBYTES)
158  {
159  const size_t full_blocks = ((length-1) / BLAKE2B_BLOCKBYTES);
160  compress(input, full_blocks, BLAKE2B_BLOCKBYTES);
161 
162  input += full_blocks * BLAKE2B_BLOCKBYTES;
163  length -= full_blocks * BLAKE2B_BLOCKBYTES;
164  }
165 
166  if(length > 0)
167  {
168  copy_mem(&m_buffer[m_bufpos], input, length);
169  m_bufpos += length;
170  }
171  }
172 
173 void Blake2b::final_result(uint8_t output[])
174  {
175  if(m_bufpos != BLAKE2B_BLOCKBYTES)
176  clear_mem(&m_buffer[m_bufpos], BLAKE2B_BLOCKBYTES - m_bufpos);
177  m_F[0] = 0xFFFFFFFFFFFFFFFF;
178  compress(m_buffer.data(), 1, m_bufpos);
179  copy_out_vec_le(output, output_length(), m_H);
180  clear();
181  }
182 
183 std::string Blake2b::name() const
184  {
185  return "Blake2b(" + std::to_string(m_output_bits) + ")";
186  }
187 
189  {
190  return new Blake2b(m_output_bits);
191  }
192 
193 std::unique_ptr<HashFunction> Blake2b::copy_state() const
194  {
195  return std::unique_ptr<HashFunction>(new Blake2b(*this));
196  }
197 
199  {
200  zeroise(m_H);
201  zeroise(m_buffer);
202  m_bufpos = 0;
203  state_init();
204  }
205 
206 }
HashFunction * clone() const override
Definition: blake2b.cpp:188
Blake2b(size_t output_bits=512)
Definition: blake2b.cpp:34
void clear_mem(T *ptr, size_t n)
Definition: mem_ops.h:97
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:210
std::unique_ptr< HashFunction > copy_state() const override
Definition: blake2b.cpp:193
T load_le(const uint8_t in[], size_t off)
Definition: loadstor.h:121
void clear() override
Definition: blake2b.cpp:198
void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:108
Definition: alg_id.cpp:13
std::string name() const override
Definition: blake2b.cpp:183
size_t output_length() const override
Definition: blake2b.h:29
void zeroise(std::vector< T, Alloc > &vec)
Definition: secmem.h:183
void copy_out_vec_le(uint8_t out[], size_t out_bytes, const std::vector< T, Alloc > &in)
Definition: loadstor.h:690