• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 23116334076

15 Mar 2026 06:15PM UTC coverage: 89.744% (-2.2%) from 91.99%
23116334076

push

github

web-flow
Merge pull request #5449 from randombit/jack/fix-ocsp-sig-check

Fix OCSP response verification

104379 of 116307 relevant lines covered (89.74%)

11673079.73 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.81
/src/lib/utils/ghash/ghash.cpp
1
/*
2
* GCM GHASH
3
* (C) 2013,2015,2017 Jack Lloyd
4
* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity
5
* (C) 2024 René Meusel, Rohde & Schwarz Cybersecurity
6
*
7
* Botan is released under the Simplified BSD License (see license.txt)
8
*/
9

10
#include <botan/internal/ghash.h>
11

12
#include <botan/internal/ct_utils.h>
13
#include <botan/internal/loadstor.h>
14

15
#if defined(BOTAN_HAS_CPUID)
16
   #include <botan/internal/cpuid.h>
17
#endif
18

19
namespace Botan {
20

21
std::string GHASH::provider() const {
957✔
22
#if defined(BOTAN_HAS_GHASH_AVX512_CLMUL)
23
   if(auto feat = CPUID::check(CPUID::Feature::AVX512_CLMUL)) {
957✔
24
      return *feat;
×
25
   }
×
26
#endif
27

28
#if defined(BOTAN_HAS_GHASH_CLMUL_CPU)
29
   if(auto feat = CPUID::check(CPUID::Feature::HW_CLMUL)) {
957✔
30
      return *feat;
958✔
31
   }
479✔
32
#endif
33

34
#if defined(BOTAN_HAS_GHASH_CLMUL_VPERM)
35
   if(auto feat = CPUID::check(CPUID::Feature::SIMD_4X32)) {
478✔
36
      return *feat;
478✔
37
   }
239✔
38
#endif
39

40
   return "base";
239✔
41
}
42

43
void GHASH::ghash_multiply(std::span<uint8_t, GCM_BS> x, std::span<const uint8_t> input, size_t blocks) {
49,792✔
44
   BOTAN_ASSERT_NOMSG(input.size() % GCM_BS == 0);
49,792✔
45

46
#if defined(BOTAN_HAS_GHASH_AVX512_CLMUL)
47
   if(CPUID::has(CPUID::Feature::AVX512_CLMUL)) {
49,792✔
48
      BOTAN_ASSERT_NOMSG(!m_H_pow.empty());
×
49
      return ghash_multiply_avx512_clmul(x.data(), m_H_pow.data(), input.data(), blocks);
43,182✔
50
   }
51
#endif
52

53
#if defined(BOTAN_HAS_GHASH_CLMUL_CPU)
54
   if(CPUID::has(CPUID::Feature::HW_CLMUL)) {
49,792✔
55
      BOTAN_ASSERT_NOMSG(!m_H_pow.empty());
36,575✔
56
      return ghash_multiply_cpu(x.data(), m_H_pow, input.data(), blocks);
36,575✔
57
   }
58
#endif
59

60
#if defined(BOTAN_HAS_GHASH_CLMUL_VPERM)
61
   if(CPUID::has(CPUID::Feature::SIMD_2X64)) {
13,217✔
62
      return ghash_multiply_vperm(x.data(), m_HM.data(), input.data(), blocks);
6,607✔
63
   }
64
#endif
65

66
   auto scope = CT::scoped_poison(x);
6,610✔
67

68
   auto X = load_be<std::array<uint64_t, 2>>(x);
6,610✔
69

70
   BufferSlicer in(input);
6,610✔
71
   for(size_t b = 0; b != blocks; ++b) {
33,708✔
72
      const auto I = load_be<std::array<uint64_t, 2>>(in.take<GCM_BS>());
27,098✔
73
      X[0] ^= I[0];
27,098✔
74
      X[1] ^= I[1];
27,098✔
75

76
      std::array<uint64_t, 2> Z{};
27,098✔
77

78
      for(size_t i = 0; i != 64; ++i) {
1,761,370✔
79
         const auto X0MASK = CT::Mask<uint64_t>::expand_top_bit(X[0]);
1,734,272✔
80
         const auto X1MASK = CT::Mask<uint64_t>::expand_top_bit(X[1]);
1,734,272✔
81

82
         X[0] <<= 1;
1,734,272✔
83
         X[1] <<= 1;
1,734,272✔
84

85
         Z[0] = X0MASK.select(Z[0] ^ m_HM[4 * i], Z[0]);
1,734,272✔
86
         Z[1] = X0MASK.select(Z[1] ^ m_HM[4 * i + 1], Z[1]);
1,734,272✔
87

88
         Z[0] = X1MASK.select(Z[0] ^ m_HM[4 * i + 2], Z[0]);
1,734,272✔
89
         Z[1] = X1MASK.select(Z[1] ^ m_HM[4 * i + 3], Z[1]);
1,734,272✔
90
      }
91

92
      X[0] = Z[0];
27,098✔
93
      X[1] = Z[1];
27,098✔
94
   }
95

96
   store_be(x, X);
6,610✔
97
}
6,610✔
98

99
bool GHASH::has_keying_material() const {
74,725✔
100
   return !m_HM.empty() || !m_H_pow.empty();
74,725✔
101
}
102

103
void GHASH::key_schedule(std::span<const uint8_t> key) {
7,966✔
104
   m_H_ad = {0};
7,966✔
105
   m_ad_len = 0;
7,966✔
106
   m_text_len = 0;
7,966✔
107

108
   BOTAN_ASSERT_NOMSG(key.size() == GCM_BS);
7,966✔
109
   auto H = load_be<std::array<uint64_t, 2>>(key.first<GCM_BS>());
7,966✔
110

111
#if defined(BOTAN_HAS_GHASH_AVX512_CLMUL)
112
   if(CPUID::has(CPUID::Feature::AVX512_CLMUL)) {
7,966✔
113
      zap(m_HM);
×
114
      if(m_H_pow.size() != 32) {
×
115
         m_H_pow.resize(32);
×
116
      }
117
      ghash_precompute_avx512_clmul(key.data(), m_H_pow.data());
×
118
      // m_HM left empty
119
      return;
×
120
   }
121
#endif
122

123
#if defined(BOTAN_HAS_GHASH_CLMUL_CPU)
124
   if(CPUID::has(CPUID::Feature::HW_CLMUL)) {
7,966✔
125
      zap(m_HM);
5,788✔
126
      ghash_precompute_cpu(key.data(), m_H_pow);
5,788✔
127
      // m_HM left empty
128
      return;
5,788✔
129
   }
130
#endif
131

132
   const uint64_t R = 0xE100000000000000;
2,178✔
133

134
   if(m_HM.size() != 256) {
2,178✔
135
      m_HM.resize(256);
2,178✔
136
   }
137

138
   // precompute the multiples of H
139
   for(size_t i = 0; i != 2; ++i) {
6,534✔
140
      for(size_t j = 0; j != 64; ++j) {
283,140✔
141
         /*
142
         we interleave H^1, H^65, H^2, H^66, H3, H67, H4, H68
143
         to make indexing nicer in the multiplication code
144
         */
145
         m_HM[4 * j + 2 * i] = H[0];
278,784✔
146
         m_HM[4 * j + 2 * i + 1] = H[1];
278,784✔
147

148
         // GCM's bit ops are reversed so we carry out of the bottom
149
         const uint64_t carry = CT::Mask<uint64_t>::expand(H[1] & 1).if_set_return(R);
278,784✔
150
         H[1] = (H[1] >> 1) | (H[0] << 63);
278,784✔
151
         H[0] = (H[0] >> 1) ^ carry;
278,784✔
152
      }
153
   }
154
}
155

156
void GHASH::start(std::span<const uint8_t> nonce) {
14,555✔
157
   BOTAN_ARG_CHECK(nonce.size() == 16, "GHASH requires a 128-bit nonce");
14,555✔
158
   auto& n = m_nonce.emplace();
14,555✔
159
   copy_mem(n, nonce);
14,555✔
160
   copy_mem(m_ghash, m_H_ad);
14,555✔
161
}
14,555✔
162

163
void GHASH::set_associated_data(std::span<const uint8_t> input) {
9,417✔
164
   BOTAN_STATE_CHECK(!m_nonce);
9,417✔
165

166
   assert_key_material_set();
9,033✔
167
   m_H_ad = {0};
8,265✔
168
   ghash_update(m_H_ad, input);
8,265✔
169
   ghash_zeropad(m_H_ad);
8,265✔
170
   m_ad_len = input.size();
8,265✔
171
}
8,265✔
172

173
void GHASH::reset_associated_data() {
4,545✔
174
   // This should only be called in GMAC context
175
   BOTAN_STATE_CHECK(m_text_len == 0);
4,545✔
176
   assert_key_material_set();
4,545✔
177
   m_H_ad = {0};
4,545✔
178
   m_ad_len = 0;
4,545✔
179
}
4,545✔
180

181
void GHASH::update_associated_data(std::span<const uint8_t> ad) {
9,056✔
182
   assert_key_material_set();
9,056✔
183
   ghash_update(m_ghash, ad);
7,912✔
184
   m_ad_len += ad.size();
7,912✔
185
}
7,912✔
186

187
void GHASH::update(std::span<const uint8_t> input) {
38,204✔
188
   assert_key_material_set();
38,204✔
189
   BOTAN_STATE_CHECK(m_nonce);
37,832✔
190
   ghash_update(m_ghash, input);
37,256✔
191
   m_text_len += input.size();
37,256✔
192
}
37,256✔
193

194
void GHASH::final(std::span<uint8_t> mac) {
13,035✔
195
   BOTAN_ARG_CHECK(!mac.empty() && mac.size() <= GCM_BS, "GHASH output length");
13,035✔
196
   BOTAN_STATE_CHECK(m_nonce);
13,035✔
197
   assert_key_material_set();
12,639✔
198

199
   ghash_zeropad(m_ghash);
12,639✔
200
   ghash_final_block(m_ghash, m_ad_len, m_text_len);
12,639✔
201

202
   xor_buf(mac, std::span{m_ghash}.first(mac.size()), std::span{*m_nonce}.first(mac.size()));
12,639✔
203

204
   secure_scrub_memory(m_ghash);
12,639✔
205
   m_text_len = 0;
12,639✔
206
   m_nonce.reset();
12,639✔
207
}
12,639✔
208

209
void GHASH::nonce_hash(std::span<uint8_t, GCM_BS> y0, std::span<const uint8_t> nonce) {
1,248✔
210
   assert_key_material_set();
1,248✔
211
   BOTAN_STATE_CHECK(!m_nonce);
1,248✔
212

213
   ghash_update(y0, nonce);
1,248✔
214
   ghash_zeropad(y0);
1,248✔
215
   ghash_final_block(y0, 0, nonce.size());
1,248✔
216
}
1,248✔
217

218
void GHASH::clear() {
5,503✔
219
   zap(m_HM);
5,503✔
220
   zap(m_H_pow);
5,503✔
221
   this->reset_state();
5,503✔
222
}
5,503✔
223

224
void GHASH::reset_state() {
7,967✔
225
   m_H_ad = {0};
7,967✔
226
   secure_scrub_memory(m_ghash);
7,967✔
227
   if(m_nonce) {
7,967✔
228
      secure_scrub_memory(m_nonce.value());
1,344✔
229
      m_nonce.reset();
1,344✔
230
   }
231
   m_buffer.clear();
7,967✔
232
   m_text_len = m_ad_len = 0;
7,967✔
233
}
7,967✔
234

235
void GHASH::ghash_update(std::span<uint8_t, GCM_BS> x, std::span<const uint8_t> input) {
54,681✔
236
   BufferSlicer in(input);
54,681✔
237
   while(!in.empty()) {
174,441✔
238
      if(const auto one_block = m_buffer.handle_unaligned_data(in)) {
65,079✔
239
         ghash_multiply(x, one_block.value(), 1);
2,824✔
240
      }
241

242
      if(m_buffer.in_alignment()) {
65,079✔
243
         const auto [aligned_data, full_blocks] = m_buffer.aligned_data_to_process(in);
17,046✔
244
         if(full_blocks > 0) {
17,046✔
245
            ghash_multiply(x, aligned_data, full_blocks);
15,278✔
246
         }
247
      }
248
   }
249
   BOTAN_ASSERT_NOMSG(in.empty());
54,681✔
250
}
54,681✔
251

252
void GHASH::ghash_zeropad(std::span<uint8_t, GCM_BS> x) {
22,152✔
253
   if(!m_buffer.in_alignment()) {
22,152✔
254
      m_buffer.fill_up_with_zeros();
17,803✔
255
      ghash_multiply(x, m_buffer.consume(), 1);
17,803✔
256
   }
257
}
22,152✔
258

259
void GHASH::ghash_final_block(std::span<uint8_t, GCM_BS> x, uint64_t ad_len, uint64_t text_len) {
13,887✔
260
   BOTAN_STATE_CHECK(m_buffer.in_alignment());
13,887✔
261
   const auto final_block = store_be(8 * ad_len, 8 * text_len);
13,887✔
262
   ghash_multiply(x, final_block, 1);
13,887✔
263
}
13,887✔
264

265
}  // namespace Botan
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc