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

randombit / botan / 16239649803

12 Jul 2025 03:54PM UTC coverage: 90.588% (+0.02%) from 90.572%
16239649803

Pull #4880

github

web-flow
Merge 79ae69b5e into e3b3452ec
Pull Request #4880: Refactor: Cipher_Mode::finish_msg() using std::span

99178 of 109483 relevant lines covered (90.59%)

12365337.5 hits per line

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

98.36
/src/lib/modes/cfb/cfb.cpp
1
/*
2
* CFB Mode
3
* (C) 1999-2007,2013,2017 Jack Lloyd
4
* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity
5
*
6
* Botan is released under the Simplified BSD License (see license.txt)
7
*/
8

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

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

14
namespace Botan {
15

16
CFB_Mode::CFB_Mode(std::unique_ptr<BlockCipher> cipher, size_t feedback_bits) :
705✔
17
      m_cipher(std::move(cipher)),
705✔
18
      m_block_size(m_cipher->block_size()),
705✔
19
      m_feedback_bytes(feedback_bits != 0 ? feedback_bits / 8 : m_block_size) {
705✔
20
   if(feedback_bits % 8 != 0 || feedback() > m_block_size) {
705✔
21
      throw Invalid_Argument(fmt("{} does not support feedback bits of {}", name(), feedback_bits));
×
22
   }
23
}
705✔
24

25
void CFB_Mode::clear() {
158✔
26
   m_cipher->clear();
158✔
27
   m_keystream.clear();
158✔
28
   reset();
158✔
29
}
158✔
30

31
void CFB_Mode::reset() {
474✔
32
   m_state.clear();
474✔
33
   zeroise(m_keystream);
474✔
34
}
474✔
35

36
std::string CFB_Mode::name() const {
948✔
37
   if(feedback() == cipher().block_size()) {
948✔
38
      return fmt("{}/CFB", cipher().name());
396✔
39
   } else {
40
      return fmt("{}/CFB({})", cipher().name(), feedback() * 8);
552✔
41
   }
42
}
43

44
size_t CFB_Mode::output_length(size_t input_length) const {
158✔
45
   return input_length;
158✔
46
}
47

48
size_t CFB_Mode::bytes_needed_for_finalization(size_t final_input_length) const {
1,232✔
49
   return output_length(final_input_length);
1,232✔
50
}
51

52
size_t CFB_Mode::update_granularity() const {
553✔
53
   return feedback();
553✔
54
}
55

56
size_t CFB_Mode::ideal_granularity() const {
478✔
57
   // Multiplier here is arbitrary
58
   return 16 * feedback();
478✔
59
}
60

61
size_t CFB_Mode::minimum_final_size() const {
160✔
62
   return 0;
160✔
63
}
64

65
Key_Length_Specification CFB_Mode::key_spec() const {
1,090✔
66
   return cipher().key_spec();
1,090✔
67
}
68

69
size_t CFB_Mode::default_nonce_length() const {
466✔
70
   return block_size();
466✔
71
}
72

73
bool CFB_Mode::valid_nonce_length(size_t n) const {
1,880✔
74
   return (n == 0 || n == block_size());
1,850✔
75
}
76

77
bool CFB_Mode::has_keying_material() const {
5,042✔
78
   return m_cipher->has_keying_material();
5,042✔
79
}
80

81
void CFB_Mode::key_schedule(std::span<const uint8_t> key) {
784✔
82
   m_cipher->set_key(key);
784✔
83
   m_keystream.resize(m_cipher->block_size());
784✔
84
}
784✔
85

86
void CFB_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) {
1,538✔
87
   if(!valid_nonce_length(nonce_len)) {
1,538✔
88
      throw Invalid_IV_Length(name(), nonce_len);
316✔
89
   }
90

91
   assert_key_material_set();
1,380✔
92

93
   if(nonce_len == 0) {
1,380✔
94
      if(m_state.empty()) {
30✔
95
         throw Invalid_State("CFB requires a non-empty initial nonce");
×
96
      }
97
      // No reason to encrypt state->keystream_buf, because no change
98
   } else {
99
      m_state.assign(nonce, nonce + nonce_len);
1,350✔
100
      cipher().encrypt(m_state, m_keystream);
1,350✔
101
      m_keystream_pos = 0;
1,350✔
102
   }
103
}
1,380✔
104

105
void CFB_Mode::shift_register() {
6,413✔
106
   const size_t shift = feedback();
6,413✔
107
   const size_t carryover = block_size() - shift;
6,413✔
108

109
   if(carryover > 0) {
6,413✔
110
      copy_mem(m_state.data(), &m_state[shift], carryover);
3,104✔
111
   }
112
   copy_mem(&m_state[carryover], m_keystream.data(), shift);
6,413✔
113
   cipher().encrypt(m_state, m_keystream);
6,413✔
114
   m_keystream_pos = 0;
6,413✔
115
}
6,413✔
116

117
size_t CFB_Encryption::process_msg(uint8_t buf[], size_t sz) {
1,542✔
118
   assert_key_material_set();
1,542✔
119
   BOTAN_STATE_CHECK(m_state.empty() == false);
1,226✔
120

121
   const size_t shift = feedback();
1,068✔
122

123
   size_t left = sz;
1,068✔
124

125
   if(m_keystream_pos != 0) {
1,068✔
126
      const size_t take = std::min<size_t>(left, shift - m_keystream_pos);
13✔
127

128
      xor_buf(m_keystream.data() + m_keystream_pos, buf, take);
13✔
129
      copy_mem(buf, m_keystream.data() + m_keystream_pos, take);
13✔
130

131
      m_keystream_pos += take;
13✔
132
      left -= take;
13✔
133
      buf += take;
13✔
134

135
      if(m_keystream_pos == shift) {
13✔
136
         shift_register();
10✔
137
      }
138
   }
139

140
   while(left >= shift) {
3,757✔
141
      xor_buf(m_keystream.data(), buf, shift);
2,689✔
142
      copy_mem(buf, m_keystream.data(), shift);
2,689✔
143

144
      left -= shift;
2,689✔
145
      buf += shift;
2,689✔
146
      shift_register();
2,689✔
147
   }
148

149
   if(left > 0) {
1,068✔
150
      xor_buf(m_keystream.data(), buf, left);
118✔
151
      copy_mem(buf, m_keystream.data(), left);
118✔
152
      m_keystream_pos += left;
118✔
153
   }
154

155
   return sz;
1,068✔
156
}
157

158
size_t CFB_Encryption::finish_msg(std::span<uint8_t> final_block, [[maybe_unused]] size_t input_bytes) {
616✔
159
   BOTAN_DEBUG_ASSERT(final_block.size() == bytes_needed_for_finalization(input_bytes));
616✔
160
   process(final_block);
616✔
161
   return final_block.size();
379✔
162
}
163

164
namespace {
165

166
inline void xor_copy(uint8_t buf[], uint8_t key_buf[], size_t len) {
3,943✔
167
   for(size_t i = 0; i != len; ++i) {
40,400✔
168
      uint8_t k = key_buf[i];
36,457✔
169
      key_buf[i] = buf[i];
36,457✔
170
      buf[i] ^= k;
36,457✔
171
   }
172
}
173

174
}  // namespace
175

176
size_t CFB_Decryption::process_msg(uint8_t buf[], size_t sz) {
1,646✔
177
   assert_key_material_set();
1,646✔
178
   BOTAN_STATE_CHECK(m_state.empty() == false);
1,330✔
179

180
   const size_t shift = feedback();
1,172✔
181

182
   size_t left = sz;
1,172✔
183

184
   if(m_keystream_pos != 0) {
1,172✔
185
      const size_t take = std::min<size_t>(left, shift - m_keystream_pos);
13✔
186

187
      xor_copy(buf, m_keystream.data() + m_keystream_pos, take);
13✔
188

189
      m_keystream_pos += take;
13✔
190
      left -= take;
13✔
191
      buf += take;
13✔
192

193
      if(m_keystream_pos == shift) {
13✔
194
         shift_register();
10✔
195
      }
196
   }
197

198
   while(left >= shift) {
4,876✔
199
      xor_copy(buf, m_keystream.data(), shift);
3,704✔
200
      left -= shift;
3,704✔
201
      buf += shift;
3,704✔
202
      shift_register();
3,704✔
203
   }
204

205
   if(left > 0) {
1,172✔
206
      xor_copy(buf, m_keystream.data(), left);
226✔
207
      m_keystream_pos += left;
226✔
208
   }
209

210
   return sz;
1,172✔
211
}
212

213
size_t CFB_Decryption::finish_msg(std::span<uint8_t> buffer, [[maybe_unused]] size_t input_bytes) {
616✔
214
   BOTAN_DEBUG_ASSERT(buffer.size() == bytes_needed_for_finalization(input_bytes));
616✔
215
   process(buffer);
616✔
216
   return buffer.size();
379✔
217
}
218

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