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

randombit / botan / 5123321399

30 May 2023 04:06PM UTC coverage: 92.213% (+0.004%) from 92.209%
5123321399

Pull #3558

github

web-flow
Merge dd72f7389 into 057bcbc35
Pull Request #3558: Add braces around all if/else statements

75602 of 81986 relevant lines covered (92.21%)

11859779.3 hits per line

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

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

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

12
#include <botan/internal/fmt.h>
13
#include <botan/internal/mode_pad.h>
14
#include <botan/internal/rounding.h>
15

16
namespace Botan {
17

18
CBC_Mode::CBC_Mode(std::unique_ptr<BlockCipher> cipher, std::unique_ptr<BlockCipherModePaddingMethod> padding) :
2,836✔
19
      m_cipher(std::move(cipher)), m_padding(std::move(padding)), m_block_size(m_cipher->block_size()) {
2,836✔
20
   if(m_padding && !m_padding->valid_blocksize(m_block_size)) {
2,836✔
21
      throw Invalid_Argument(fmt("Padding {} cannot be used with {} in CBC mode", m_padding->name(), m_cipher->name()));
×
22
   }
23
}
2,836✔
24

25
void CBC_Mode::clear() {
660✔
26
   m_cipher->clear();
660✔
27
   reset();
660✔
28
}
660✔
29

30
void CBC_Mode::reset() { m_state.clear(); }
989✔
31

32
std::string CBC_Mode::name() const {
1,318✔
33
   if(m_padding) {
1,318✔
34
      return fmt("{}/CBC/{}", cipher().name(), padding().name());
1,126✔
35
   } else {
36
      return fmt("{}/CBC/CTS", cipher().name());
192✔
37
   }
38
}
39

40
size_t CBC_Mode::update_granularity() const { return cipher().block_size(); }
2,308✔
41

42
size_t CBC_Mode::ideal_granularity() const { return cipher().parallel_bytes(); }
3,228✔
43

44
Key_Length_Specification CBC_Mode::key_spec() const { return cipher().key_spec(); }
7,774✔
45

46
size_t CBC_Mode::default_nonce_length() const { return block_size(); }
903✔
47

48
bool CBC_Mode::valid_nonce_length(size_t n) const { return (n == 0 || n == block_size()); }
8,048✔
49

50
bool CBC_Mode::has_keying_material() const { return m_cipher->has_keying_material(); }
1,974✔
51

52
void CBC_Mode::key_schedule(const uint8_t key[], size_t length) {
3,389✔
53
   m_cipher->set_key(key, length);
3,389✔
54
   m_state.clear();
3,389✔
55
}
3,389✔
56

57
void CBC_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) {
7,598✔
58
   if(!valid_nonce_length(nonce_len)) {
7,598✔
59
      throw Invalid_IV_Length(name(), nonce_len);
1,316✔
60
   }
61

62
   /*
63
   * A nonce of zero length means carry the last ciphertext value over
64
   * as the new IV, as unfortunately some protocols require this. If
65
   * this is the first message then we use an IV of all zeros.
66
   */
67
   if(nonce_len) {
6,940✔
68
      m_state.assign(nonce, nonce + nonce_len);
6,920✔
69
   } else if(m_state.empty()) {
20✔
70
      m_state.resize(m_cipher->block_size());
14✔
71
   }
72
   // else leave the state alone
73
}
6,940✔
74

75
size_t CBC_Encryption::minimum_final_size() const { return 0; }
284✔
76

77
size_t CBC_Encryption::output_length(size_t input_length) const {
283✔
78
   if(input_length == 0) {
283✔
79
      return block_size();
4✔
80
   } else {
81
      return round_up(input_length, block_size());
279✔
82
   }
83
}
84

85
size_t CBC_Encryption::process_msg(uint8_t buf[], size_t sz) {
5,326✔
86
   BOTAN_STATE_CHECK(state().empty() == false);
5,326✔
87
   const size_t BS = block_size();
4,339✔
88

89
   BOTAN_ARG_CHECK(sz % BS == 0, "CBC input is not full blocks");
4,339✔
90
   const size_t blocks = sz / BS;
4,339✔
91

92
   if(blocks > 0) {
4,339✔
93
      xor_buf(&buf[0], state_ptr(), BS);
4,183✔
94
      cipher().encrypt(&buf[0]);
4,183✔
95

96
      for(size_t i = 1; i != blocks; ++i) {
143,222✔
97
         xor_buf(&buf[BS * i], &buf[BS * (i - 1)], BS);
139,039✔
98
         cipher().encrypt(&buf[BS * i]);
139,039✔
99
      }
100

101
      state().assign(&buf[BS * (blocks - 1)], &buf[BS * blocks]);
4,183✔
102
   }
103

104
   return sz;
4,339✔
105
}
106

107
void CBC_Encryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
2,400✔
108
   BOTAN_STATE_CHECK(state().empty() == false);
2,400✔
109
   BOTAN_ARG_CHECK(buffer.size() >= offset, "Offset is out of range");
1,557✔
110

111
   const size_t BS = block_size();
1,557✔
112

113
   const size_t bytes_in_final_block = (buffer.size() - offset) % BS;
1,557✔
114

115
   padding().add_padding(buffer, bytes_in_final_block, BS);
1,557✔
116

117
   BOTAN_ASSERT_EQUAL(buffer.size() % BS, offset % BS, "Padded to block boundary");
1,557✔
118

119
   update(buffer, offset);
1,557✔
120
}
1,557✔
121

122
bool CTS_Encryption::valid_nonce_length(size_t n) const { return (n == block_size()); }
437✔
123

124
size_t CTS_Encryption::minimum_final_size() const { return block_size() + 1; }
48✔
125

126
size_t CTS_Encryption::output_length(size_t input_length) const {
48✔
127
   return input_length;  // no ciphertext expansion in CTS
48✔
128
}
129

130
void CTS_Encryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
341✔
131
   BOTAN_STATE_CHECK(state().empty() == false);
341✔
132
   BOTAN_ARG_CHECK(buffer.size() >= offset, "Offset is out of range");
197✔
133
   uint8_t* buf = buffer.data() + offset;
197✔
134
   const size_t sz = buffer.size() - offset;
197✔
135

136
   const size_t BS = block_size();
197✔
137

138
   if(sz < BS + 1) {
197✔
139
      throw Encoding_Error(name() + ": insufficient data to encrypt");
×
140
   }
141

142
   if(sz % BS == 0) {
197✔
143
      update(buffer, offset);
32✔
144

145
      // swap last two blocks
146
      for(size_t i = 0; i != BS; ++i) {
376✔
147
         std::swap(buffer[buffer.size() - BS + i], buffer[buffer.size() - 2 * BS + i]);
344✔
148
      }
149
   } else {
150
      const size_t full_blocks = ((sz / BS) - 1) * BS;
165✔
151
      const size_t final_bytes = sz - full_blocks;
165✔
152
      BOTAN_ASSERT(final_bytes > BS && final_bytes < 2 * BS, "Left over size in expected range");
165✔
153

154
      secure_vector<uint8_t> last(buf + full_blocks, buf + full_blocks + final_bytes);
165✔
155
      buffer.resize(full_blocks + offset);
165✔
156
      update(buffer, offset);
165✔
157

158
      xor_buf(last.data(), state_ptr(), BS);
165✔
159
      cipher().encrypt(last.data());
165✔
160

161
      for(size_t i = 0; i != final_bytes - BS; ++i) {
860✔
162
         last[i] ^= last[i + BS];
695✔
163
         last[i + BS] ^= last[i];
695✔
164
      }
165

166
      cipher().encrypt(last.data());
165✔
167

168
      buffer += last;
165✔
169
   }
165✔
170
}
197✔
171

172
size_t CBC_Decryption::output_length(size_t input_length) const {
331✔
173
   return input_length;  // precise for CTS, worst case otherwise
331✔
174
}
175

176
size_t CBC_Decryption::minimum_final_size() const { return block_size(); }
285✔
177

178
size_t CBC_Decryption::process_msg(uint8_t buf[], size_t sz) {
5,546✔
179
   BOTAN_STATE_CHECK(state().empty() == false);
5,546✔
180

181
   const size_t BS = block_size();
4,559✔
182

183
   BOTAN_ARG_CHECK(sz % BS == 0, "Input is not full blocks");
4,559✔
184
   size_t blocks = sz / BS;
4,559✔
185

186
   while(blocks) {
16,797✔
187
      const size_t to_proc = std::min(BS * blocks, m_tempbuf.size());
12,238✔
188

189
      cipher().decrypt_n(buf, m_tempbuf.data(), to_proc / BS);
12,238✔
190

191
      xor_buf(m_tempbuf.data(), state_ptr(), BS);
12,238✔
192
      xor_buf(&m_tempbuf[BS], buf, to_proc - BS);
12,238✔
193
      copy_mem(state_ptr(), buf + (to_proc - BS), BS);
12,238✔
194

195
      copy_mem(buf, m_tempbuf.data(), to_proc);
12,238✔
196

197
      buf += to_proc;
12,238✔
198
      blocks -= to_proc / BS;
12,238✔
199
   }
200

201
   return sz;
4,559✔
202
}
203

204
void CBC_Decryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
2,348✔
205
   BOTAN_STATE_CHECK(state().empty() == false);
2,348✔
206
   BOTAN_ARG_CHECK(buffer.size() >= offset, "Offset is out of range");
1,505✔
207
   const size_t sz = buffer.size() - offset;
1,505✔
208

209
   const size_t BS = block_size();
1,505✔
210

211
   if(sz == 0 || sz % BS) {
1,505✔
212
      throw Decoding_Error(name() + ": Ciphertext not a multiple of block size");
×
213
   }
214

215
   update(buffer, offset);
1,505✔
216

217
   const size_t pad_bytes = BS - padding().unpad(&buffer[buffer.size() - BS], BS);
1,505✔
218
   buffer.resize(buffer.size() - pad_bytes);  // remove padding
1,505✔
219
   if(pad_bytes == 0 && padding().name() != "NoPadding") {
1,591✔
220
      throw Decoding_Error("Invalid CBC padding");
×
221
   }
222
}
1,505✔
223

224
void CBC_Decryption::reset() {
987✔
225
   CBC_Mode::reset();
987✔
226
   zeroise(m_tempbuf);
987✔
227
}
987✔
228

229
bool CTS_Decryption::valid_nonce_length(size_t n) const { return (n == block_size()); }
437✔
230

231
size_t CTS_Decryption::minimum_final_size() const { return block_size() + 1; }
48✔
232

233
void CTS_Decryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
341✔
234
   BOTAN_STATE_CHECK(state().empty() == false);
341✔
235
   BOTAN_ARG_CHECK(buffer.size() >= offset, "Offset is out of range");
197✔
236
   const size_t sz = buffer.size() - offset;
197✔
237
   uint8_t* buf = buffer.data() + offset;
197✔
238

239
   const size_t BS = block_size();
197✔
240

241
   if(sz < BS + 1) {
197✔
242
      throw Encoding_Error(name() + ": insufficient data to decrypt");
×
243
   }
244

245
   if(sz % BS == 0) {
197✔
246
      // swap last two blocks
247

248
      for(size_t i = 0; i != BS; ++i) {
376✔
249
         std::swap(buffer[buffer.size() - BS + i], buffer[buffer.size() - 2 * BS + i]);
344✔
250
      }
251

252
      update(buffer, offset);
32✔
253
   } else {
254
      const size_t full_blocks = ((sz / BS) - 1) * BS;
165✔
255
      const size_t final_bytes = sz - full_blocks;
165✔
256
      BOTAN_ASSERT(final_bytes > BS && final_bytes < 2 * BS, "Left over size in expected range");
165✔
257

258
      secure_vector<uint8_t> last(buf + full_blocks, buf + full_blocks + final_bytes);
165✔
259
      buffer.resize(full_blocks + offset);
165✔
260
      update(buffer, offset);
165✔
261

262
      cipher().decrypt(last.data());
165✔
263

264
      xor_buf(last.data(), &last[BS], final_bytes - BS);
165✔
265

266
      for(size_t i = 0; i != final_bytes - BS; ++i) {
860✔
267
         std::swap(last[i], last[i + BS]);
695✔
268
      }
269

270
      cipher().decrypt(last.data());
165✔
271
      xor_buf(last.data(), state_ptr(), BS);
165✔
272

273
      buffer += last;
165✔
274
   }
165✔
275
}
197✔
276

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

© 2025 Coveralls, Inc