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

randombit / botan / 23963731334

03 Apr 2026 09:29PM UTC coverage: 91.886% (+2.4%) from 89.501%
23963731334

push

github

web-flow
Merge pull request #5518 from randombit/jack/fix-unknown-ext-handling

Improve handling of X509 extensions which fail to parse

108312 of 117876 relevant lines covered (91.89%)

11232507.64 hits per line

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

83.57
/src/lib/pbkdf/argon2/argon2.cpp
1
/**
2
* (C) 2018,2019,2022 Jack Lloyd
3
*
4
* Botan is released under the Simplified BSD License (see license.txt)
5
*/
6

7
#include <botan/argon2.h>
8

9
#include <botan/hash.h>
10
#include <botan/mem_ops.h>
11
#include <botan/internal/fmt.h>
12
#include <botan/internal/loadstor.h>
13
#include <botan/internal/mem_utils.h>
14
#include <botan/internal/rotate.h>
15
#include <limits>
16

17
#if defined(BOTAN_HAS_THREAD_UTILS)
18
   #include <botan/internal/thread_pool.h>
19
#endif
20

21
#if defined(BOTAN_HAS_CPUID)
22
   #include <botan/internal/cpuid.h>
23
#endif
24

25
namespace Botan {
26

27
namespace {
28

29
const size_t SYNC_POINTS = 4;
30

31
void argon2_H0(uint8_t H0[64],
1,106✔
32
               HashFunction& blake2b,
33
               size_t output_len,
34
               const char* password,
35
               size_t password_len,
36
               const uint8_t salt[],
37
               size_t salt_len,
38
               const uint8_t key[],
39
               size_t key_len,
40
               const uint8_t ad[],
41
               size_t ad_len,
42
               size_t y,
43
               size_t p,
44
               size_t M,
45
               size_t t) {
46
   const uint8_t v = 19;  // Argon2 version code
1,106✔
47

48
   blake2b.update_le(static_cast<uint32_t>(p));
1,106✔
49
   blake2b.update_le(static_cast<uint32_t>(output_len));
1,106✔
50
   blake2b.update_le(static_cast<uint32_t>(M));
1,106✔
51
   blake2b.update_le(static_cast<uint32_t>(t));
1,106✔
52
   blake2b.update_le(static_cast<uint32_t>(v));
1,106✔
53
   blake2b.update_le(static_cast<uint32_t>(y));
1,106✔
54

55
   blake2b.update_le(static_cast<uint32_t>(password_len));
1,106✔
56
   blake2b.update(as_span_of_bytes(password, password_len));
1,106✔
57

58
   blake2b.update_le(static_cast<uint32_t>(salt_len));
1,106✔
59
   blake2b.update(salt, salt_len);
1,106✔
60

61
   blake2b.update_le(static_cast<uint32_t>(key_len));
1,106✔
62
   blake2b.update(key, key_len);
1,106✔
63

64
   blake2b.update_le(static_cast<uint32_t>(ad_len));
1,106✔
65
   blake2b.update(ad, ad_len);
1,106✔
66

67
   blake2b.final(H0);
1,106✔
68
}
1,106✔
69

70
void extract_key(uint8_t output[], size_t output_len, const secure_vector<uint64_t>& B, size_t memory, size_t threads) {
1,106✔
71
   const size_t lanes = memory / threads;
1,106✔
72

73
   uint64_t sum[128] = {0};
1,106✔
74

75
   for(size_t lane = 0; lane != threads; ++lane) {
4,390✔
76
      const size_t start = 128 * (lane * lanes + lanes - 1);
3,284✔
77
      const size_t end = 128 * (lane * lanes + lanes);
3,284✔
78

79
      for(size_t j = start; j != end; ++j) {
423,636✔
80
         sum[j % 128] ^= B[j];
420,352✔
81
      }
82
   }
83

84
   if(output_len <= 64) {
1,106✔
85
      auto blake2b = HashFunction::create_or_throw(fmt("BLAKE2b({})", output_len * 8));
332✔
86
      blake2b->update_le(static_cast<uint32_t>(output_len));
332✔
87
      for(size_t i = 0; i != 128; ++i) {  // NOLINT(modernize-loop-convert)
42,828✔
88
         blake2b->update_le(sum[i]);
42,496✔
89
      }
90
      blake2b->final(output);
664✔
91
   } else {
332✔
92
      secure_vector<uint8_t> T(64);
774✔
93

94
      auto blake2b = HashFunction::create_or_throw("BLAKE2b(512)");
774✔
95
      blake2b->update_le(static_cast<uint32_t>(output_len));
774✔
96
      for(size_t i = 0; i != 128; ++i) {  // NOLINT(modernize-loop-convert)
99,846✔
97
         blake2b->update_le(sum[i]);
99,072✔
98
      }
99
      blake2b->final(std::span{T});
774✔
100

101
      while(output_len > 64) {
774✔
102
         copy_mem(output, T.data(), 32);
3,468✔
103
         output_len -= 32;
3,468✔
104
         output += 32;
3,468✔
105

106
         if(output_len > 64) {
3,468✔
107
            blake2b->update(T);
2,694✔
108
            blake2b->final(std::span{T});
2,694✔
109
         }
110
      }
111

112
      if(output_len == 64) {
774✔
113
         blake2b->update(T);
24✔
114
         blake2b->final(output);
48✔
115
      } else {
116
         auto blake2b_f = HashFunction::create_or_throw(fmt("BLAKE2b({})", output_len * 8));
750✔
117
         blake2b_f->update(T);
750✔
118
         blake2b_f->final(output);
1,500✔
119
      }
750✔
120
   }
1,548✔
121
}
1,106✔
122

123
void init_blocks(
1,106✔
124
   secure_vector<uint64_t>& B, HashFunction& blake2b, const uint8_t H0[64], size_t memory, size_t threads) {
125
   BOTAN_ASSERT_NOMSG(B.size() >= threads * 256);
1,106✔
126

127
   for(size_t i = 0; i != threads; ++i) {
4,390✔
128
      const size_t B_off = i * (memory / threads);
3,284✔
129

130
      BOTAN_ASSERT_NOMSG(B.size() >= 128 * (B_off + 2));
3,284✔
131

132
      for(size_t j = 0; j != 2; ++j) {
9,852✔
133
         uint8_t T[64] = {0};
6,568✔
134

135
         blake2b.update_le(static_cast<uint32_t>(1024));
6,568✔
136
         blake2b.update(H0, 64);
6,568✔
137
         blake2b.update_le(static_cast<uint32_t>(j));
6,568✔
138
         blake2b.update_le(static_cast<uint32_t>(i));
6,568✔
139
         blake2b.final(T);
6,568✔
140

141
         for(size_t k = 0; k != 30; ++k) {
203,608✔
142
            load_le(&B[128 * (B_off + j) + 4 * k], T, 32 / 8);
197,040✔
143
            blake2b.update(T, 64);
197,040✔
144
            blake2b.final(T);
394,080✔
145
         }
146

147
         load_le(&B[128 * (B_off + j) + 4 * 30], T, 64 / 8);
6,568✔
148
      }
149
   }
150
}
1,106✔
151

152
BOTAN_FORCE_INLINE void blamka_G(uint64_t& A, uint64_t& B, uint64_t& C, uint64_t& D) {
×
153
   A += B + (static_cast<uint64_t>(2) * static_cast<uint32_t>(A)) * static_cast<uint32_t>(B);
×
154
   D = rotr<32>(A ^ D);
×
155

156
   C += D + (static_cast<uint64_t>(2) * static_cast<uint32_t>(C)) * static_cast<uint32_t>(D);
×
157
   B = rotr<24>(B ^ C);
×
158

159
   A += B + (static_cast<uint64_t>(2) * static_cast<uint32_t>(A)) * static_cast<uint32_t>(B);
×
160
   D = rotr<16>(A ^ D);
×
161

162
   C += D + (static_cast<uint64_t>(2) * static_cast<uint32_t>(C)) * static_cast<uint32_t>(D);
×
163
   B = rotr<63>(B ^ C);
×
164
}
165

166
}  // namespace
167

168
void Argon2::blamka(uint64_t N[128], uint64_t T[128]) {
2,663,092✔
169
#if defined(BOTAN_HAS_ARGON2_AVX512)
170
   if(CPUID::has(CPUID::Feature::AVX512)) {
2,663,092✔
171
      return Argon2::blamka_avx512(N, T);
2,663,092✔
172
   }
173
#endif
174

175
#if defined(BOTAN_HAS_ARGON2_AVX2)
176
   if(CPUID::has(CPUID::Feature::AVX2)) {
×
177
      return Argon2::blamka_avx2(N, T);
×
178
   }
179
#endif
180

181
#if defined(BOTAN_HAS_ARGON2_SIMD64)
182
   if(CPUID::has(CPUID::Feature::SIMD_2X64)) {
×
183
      return Argon2::blamka_simd64(N, T);
×
184
   }
185
#endif
186

187
   copy_mem(T, N, 128);
×
188

189
   for(size_t i = 0; i != 128; i += 16) {
×
190
      blamka_G(T[i + 0], T[i + 4], T[i + 8], T[i + 12]);
×
191
      blamka_G(T[i + 1], T[i + 5], T[i + 9], T[i + 13]);
×
192
      blamka_G(T[i + 2], T[i + 6], T[i + 10], T[i + 14]);
×
193
      blamka_G(T[i + 3], T[i + 7], T[i + 11], T[i + 15]);
×
194

195
      blamka_G(T[i + 0], T[i + 5], T[i + 10], T[i + 15]);
×
196
      blamka_G(T[i + 1], T[i + 6], T[i + 11], T[i + 12]);
×
197
      blamka_G(T[i + 2], T[i + 7], T[i + 8], T[i + 13]);
×
198
      blamka_G(T[i + 3], T[i + 4], T[i + 9], T[i + 14]);
×
199
   }
200

201
   for(size_t i = 0; i != 128 / 8; i += 2) {
×
202
      blamka_G(T[i + 0], T[i + 32], T[i + 64], T[i + 96]);
×
203
      blamka_G(T[i + 1], T[i + 33], T[i + 65], T[i + 97]);
×
204
      blamka_G(T[i + 16], T[i + 48], T[i + 80], T[i + 112]);
×
205
      blamka_G(T[i + 17], T[i + 49], T[i + 81], T[i + 113]);
×
206

207
      blamka_G(T[i + 0], T[i + 33], T[i + 80], T[i + 113]);
×
208
      blamka_G(T[i + 1], T[i + 48], T[i + 81], T[i + 96]);
×
209
      blamka_G(T[i + 16], T[i + 49], T[i + 64], T[i + 97]);
×
210
      blamka_G(T[i + 17], T[i + 32], T[i + 65], T[i + 112]);
×
211
   }
212

213
   for(size_t i = 0; i != 128; ++i) {
×
214
      N[i] ^= T[i];
×
215
   }
216
}
217

218
namespace {
219

220
void gen_2i_addresses(uint64_t T[128],
81,206✔
221
                      uint64_t B[128],
222
                      size_t n,
223
                      size_t lane,
224
                      size_t slice,
225
                      size_t memory,
226
                      size_t time,
227
                      size_t mode,
228
                      size_t cnt) {
229
   clear_mem(B, 128);
162,412✔
230

231
   B[0] = n;
81,206✔
232
   B[1] = lane;
81,206✔
233
   B[2] = slice;
81,206✔
234
   B[3] = memory;
81,206✔
235
   B[4] = time;
81,206✔
236
   B[5] = mode;
81,206✔
237
   B[6] = cnt;
81,206✔
238

239
   for(size_t r = 0; r != 2; ++r) {
243,618✔
240
      Argon2::blamka(B, T);
162,412✔
241
   }
242
}
243

244
uint32_t index_alpha(
2,500,680✔
245
   uint64_t random, size_t lanes, size_t segments, size_t threads, size_t n, size_t slice, size_t lane, size_t index) {
246
   size_t ref_lane = static_cast<uint32_t>(random >> 32) % threads;
2,500,680✔
247

248
   if(n == 0 && slice == 0) {
2,500,680✔
249
      ref_lane = lane;
222,018✔
250
   }
251

252
   size_t m = 3 * segments;
2,500,680✔
253
   size_t s = ((slice + 1) % 4) * segments;
2,500,680✔
254

255
   if(lane == ref_lane) {
2,500,680✔
256
      m += index;
973,380✔
257
   }
258

259
   if(n == 0) {
2,500,680✔
260
      m = slice * segments;
907,776✔
261
      s = 0;
907,776✔
262
      if(slice == 0 || lane == ref_lane) {
907,776✔
263
         m += index;
860,673✔
264
      }
265
   }
266

267
   if(index == 0 || lane == ref_lane) {
2,500,680✔
268
      m -= 1;
1,162,935✔
269
   }
270

271
   uint64_t p = static_cast<uint32_t>(random);
2,500,680✔
272
   p = (p * p) >> 32;
2,500,680✔
273
   p = (p * m) >> 32;
2,500,680✔
274

275
   return static_cast<uint32_t>(ref_lane * lanes + (s + m - (p + 1)) % lanes);
2,500,680✔
276
}
277

278
void process_block(secure_vector<uint64_t>& B,
201,620✔
279
                   size_t n,
280
                   size_t slice,
281
                   size_t lane,
282
                   size_t lanes,
283
                   size_t segments,
284
                   size_t threads,
285
                   uint8_t mode,
286
                   size_t memory,
287
                   size_t time) {
288
   uint64_t T[128];
201,620✔
289
   size_t index = 0;
201,620✔
290
   if(n == 0 && slice == 0) {
201,620✔
291
      index = 2;
3,284✔
292
   }
293

294
   const bool use_2i = mode == 1 || (mode == 2 && n == 0 && slice < SYNC_POINTS / 2);
201,620✔
295

296
   uint64_t addresses[128];
297
   size_t address_counter = 1;
279,352✔
298

299
   if(use_2i) {
300
      gen_2i_addresses(T, addresses, n, lane, slice, memory, time, mode, address_counter);
279,352✔
301
   }
302

303
   while(index < segments) {
2,702,300✔
304
      const size_t offset = lane * lanes + slice * segments + index;
2,500,680✔
305

306
      size_t prev = offset - 1;
2,500,680✔
307
      if(index == 0 && slice == 0) {
2,500,680✔
308
         prev += lanes;
47,121✔
309
      }
310

311
      if(use_2i && index > 0 && index % 128 == 0) {
2,500,680✔
312
         address_counter += 1;
3,474✔
313
         gen_2i_addresses(T, addresses, n, lane, slice, memory, time, mode, address_counter);
3,474✔
314
      }
315

316
      const uint64_t random = use_2i ? addresses[index % 128] : B.at(128 * prev);
2,500,680✔
317
      const size_t new_offset = index_alpha(random, lanes, segments, threads, n, slice, lane, index);
2,500,680✔
318

319
      uint64_t N[128];
2,500,680✔
320
      for(size_t i = 0; i != 128; ++i) {
322,587,720✔
321
         N[i] = B[128 * prev + i] ^ B[128 * new_offset + i];
320,087,040✔
322
      }
323

324
      Argon2::blamka(N, T);
2,500,680✔
325

326
      for(size_t i = 0; i != 128; ++i) {
322,587,720✔
327
         B[128 * offset + i] ^= N[i];
320,087,040✔
328
      }
329

330
      index += 1;
2,500,680✔
331
   }
332
}
201,620✔
333

334
void process_blocks(secure_vector<uint64_t>& B, size_t t, size_t memory, size_t threads, uint8_t mode) {
1,106✔
335
   const size_t lanes = memory / threads;
1,106✔
336
   const size_t segments = lanes / SYNC_POINTS;
1,106✔
337

338
#if defined(BOTAN_HAS_THREAD_UTILS)
339
   if(threads > 1) {
1,106✔
340
      auto& thread_pool = Thread_Pool::global_instance();
114✔
341

342
      for(size_t n = 0; n != t; ++n) {
1,575✔
343
         for(size_t slice = 0; slice != SYNC_POINTS; ++slice) {
7,305✔
344
            std::vector<std::future<void>> fut_results;
5,844✔
345
            fut_results.reserve(threads);
5,844✔
346

347
            for(size_t lane = 0; lane != threads; ++lane) {
203,460✔
348
               fut_results.push_back(thread_pool.run(
395,232✔
349
                  process_block, std::ref(B), n, slice, lane, lanes, segments, threads, mode, memory, t));
395,232✔
350
            }
351

352
            for(auto& fut : fut_results) {
203,460✔
353
               fut.get();
197,616✔
354
            }
355
         }
5,844✔
356
      }
357

358
      return;
114✔
359
   }
360
#endif
361

362
   for(size_t n = 0; n != t; ++n) {
1,993✔
363
      for(size_t slice = 0; slice != SYNC_POINTS; ++slice) {
5,005✔
364
         for(size_t lane = 0; lane != threads; ++lane) {
8,008✔
365
            process_block(B, n, slice, lane, lanes, segments, threads, mode, memory, t);
4,004✔
366
         }
367
      }
368
   }
369
}
370

371
}  // namespace
372

373
void Argon2::argon2(uint8_t output[],
1,106✔
374
                    size_t output_len,
375
                    const char* password,
376
                    size_t password_len,
377
                    const uint8_t salt[],
378
                    size_t salt_len,
379
                    const uint8_t key[],
380
                    size_t key_len,
381
                    const uint8_t ad[],
382
                    size_t ad_len) const {
383
   BOTAN_ARG_CHECK(output_len >= 4 && output_len <= std::numeric_limits<uint32_t>::max(),
1,106✔
384
                   "Invalid Argon2 output length");
385
   BOTAN_ARG_CHECK(password_len <= std::numeric_limits<uint32_t>::max(), "Invalid Argon2 password length");
1,106✔
386
   BOTAN_ARG_CHECK(salt_len <= std::numeric_limits<uint32_t>::max(), "Invalid Argon2 salt length");
1,106✔
387
   BOTAN_ARG_CHECK(key_len <= std::numeric_limits<uint32_t>::max(), "Invalid Argon2 key length");
1,106✔
388
   BOTAN_ARG_CHECK(ad_len <= std::numeric_limits<uint32_t>::max(), "Invalid Argon2 ad length");
1,106✔
389

390
   auto blake2 = HashFunction::create_or_throw("BLAKE2b");
1,106✔
391

392
   uint8_t H0[64] = {0};
1,106✔
393
   argon2_H0(H0,
1,106✔
394
             *blake2,
1,106✔
395
             output_len,
396
             password,
397
             password_len,
398
             salt,
399
             salt_len,
400
             key,
401
             key_len,
402
             ad,
403
             ad_len,
404
             m_family,
1,106✔
405
             m_p,
1,106✔
406
             m_M,
1,106✔
407
             m_t);
1,106✔
408

409
   const size_t memory = (m_M / (SYNC_POINTS * m_p)) * (SYNC_POINTS * m_p);
1,106✔
410

411
   secure_vector<uint64_t> B(memory * 1024 / 8);
1,106✔
412

413
   init_blocks(B, *blake2, H0, memory, m_p);
1,106✔
414
   process_blocks(B, m_t, memory, m_p, m_family);
1,106✔
415

416
   clear_mem(output, output_len);
1,106✔
417
   extract_key(output, output_len, B, memory, m_p);
1,106✔
418
}
2,212✔
419

420
}  // 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