Coverage Report

Created: 2022-06-23 06:44

/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
7
   {
31
7
   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
7
   clear();
36
7
   }
37
38
std::string Streebog::name() const
39
0
   {
40
0
   return "Streebog-" + std::to_string(m_output_bits);
41
0
   }
42
43
/*
44
* Clear memory of sensitive data
45
*/
46
void Streebog::clear()
47
14
   {
48
14
   m_count = 0;
49
14
   m_position = 0;
50
14
   zeroise(m_buffer);
51
14
   zeroise(m_S);
52
53
14
   const uint64_t fill = (m_output_bits == 512) ? 0 : 0x0101010101010101;
54
14
   std::fill(m_h.begin(), m_h.end(), fill);
55
14
   }
56
57
/*
58
* Update the hash
59
*/
60
void Streebog::add_data(const uint8_t input[], size_t length)
61
7
   {
62
7
   const size_t block_size = m_buffer.size();
63
64
7
   if(m_position)
65
0
      {
66
0
      buffer_insert(m_buffer, m_position, input, length);
67
68
0
      if(m_position + length >= block_size)
69
0
         {
70
0
         compress(m_buffer.data());
71
0
         m_count += 512;
72
0
         input += (block_size - m_position);
73
0
         length -= (block_size - m_position);
74
0
         m_position = 0;
75
0
         }
76
0
      }
77
78
7
   const size_t full_blocks = length / block_size;
79
7
   const size_t remaining   = length % block_size;
80
81
64
   for(size_t i = 0; i != full_blocks; ++i)
82
57
      {
83
57
      compress(input + block_size * i);
84
57
      m_count += 512;
85
57
      }
86
87
7
   buffer_insert(m_buffer, m_position, input + full_blocks * block_size, remaining);
88
7
   m_position += remaining;
89
7
   }
90
91
/*
92
* Finalize a hash
93
*/
94
void Streebog::final_result(uint8_t output[])
95
7
   {
96
7
   m_buffer[m_position++] = 0x01;
97
98
7
   if(m_position != m_buffer.size())
99
7
      clear_mem(&m_buffer[m_position], m_buffer.size() - m_position);
100
101
7
   compress(m_buffer.data());
102
7
   m_count += (m_position - 1) * 8;
103
104
7
   zeroise(m_buffer);
105
7
   store_le(m_count, m_buffer.data());
106
7
   compress(m_buffer.data(), true);
107
108
7
   compress_64(m_S.data(), true);
109
   // FIXME
110
7
   std::memcpy(output, &m_h[8 - output_length() / 8], output_length());
111
7
   clear();
112
7
   }
113
114
namespace {
115
116
inline uint64_t force_le(uint64_t x)
117
133k
   {
118
133k
#if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
119
133k
   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
133k
   }
127
128
inline void lps(uint64_t block[8])
129
1.95k
   {
130
1.95k
   uint8_t r[64];
131
   // FIXME
132
1.95k
   std::memcpy(r, block, 64);
133
134
17.5k
   for(int i = 0; i < 8; ++i)
135
15.6k
      {
136
15.6k
      block[i] = force_le(STREEBOG_Ax[0][r[i + 0*8]]) ^
137
15.6k
                 force_le(STREEBOG_Ax[1][r[i + 1*8]]) ^
138
15.6k
                 force_le(STREEBOG_Ax[2][r[i + 2*8]]) ^
139
15.6k
                 force_le(STREEBOG_Ax[3][r[i + 3*8]]) ^
140
15.6k
                 force_le(STREEBOG_Ax[4][r[i + 4*8]]) ^
141
15.6k
                 force_le(STREEBOG_Ax[5][r[i + 5*8]]) ^
142
15.6k
                 force_le(STREEBOG_Ax[6][r[i + 6*8]]) ^
143
15.6k
                 force_le(STREEBOG_Ax[7][r[i + 7*8]]);
144
15.6k
      }
145
1.95k
   }
146
147
} //namespace
148
149
void Streebog::compress(const uint8_t input[], bool last_block)
150
71
   {
151
71
   uint64_t M[8];
152
71
   std::memcpy(M, input, 64);
153
154
71
   compress_64(M, last_block);
155
71
   }
156
157
void Streebog::compress_64(const uint64_t M[], bool last_block)
158
78
   {
159
78
   const uint64_t N = last_block ? 0 : force_le(m_count);
160
161
78
   uint64_t hN[8];
162
78
   uint64_t A[8];
163
164
78
   copy_mem(hN, m_h.data(), 8);
165
78
   hN[0] ^= N;
166
78
   lps(hN);
167
168
78
   copy_mem(A, hN, 8);
169
170
702
   for(size_t i = 0; i != 8; ++i)
171
624
      {
172
624
      hN[i] ^= M[i];
173
624
      }
174
175
1.01k
   for(size_t i = 0; i < 12; ++i)
176
936
      {
177
8.42k
      for(size_t j = 0; j != 8; ++j)
178
7.48k
         A[j] ^= force_le(STREEBOG_C[i][j]);
179
936
      lps(A);
180
181
936
      lps(hN);
182
8.42k
      for(size_t j = 0; j != 8; ++j)
183
7.48k
         hN[j] ^= A[j];
184
936
      }
185
186
702
   for(size_t i = 0; i != 8; ++i)
187
624
      {
188
624
      m_h[i] ^= hN[i] ^ M[i];
189
624
      }
190
191
78
   if(!last_block)
192
64
      {
193
64
      uint64_t carry = 0;
194
576
      for(int i = 0; i < 8; i++)
195
512
         {
196
512
         const uint64_t m = force_le(M[i]);
197
512
         const uint64_t hi = force_le(m_S[i]);
198
512
         const uint64_t t = hi + m + carry;
199
200
512
         m_S[i] = force_le(t);
201
512
         if(t != m)
202
456
            carry = (t < m);
203
512
         }
204
64
      }
205
78
   }
206
207
}