Coverage Report

Created: 2020-11-21 08:34

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