Coverage Report

Created: 2023-02-22 06:14

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