Botan  2.13.0
Crypto and TLS for C++11
streebog.cpp
Go to the documentation of this file.
1 /*
2 * Streebog
3 * (C) 2017 Ribose Inc.
4 * (C) 2018 Jack Lloyd
5 *
6 * Botan is released under the Simplified BSD License (see license.txt)
7 */
8 
9 #include <botan/streebog.h>
10 #include <botan/loadstor.h>
11 #include <botan/exceptn.h>
12 
13 namespace Botan {
14 
15 extern const uint64_t STREEBOG_Ax[8][256];
16 extern const uint64_t STREEBOG_C[12][8];
17 
18 std::unique_ptr<HashFunction> Streebog::copy_state() const
19  {
20  return std::unique_ptr<HashFunction>(new Streebog(*this));
21  }
22 
23 Streebog::Streebog(size_t output_bits) :
24  m_output_bits(output_bits),
25  m_count(0),
26  m_position(0),
27  m_buffer(64),
28  m_h(8),
29  m_S(8)
30  {
31  if(output_bits != 256 && output_bits != 512)
32  throw Invalid_Argument("Streebog: Invalid output length " +
33  std::to_string(output_bits));
34 
35  clear();
36  }
37 
38 std::string Streebog::name() const
39  {
40  return "Streebog-" + std::to_string(m_output_bits);
41  }
42 
43 /*
44 * Clear memory of sensitive data
45 */
47  {
48  m_count = 0;
49  m_position = 0;
50  zeroise(m_buffer);
51  zeroise(m_S);
52 
53  const uint64_t fill = (m_output_bits == 512) ? 0 : 0x0101010101010101;
54  std::fill(m_h.begin(), m_h.end(), fill);
55  }
56 
57 /*
58 * Update the hash
59 */
60 void Streebog::add_data(const uint8_t input[], size_t length)
61  {
62  const size_t block_size = m_buffer.size();
63 
64  if(m_position)
65  {
66  buffer_insert(m_buffer, m_position, input, length);
67 
68  if(m_position + length >= block_size)
69  {
70  compress(m_buffer.data());
71  m_count += 512;
72  input += (block_size - m_position);
73  length -= (block_size - m_position);
74  m_position = 0;
75  }
76  }
77 
78  const size_t full_blocks = length / block_size;
79  const size_t remaining = length % block_size;
80 
81  for(size_t i = 0; i != full_blocks; ++i)
82  {
83  compress(input + block_size * i);
84  m_count += 512;
85  }
86 
87  buffer_insert(m_buffer, m_position, input + full_blocks * block_size, remaining);
88  m_position += remaining;
89  }
90 
91 /*
92 * Finalize a hash
93 */
94 void Streebog::final_result(uint8_t output[])
95  {
96  m_buffer[m_position++] = 0x01;
97 
98  if(m_position != m_buffer.size())
99  clear_mem(&m_buffer[m_position], m_buffer.size() - m_position);
100 
101  compress(m_buffer.data());
102  m_count += (m_position - 1) * 8;
103 
104  zeroise(m_buffer);
105  store_le(m_count, m_buffer.data());
106  compress(m_buffer.data(), true);
107 
108  compress_64(m_S.data(), true);
109  // FIXME
110  std::memcpy(output, &m_h[8 - output_length() / 8], output_length());
111  clear();
112  }
113 
114 namespace {
115 
116 inline uint64_t force_le(uint64_t x)
117  {
118 #if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
119  return x;
120 #elif defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
121  return reverse_bytes(x);
122 #else
123  store_le(x, reinterpret_cast<uint8_t*>(&x));
124  return x;
125 #endif
126  }
127 
128 inline void lps(uint64_t block[8])
129  {
130  uint8_t r[64];
131  // FIXME
132  std::memcpy(r, block, 64);
133 
134  for(int i = 0; i < 8; ++i)
135  {
136  block[i] = force_le(STREEBOG_Ax[0][r[i + 0*8]]) ^
137  force_le(STREEBOG_Ax[1][r[i + 1*8]]) ^
138  force_le(STREEBOG_Ax[2][r[i + 2*8]]) ^
139  force_le(STREEBOG_Ax[3][r[i + 3*8]]) ^
140  force_le(STREEBOG_Ax[4][r[i + 4*8]]) ^
141  force_le(STREEBOG_Ax[5][r[i + 5*8]]) ^
142  force_le(STREEBOG_Ax[6][r[i + 6*8]]) ^
143  force_le(STREEBOG_Ax[7][r[i + 7*8]]);
144  }
145  }
146 
147 } //namespace
148 
149 void Streebog::compress(const uint8_t input[], bool last_block)
150  {
151  uint64_t M[8];
152  std::memcpy(M, input, 64);
153 
154  compress_64(M, last_block);
155  }
156 
157 void Streebog::compress_64(const uint64_t M[], bool last_block)
158  {
159  uint64_t N = force_le(last_block ? 0ULL : m_count);
160 
161  uint64_t hN[8];
162  uint64_t A[8];
163 
164  copy_mem(hN, m_h.data(), 8);
165  hN[0] ^= N;
166  lps(hN);
167 
168  copy_mem(A, hN, 8);
169 
170  for(size_t i = 0; i != 8; ++i)
171  {
172  hN[i] ^= M[i];
173  }
174 
175  for(size_t i = 0; i < 12; ++i)
176  {
177  for(size_t j = 0; j != 8; ++j)
178  A[j] ^= force_le(STREEBOG_C[i][j]);
179  lps(A);
180 
181  lps(hN);
182  for(size_t j = 0; j != 8; ++j)
183  hN[j] ^= A[j];
184  }
185 
186  for(size_t i = 0; i != 8; ++i)
187  {
188  m_h[i] ^= hN[i] ^ M[i];
189  }
190 
191  if(!last_block)
192  {
193  uint64_t carry = 0;
194  for(int i = 0; i < 8; i++)
195  {
196  const uint64_t m = force_le(M[i]);
197  const uint64_t hi = force_le(m_S[i]);
198  const uint64_t t = hi + m + carry;
199 
200  m_S[i] = force_le(t);
201  if(t != m)
202  carry = (t < m);
203  }
204  }
205  }
206 
207 }
std::string name() const override
Definition: streebog.cpp:38
void carry(int64_t &h0, int64_t &h1)
void clear_mem(T *ptr, size_t n)
Definition: mem_ops.h:112
size_t output_length() const override
Definition: streebog.h:24
const uint64_t STREEBOG_C[12][8]
void clear() override
Definition: streebog.cpp:46
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:213
std::unique_ptr< HashFunction > copy_state() const override
Definition: streebog.cpp:18
void add_data(const uint8_t input[], size_t length) override
Definition: streebog.cpp:60
void compress_64(const uint64_t input[], bool lastblock=false)
Definition: streebog.cpp:157
void compress(const uint8_t input[], bool lastblock=false)
Definition: streebog.cpp:149
void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:132
Definition: alg_id.cpp:13
uint16_t reverse_bytes(uint16_t val)
Definition: bswap.h:25
void final_result(uint8_t out[]) override
Definition: streebog.cpp:94
size_t buffer_insert(std::vector< T, Alloc > &buf, size_t buf_offset, const T input[], size_t input_length)
Definition: secmem.h:80
const uint64_t STREEBOG_Ax[8][256]
Streebog(size_t output_bits)
Definition: streebog.cpp:23
void store_le(uint16_t in, uint8_t out[2])
Definition: loadstor.h:454
void zeroise(std::vector< T, Alloc > &vec)
Definition: secmem.h:160