Botan 3.10.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/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 const uint64_t block2[8] = {block[0], block[1], block[2], block[3], block[4], block[5], block[6], block[7]};
110 std::span<const uint8_t> r{reinterpret_cast<const uint8_t*>(block2), 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) { // NOLINT(modernize-loop-convert)
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) ? 1 : 0;
171 }
172 }
173 }
174}
175
176} // namespace Botan
bool empty() const
Definition stl_util.h:120
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:54
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: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:125
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:145
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]