Botan 3.3.0
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/internal/streebog.h>
10
11#include <botan/exceptn.h>
12#include <botan/internal/fmt.h>
13#include <botan/internal/loadstor.h>
14#include <botan/internal/stl_util.h>
15
16namespace Botan {
17
18extern const uint64_t STREEBOG_Ax[8][256];
19extern const uint64_t STREEBOG_C[12][8];
20
21std::unique_ptr<HashFunction> Streebog::copy_state() const {
22 return std::make_unique<Streebog>(*this);
23}
24
25Streebog::Streebog(size_t output_bits) : m_output_bits(output_bits), m_count(0), m_h(8), m_S(8) {
26 if(output_bits != 256 && output_bits != 512) {
27 throw Invalid_Argument(fmt("Streebog: Invalid output length {}", output_bits));
28 }
29
30 clear();
31}
32
33std::string Streebog::name() const {
34 return fmt("Streebog-{}", m_output_bits);
35}
36
37/*
38* Clear memory of sensitive data
39*/
41 m_count = 0;
42 m_buffer.clear();
43 zeroise(m_S);
44
45 const uint64_t fill = (m_output_bits == 512) ? 0 : 0x0101010101010101;
46 std::fill(m_h.begin(), m_h.end(), fill);
47}
48
49/*
50* Update the hash
51*/
52void Streebog::add_data(std::span<const uint8_t> input) {
53 BufferSlicer in(input);
54
55 while(!in.empty()) {
56 if(const auto one_block = m_buffer.handle_unaligned_data(in)) {
57 compress(one_block->data());
58 m_count += 512;
59 }
60
61 if(m_buffer.in_alignment()) {
62 while(const auto aligned_block = m_buffer.next_aligned_block_to_process(in)) {
63 compress(aligned_block->data());
64 m_count += 512;
65 }
66 }
67 }
68}
69
70/*
71* Finalize a hash
72*/
73void Streebog::final_result(std::span<uint8_t> output) {
74 const auto pos = m_buffer.elements_in_buffer();
75
76 const uint8_t padding = 0x01;
77 m_buffer.append({&padding, 1});
78 m_buffer.fill_up_with_zeros();
79
80 compress(m_buffer.consume().data());
81 m_count += pos * 8;
82
83 m_buffer.fill_up_with_zeros();
84 store_le(m_count, m_buffer.directly_modify_first(sizeof(m_count)).data());
85 compress(m_buffer.consume().data(), true);
86
87 compress_64(m_S.data(), true);
88 // FIXME
89 std::memcpy(output.data(), &m_h[8 - output_length() / 8], output_length());
90 clear();
91}
92
93namespace {
94
95inline uint64_t force_le(uint64_t x) {
96#if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
97 return x;
98#elif defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
99 return reverse_bytes(x);
100#else
101 store_le(x, reinterpret_cast<uint8_t*>(&x));
102 return x;
103#endif
104}
105
106inline void lps(uint64_t block[8]) {
107 uint8_t r[64];
108 // FIXME
109 std::memcpy(r, block, 64);
110
111 for(int i = 0; i < 8; ++i) {
112 block[i] = force_le(STREEBOG_Ax[0][r[i + 0 * 8]]) ^ force_le(STREEBOG_Ax[1][r[i + 1 * 8]]) ^
113 force_le(STREEBOG_Ax[2][r[i + 2 * 8]]) ^ force_le(STREEBOG_Ax[3][r[i + 3 * 8]]) ^
114 force_le(STREEBOG_Ax[4][r[i + 4 * 8]]) ^ force_le(STREEBOG_Ax[5][r[i + 5 * 8]]) ^
115 force_le(STREEBOG_Ax[6][r[i + 6 * 8]]) ^ force_le(STREEBOG_Ax[7][r[i + 7 * 8]]);
116 }
117}
118
119} //namespace
120
121void Streebog::compress(const uint8_t input[], bool last_block) {
122 uint64_t M[8];
123 std::memcpy(M, input, 64);
124
125 compress_64(M, last_block);
126}
127
128void Streebog::compress_64(const uint64_t M[], bool last_block) {
129 const uint64_t N = last_block ? 0 : force_le(m_count);
130
131 uint64_t hN[8];
132 uint64_t A[8];
133
134 copy_mem(hN, m_h.data(), 8);
135 hN[0] ^= N;
136 lps(hN);
137
138 copy_mem(A, hN, 8);
139
140 for(size_t i = 0; i != 8; ++i) {
141 hN[i] ^= M[i];
142 }
143
144 for(size_t i = 0; i < 12; ++i) {
145 for(size_t j = 0; j != 8; ++j) {
146 A[j] ^= force_le(STREEBOG_C[i][j]);
147 }
148 lps(A);
149
150 lps(hN);
151 for(size_t j = 0; j != 8; ++j) {
152 hN[j] ^= A[j];
153 }
154 }
155
156 for(size_t i = 0; i != 8; ++i) {
157 m_h[i] ^= hN[i] ^ M[i];
158 }
159
160 if(!last_block) {
161 uint64_t carry = 0;
162 for(int i = 0; i < 8; i++) {
163 const uint64_t m = force_le(M[i]);
164 const uint64_t hi = force_le(m_S[i]);
165 const uint64_t t = hi + m + carry;
166
167 m_S[i] = force_le(t);
168 if(t != m) {
169 carry = (t < m);
170 }
171 }
172 }
173}
174
175} // namespace Botan
std::span< T > directly_modify_first(size_t elements)
size_t elements_in_buffer() const
std::optional< std::span< const uint8_t > > next_aligned_block_to_process(BufferSlicer &slicer) const
void append(std::span< const T > elements)
std::optional< std::span< const T > > handle_unaligned_data(BufferSlicer &slicer)
std::span< const T > consume()
bool empty() const
Definition stl_util.h:186
void compress(const uint8_t input[], bool lastblock=false)
Definition streebog.cpp:121
void add_data(std::span< const uint8_t > input) override
Definition streebog.cpp:52
size_t output_length() const override
Definition streebog.h:23
void compress_64(const uint64_t input[], bool lastblock=false)
Definition streebog.cpp:128
std::unique_ptr< HashFunction > copy_state() const override
Definition streebog.cpp:21
void final_result(std::span< uint8_t > out) override
Definition streebog.cpp:73
Streebog(size_t output_bits)
Definition streebog.cpp:25
void clear() override
Definition streebog.cpp:40
std::string name() const override
Definition streebog.cpp:33
void zeroise(std::vector< T, Alloc > &vec)
Definition secmem.h:108
std::string fmt(std::string_view format, const T &... args)
Definition fmt.h:53
const uint64_t STREEBOG_C[12][8]
constexpr void store_le(T in, OutR &&out_range)
Definition loadstor.h:383
constexpr uint16_t reverse_bytes(uint16_t x)
Definition bswap.h:19
void carry(int64_t &h0, int64_t &h1)
const uint64_t STREEBOG_Ax[8][256]
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:146