Coverage Report

Created: 2023-06-07 07:00

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