Coverage Report

Created: 2024-11-21 07:03

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