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