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