Coverage Report

Created: 2023-09-25 06:33

/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
#include <botan/internal/stl_util.h>
15
16
namespace Botan {
17
18
extern const uint64_t STREEBOG_Ax[8][256];
19
extern const uint64_t STREEBOG_C[12][8];
20
21
0
std::unique_ptr<HashFunction> Streebog::copy_state() const {
22
0
   return std::make_unique<Streebog>(*this);
23
0
}
24
25
223
Streebog::Streebog(size_t output_bits) : m_output_bits(output_bits), m_count(0), m_h(8), m_S(8) {
26
223
   if(output_bits != 256 && output_bits != 512) {
27
0
      throw Invalid_Argument(fmt("Streebog: Invalid output length {}", output_bits));
28
0
   }
29
30
223
   clear();
31
223
}
32
33
10
std::string Streebog::name() const {
34
10
   return fmt("Streebog-{}", m_output_bits);
35
10
}
36
37
/*
38
* Clear memory of sensitive data
39
*/
40
7.90k
void Streebog::clear() {
41
7.90k
   m_count = 0;
42
7.90k
   m_buffer.clear();
43
7.90k
   zeroise(m_S);
44
45
7.90k
   const uint64_t fill = (m_output_bits == 512) ? 0 : 0x0101010101010101;
46
7.90k
   std::fill(m_h.begin(), m_h.end(), fill);
47
7.90k
}
48
49
/*
50
* Update the hash
51
*/
52
26.8k
void Streebog::add_data(std::span<const uint8_t> input) {
53
26.8k
   BufferSlicer in(input);
54
55
47.0k
   while(!in.empty()) {
56
20.2k
      if(const auto one_block = m_buffer.handle_unaligned_data(in)) {
57
232
         compress(one_block->data());
58
232
         m_count += 512;
59
232
      }
60
61
20.2k
      if(m_buffer.in_alignment()) {
62
25.0k
         while(const auto aligned_block = m_buffer.next_aligned_block_to_process(in)) {
63
12.9k
            compress(aligned_block->data());
64
12.9k
            m_count += 512;
65
12.9k
         }
66
12.1k
      }
67
20.2k
   }
68
26.8k
}
69
70
/*
71
* Finalize a hash
72
*/
73
7.54k
void Streebog::final_result(std::span<uint8_t> output) {
74
7.54k
   const auto pos = m_buffer.elements_in_buffer();
75
76
7.54k
   const uint8_t padding = 0x01;
77
7.54k
   m_buffer.append({&padding, 1});
78
7.54k
   m_buffer.fill_up_with_zeros();
79
80
7.54k
   compress(m_buffer.consume().data());
81
7.54k
   m_count += pos * 8;
82
83
7.54k
   m_buffer.fill_up_with_zeros();
84
7.54k
   store_le(m_count, m_buffer.directly_modify_first(sizeof(m_count)).data());
85
7.54k
   compress(m_buffer.consume().data(), true);
86
87
7.54k
   compress_64(m_S.data(), true);
88
   // FIXME
89
7.54k
   std::memcpy(output.data(), &m_h[8 - output_length() / 8], output_length());
90
7.54k
   clear();
91
7.54k
}
92
93
namespace {
94
95
61.2M
inline uint64_t force_le(uint64_t x) {
96
61.2M
#if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
97
61.2M
   return x;
98
#elif defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
99
   return reverse_bytes(x);
100
#else
101
   store_le(x, reinterpret_cast<uint8_t*>(&x));
102
   return x;
103
#endif
104
61.2M
}
105
106
894k
inline void lps(uint64_t block[8]) {
107
894k
   uint8_t r[64];
108
   // FIXME
109
894k
   std::memcpy(r, block, 64);
110
111
8.05M
   for(int i = 0; i < 8; ++i) {
112
7.15M
      block[i] = force_le(STREEBOG_Ax[0][r[i + 0 * 8]]) ^ force_le(STREEBOG_Ax[1][r[i + 1 * 8]]) ^
113
7.15M
                 force_le(STREEBOG_Ax[2][r[i + 2 * 8]]) ^ force_le(STREEBOG_Ax[3][r[i + 3 * 8]]) ^
114
7.15M
                 force_le(STREEBOG_Ax[4][r[i + 4 * 8]]) ^ force_le(STREEBOG_Ax[5][r[i + 5 * 8]]) ^
115
7.15M
                 force_le(STREEBOG_Ax[6][r[i + 6 * 8]]) ^ force_le(STREEBOG_Ax[7][r[i + 7 * 8]]);
116
7.15M
   }
117
894k
}
118
119
}  //namespace
120
121
28.2k
void Streebog::compress(const uint8_t input[], bool last_block) {
122
28.2k
   uint64_t M[8];
123
28.2k
   std::memcpy(M, input, 64);
124
125
28.2k
   compress_64(M, last_block);
126
28.2k
}
127
128
35.7k
void Streebog::compress_64(const uint64_t M[], bool last_block) {
129
35.7k
   const uint64_t N = last_block ? 0 : force_le(m_count);
130
131
35.7k
   uint64_t hN[8];
132
35.7k
   uint64_t A[8];
133
134
35.7k
   copy_mem(hN, m_h.data(), 8);
135
35.7k
   hN[0] ^= N;
136
35.7k
   lps(hN);
137
138
35.7k
   copy_mem(A, hN, 8);
139
140
322k
   for(size_t i = 0; i != 8; ++i) {
141
286k
      hN[i] ^= M[i];
142
286k
   }
143
144
465k
   for(size_t i = 0; i < 12; ++i) {
145
3.86M
      for(size_t j = 0; j != 8; ++j) {
146
3.43M
         A[j] ^= force_le(STREEBOG_C[i][j]);
147
3.43M
      }
148
429k
      lps(A);
149
150
429k
      lps(hN);
151
3.86M
      for(size_t j = 0; j != 8; ++j) {
152
3.43M
         hN[j] ^= A[j];
153
3.43M
      }
154
429k
   }
155
156
322k
   for(size_t i = 0; i != 8; ++i) {
157
286k
      m_h[i] ^= hN[i] ^ M[i];
158
286k
   }
159
160
35.7k
   if(!last_block) {
161
20.7k
      uint64_t carry = 0;
162
186k
      for(int i = 0; i < 8; i++) {
163
165k
         const uint64_t m = force_le(M[i]);
164
165k
         const uint64_t hi = force_le(m_S[i]);
165
165k
         const uint64_t t = hi + m + carry;
166
167
165k
         m_S[i] = force_le(t);
168
165k
         if(t != m) {
169
104k
            carry = (t < m);
170
104k
         }
171
165k
      }
172
20.7k
   }
173
35.7k
}
174
175
}  // namespace Botan