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

randombit / botan / 13274522654

11 Feb 2025 11:26PM UTC coverage: 91.645% (-0.007%) from 91.652%
13274522654

push

github

web-flow
Merge pull request #4647 from randombit/jack/internal-assert-and-mem-ops

Avoid using mem_ops.h or assert.h in public headers

94854 of 103501 relevant lines covered (91.65%)

11334975.77 hits per line

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

98.31
/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 ? feedback_bits / 8 : m_block_size) {
705✔
20
   if(feedback_bits % 8 || 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::update_granularity() const {
553✔
49
   return feedback();
553✔
50
}
51

52
size_t CFB_Mode::ideal_granularity() const {
478✔
53
   // Multiplier here is arbitrary
54
   return 16 * feedback();
478✔
55
}
56

57
size_t CFB_Mode::minimum_final_size() const {
160✔
58
   return 0;
160✔
59
}
60

61
Key_Length_Specification CFB_Mode::key_spec() const {
1,090✔
62
   return cipher().key_spec();
1,090✔
63
}
64

65
size_t CFB_Mode::default_nonce_length() const {
466✔
66
   return block_size();
466✔
67
}
68

69
bool CFB_Mode::valid_nonce_length(size_t n) const {
1,880✔
70
   return (n == 0 || n == block_size());
1,850✔
71
}
72

73
bool CFB_Mode::has_keying_material() const {
5,042✔
74
   return m_cipher->has_keying_material();
5,042✔
75
}
76

77
void CFB_Mode::key_schedule(std::span<const uint8_t> key) {
784✔
78
   m_cipher->set_key(key);
784✔
79
   m_keystream.resize(m_cipher->block_size());
784✔
80
}
784✔
81

82
void CFB_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) {
1,538✔
83
   if(!valid_nonce_length(nonce_len)) {
1,538✔
84
      throw Invalid_IV_Length(name(), nonce_len);
316✔
85
   }
86

87
   assert_key_material_set();
1,380✔
88

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

101
void CFB_Mode::shift_register() {
6,413✔
102
   const size_t shift = feedback();
6,413✔
103
   const size_t carryover = block_size() - shift;
6,413✔
104

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

113
size_t CFB_Encryption::process_msg(uint8_t buf[], size_t sz) {
1,542✔
114
   assert_key_material_set();
1,542✔
115
   BOTAN_STATE_CHECK(m_state.empty() == false);
1,226✔
116

117
   const size_t shift = feedback();
1,068✔
118

119
   size_t left = sz;
1,068✔
120

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

124
      xor_buf(m_keystream.data() + m_keystream_pos, buf, take);
13✔
125
      copy_mem(buf, m_keystream.data() + m_keystream_pos, take);
13✔
126

127
      m_keystream_pos += take;
13✔
128
      left -= take;
13✔
129
      buf += take;
13✔
130

131
      if(m_keystream_pos == shift) {
13✔
132
         shift_register();
10✔
133
      }
134
   }
135

136
   while(left >= shift) {
3,757✔
137
      xor_buf(m_keystream.data(), buf, shift);
2,689✔
138
      copy_mem(buf, m_keystream.data(), shift);
2,689✔
139

140
      left -= shift;
2,689✔
141
      buf += shift;
2,689✔
142
      shift_register();
2,689✔
143
   }
144

145
   if(left > 0) {
1,068✔
146
      xor_buf(m_keystream.data(), buf, left);
118✔
147
      copy_mem(buf, m_keystream.data(), left);
118✔
148
      m_keystream_pos += left;
118✔
149
   }
150

151
   return sz;
1,068✔
152
}
153

154
void CFB_Encryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
616✔
155
   update(buffer, offset);
616✔
156
}
379✔
157

158
namespace {
159

160
inline void xor_copy(uint8_t buf[], uint8_t key_buf[], size_t len) {
3,943✔
161
   for(size_t i = 0; i != len; ++i) {
40,400✔
162
      uint8_t k = key_buf[i];
36,457✔
163
      key_buf[i] = buf[i];
36,457✔
164
      buf[i] ^= k;
36,457✔
165
   }
166
}
167

168
}  // namespace
169

170
size_t CFB_Decryption::process_msg(uint8_t buf[], size_t sz) {
1,646✔
171
   assert_key_material_set();
1,646✔
172
   BOTAN_STATE_CHECK(m_state.empty() == false);
1,330✔
173

174
   const size_t shift = feedback();
1,172✔
175

176
   size_t left = sz;
1,172✔
177

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

181
      xor_copy(buf, m_keystream.data() + m_keystream_pos, take);
13✔
182

183
      m_keystream_pos += take;
13✔
184
      left -= take;
13✔
185
      buf += take;
13✔
186

187
      if(m_keystream_pos == shift) {
13✔
188
         shift_register();
10✔
189
      }
190
   }
191

192
   while(left >= shift) {
4,876✔
193
      xor_copy(buf, m_keystream.data(), shift);
3,704✔
194
      left -= shift;
3,704✔
195
      buf += shift;
3,704✔
196
      shift_register();
3,704✔
197
   }
198

199
   if(left > 0) {
1,172✔
200
      xor_copy(buf, m_keystream.data(), left);
226✔
201
      m_keystream_pos += left;
226✔
202
   }
203

204
   return sz;
1,172✔
205
}
206

207
void CFB_Decryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
616✔
208
   update(buffer, offset);
616✔
209
}
379✔
210

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