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