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

randombit / botan / 19070123910

04 Nov 2025 01:24PM UTC coverage: 92.016% (+1.3%) from 90.686%
19070123910

Pull #5102

github

web-flow
Merge 8f499800f into f8ef97b37
Pull Request #5102: Refactor: Keccak permutation has to be configured statically

102110 of 110970 relevant lines covered (92.02%)

12434884.94 hits per line

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

95.24
/src/lib/stream/shake_cipher/shake_cipher.cpp
1
/*
2
 * SHAKE-128 and SHAKE-256
3
 * (C) 2016 Jack Lloyd
4
 *     2022 René Meusel, Michael Boric - Rohde & Schwarz Cybersecurity
5
 *
6
 * Botan is released under the Simplified BSD License (see license.txt)
7
 */
8

9
#include <botan/internal/shake_cipher.h>
10

11
#include <botan/exceptn.h>
12
#include <botan/mem_ops.h>
13

14
namespace Botan {
15

16
namespace {
17

18
constexpr auto select_shake_cipher_permutation(size_t capacity) {
18,320✔
19
   switch(capacity) {
18,320✔
20
      case 256:
9,160✔
21
         return Keccak_Permutation({.capacity_bits = 256, .padding = KeccakPadding::shake()});
9,160✔
22
      case 512:
9,160✔
23
         return Keccak_Permutation({.capacity_bits = 512, .padding = KeccakPadding::shake()});
9,160✔
24
      default:
×
25
         throw Botan::Invalid_Argument("SHAKE_Cipher: Unsupported capacity");
×
26
   }
27
}
28

29
}  // namespace
30

31
SHAKE_Cipher::SHAKE_Cipher(size_t keccak_capacity) :
6,870✔
32
      m_keccak(select_shake_cipher_permutation(keccak_capacity)),
6,870✔
33
      m_has_keying_material(false),
6,870✔
34
      m_keystream_buffer(buffer_size()),
6,870✔
35
      m_bytes_generated(0) {}
6,870✔
36

37
void SHAKE_Cipher::set_iv_bytes(const uint8_t /*iv*/[], size_t length) {
6,870✔
38
   /*
39
   * This could be supported in some way (say, by treating iv as
40
   * a prefix or suffix of the key).
41
   */
42
   if(length != 0) {
6,870✔
43
      throw Invalid_IV_Length(name(), length);
4,580✔
44
   }
45
}
4,580✔
46

47
void SHAKE_Cipher::seek(uint64_t /*offset*/) {
2,290✔
48
   throw Not_Implemented("SHAKE_Cipher::seek");
2,290✔
49
}
50

51
void SHAKE_Cipher::clear() {
11,450✔
52
   m_keccak = select_shake_cipher_permutation(m_keccak.bit_capacity());
11,450✔
53
   m_has_keying_material = false;
11,450✔
54
   zeroise(m_keystream_buffer);
11,450✔
55
   m_bytes_generated = 0;
11,450✔
56
}
11,450✔
57

58
void SHAKE_Cipher::cipher_bytes(const uint8_t in[], uint8_t out[], size_t length) {
9,160✔
59
   assert_key_material_set();
9,160✔
60

61
   const auto block_size = m_keystream_buffer.size();
4,580✔
62

63
   auto cipher_some = [&](size_t bytes) {
9,252✔
64
      if(bytes > 0) {
4,672✔
65
         BOTAN_ASSERT_NOMSG(bytes <= block_size);
4,654✔
66
         BOTAN_ASSERT_NOMSG(bytes <= length);
4,654✔
67
         generate_keystream_internal(std::span(m_keystream_buffer).first(bytes));
4,654✔
68
         xor_buf(out, m_keystream_buffer.data(), in, bytes);
4,654✔
69
         out += bytes;
4,654✔
70
         in += bytes;
4,654✔
71
         length -= bytes;
4,654✔
72
      }
73
   };
9,252✔
74

75
   // Bring us back into alignment with the XOF's underlying blocks
76
   if(length > block_size) {
4,580✔
77
      const auto bytes_to_alignment = block_size - m_bytes_generated % block_size;
74✔
78
      cipher_some(bytes_to_alignment);
74✔
79
   }
80

81
   // Consume the XOF's output stream block-wise as long as we can
82
   while(length >= block_size) {
4,598✔
83
      cipher_some(block_size);
18✔
84
   }
85

86
   // Process remaining data, potentially causing misalignment
87
   cipher_some(length);
4,580✔
88
}
4,580✔
89

90
void SHAKE_Cipher::generate_keystream(uint8_t out[], size_t length) {
3,124✔
91
   assert_key_material_set();
3,124✔
92
   generate_keystream_internal({out, length});
3,124✔
93
}
3,124✔
94

95
void SHAKE_Cipher::generate_keystream_internal(std::span<uint8_t> out) {
7,778✔
96
   m_keccak.squeeze(out);
7,778✔
97
   m_bytes_generated += out.size();
4,654✔
98
}
×
99

100
void SHAKE_Cipher::key_schedule(std::span<const uint8_t> key) {
9,160✔
101
   clear();
9,160✔
102
   m_keccak.absorb(key);
9,160✔
103
   m_keccak.finish();
9,160✔
104
   m_has_keying_material = true;
9,160✔
105
}
9,160✔
106

107
Key_Length_Specification SHAKE_Cipher::key_spec() const {
13,740✔
108
   return Key_Length_Specification(1, 160);
13,740✔
109
}
110

111
SHAKE_128_Cipher::SHAKE_128_Cipher() : SHAKE_Cipher(256) {}
3,435✔
112

113
SHAKE_256_Cipher::SHAKE_256_Cipher() : SHAKE_Cipher(512) {}
3,435✔
114

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