Botan 2.19.1
Crypto and TLS for C&
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
13namespace Botan {
14
15extern const uint64_t STREEBOG_Ax[8][256];
16extern const uint64_t STREEBOG_C[12][8];
17
18std::unique_ptr<HashFunction> Streebog::copy_state() const
19 {
20 return std::unique_ptr<HashFunction>(new Streebog(*this));
21 }
22
23Streebog::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
38std::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*/
60void 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*/
94void 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
114namespace {
115
116inline 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
128inline 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
149void 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
157void 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}
void compress(const uint8_t input[], bool lastblock=false)
Definition: streebog.cpp:149
void add_data(const uint8_t input[], size_t length) override
Definition: streebog.cpp:60
size_t output_length() const override
Definition: streebog.h:24
void compress_64(const uint64_t input[], bool lastblock=false)
Definition: streebog.cpp:157
std::unique_ptr< HashFunction > copy_state() const override
Definition: streebog.cpp:18
void final_result(uint8_t out[]) override
Definition: streebog.cpp:94
Streebog(size_t output_bits)
Definition: streebog.cpp:23
void clear() override
Definition: streebog.cpp:46
std::string name() const override
Definition: streebog.cpp:38
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:213
Definition: alg_id.cpp:13
void zeroise(std::vector< T, Alloc > &vec)
Definition: secmem.h:117
uint16_t reverse_bytes(uint16_t val)
Definition: bswap.h:25
size_t buffer_insert(std::vector< T, Alloc > &buf, size_t buf_offset, const T input[], size_t input_length)
Definition: mem_ops.h:228
const uint64_t STREEBOG_C[12][8]
void carry(int64_t &h0, int64_t &h1)
void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:133
void store_le(uint16_t in, uint8_t out[2])
Definition: loadstor.h:454
const uint64_t STREEBOG_Ax[8][256]
void clear_mem(T *ptr, size_t n)
Definition: mem_ops.h:115