• 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

93.84
/src/lib/modes/aead/ccm/ccm.cpp
1
/*
2
* CCM Mode Encryption
3
* (C) 2013,2018 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/ccm.h>
10

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

14
namespace Botan {
15

16
// 128-bit cipher is intrinsic to CCM definition
17
static const size_t CCM_BS = 16;
18

19
/*
20
* CCM_Mode Constructor
21
*/
22
CCM_Mode::CCM_Mode(std::unique_ptr<BlockCipher> cipher, size_t tag_size, size_t L) :
236✔
23
      m_tag_size(tag_size), m_L(L), m_cipher(std::move(cipher)) {
236✔
24
   if(m_cipher->block_size() != CCM_BS) {
236✔
25
      throw Invalid_Argument(m_cipher->name() + " cannot be used with CCM mode");
×
26
   }
27

28
   if(L < 2 || L > 8) {
236✔
29
      throw Invalid_Argument(fmt("Invalid CCM L value {}", L));
×
30
   }
31

32
   if(tag_size < 4 || tag_size > 16 || tag_size % 2 != 0) {
236✔
33
      throw Invalid_Argument(fmt("Invalid CCM tag length {}", tag_size));
×
34
   }
35
}
236✔
36

37
void CCM_Mode::clear() {
68✔
38
   m_cipher->clear();
68✔
39
   reset();
136✔
40
}
68✔
41

42
void CCM_Mode::reset() {
802✔
43
   m_nonce.clear();
371✔
44
   m_msg_buf.clear();
802✔
45
   m_ad_buf.clear();
802✔
46
}
303✔
47

48
std::string CCM_Mode::name() const { return fmt("{}/CCM({},{})", m_cipher->name(), tag_size(), L()); }
34✔
49

50
bool CCM_Mode::valid_nonce_length(size_t n) const { return (n == (15 - L())); }
635✔
51

52
size_t CCM_Mode::default_nonce_length() const { return (15 - L()); }
34✔
53

54
size_t CCM_Mode::update_granularity() const { return 1; }
237✔
55

56
size_t CCM_Mode::ideal_granularity() const {
204✔
57
   // Completely arbitrary
58
   return m_cipher->parallel_bytes();
204✔
59
}
60

61
bool CCM_Mode::requires_entire_message() const { return true; }
66✔
62

63
Key_Length_Specification CCM_Mode::key_spec() const { return m_cipher->key_spec(); }
168✔
64

65
bool CCM_Mode::has_keying_material() const { return m_cipher->has_keying_material(); }
238✔
66

67
void CCM_Mode::key_schedule(const uint8_t key[], size_t length) { m_cipher->set_key(key, length); }
168✔
68

69
void CCM_Mode::set_associated_data_n(size_t idx, std::span<const uint8_t> ad) {
665✔
70
   BOTAN_ARG_CHECK(idx == 0, "CCM: cannot handle non-zero index in set_associated_data_n");
665✔
71

72
   m_ad_buf.clear();
665✔
73

74
   if(!ad.empty()) {
665✔
75
      // FIXME: support larger AD using length encoding rules
76
      BOTAN_ARG_CHECK(ad.size() < (0xFFFF - 0xFF), "Supported CCM AD length");
641✔
77

78
      m_ad_buf.push_back(get_byte<0>(static_cast<uint16_t>(ad.size())));
641✔
79
      m_ad_buf.push_back(get_byte<1>(static_cast<uint16_t>(ad.size())));
641✔
80
      m_ad_buf.insert(m_ad_buf.end(), ad.begin(), ad.end());
641✔
81
      while(m_ad_buf.size() % CCM_BS) {
5,973✔
82
         m_ad_buf.push_back(0);  // pad with zeros to full block size
5,332✔
83
      }
84
   }
85
}
665✔
86

87
void CCM_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) {
601✔
88
   if(!valid_nonce_length(nonce_len)) {
601✔
89
      throw Invalid_IV_Length(name(), nonce_len);
×
90
   }
91

92
   m_nonce.assign(nonce, nonce + nonce_len);
601✔
93
   m_msg_buf.clear();
601✔
94
}
601✔
95

96
size_t CCM_Mode::process_msg(uint8_t buf[], size_t sz) {
1,749✔
97
   BOTAN_STATE_CHECK(!m_nonce.empty());
1,749✔
98
   m_msg_buf.insert(m_msg_buf.end(), buf, buf + sz);
1,613✔
99
   return 0;  // no output until finished
1,613✔
100
}
101

102
void CCM_Mode::encode_length(uint64_t len, uint8_t out[]) {
533✔
103
   const size_t len_bytes = L();
533✔
104

105
   BOTAN_ASSERT_NOMSG(len_bytes >= 2 && len_bytes <= 8);
533✔
106

107
   for(size_t i = 0; i != len_bytes; ++i) {
2,135✔
108
      out[len_bytes - 1 - i] = get_byte_var(sizeof(uint64_t) - 1 - i, len);
1,602✔
109
   }
110

111
   if(len_bytes < 8 && (len >> (len_bytes * 8)) > 0) {
533✔
112
      throw Encoding_Error("CCM message length too long to encode in L field");
×
113
   }
114
}
533✔
115

116
void CCM_Mode::inc(secure_vector<uint8_t>& C) {
6,398✔
117
   for(size_t i = 0; i != C.size(); ++i) {
6,398✔
118
      if(++C[C.size() - i - 1]) {
6,398✔
119
         break;
120
      }
121
   }
122
}
×
123

124
secure_vector<uint8_t> CCM_Mode::format_b0(size_t sz) {
669✔
125
   if(m_nonce.size() != 15 - L()) {
669✔
126
      throw Invalid_State("CCM mode must set nonce");
136✔
127
   }
128
   secure_vector<uint8_t> B0(CCM_BS);
533✔
129

130
   const uint8_t b_flags =
533✔
131
      static_cast<uint8_t>((!m_ad_buf.empty() ? 64 : 0) + (((tag_size() / 2) - 1) << 3) + (L() - 1));
553✔
132

133
   B0[0] = b_flags;
533✔
134
   copy_mem(&B0[1], m_nonce.data(), m_nonce.size());
533✔
135
   encode_length(sz, &B0[m_nonce.size() + 1]);
533✔
136

137
   return B0;
533✔
138
}
×
139

140
secure_vector<uint8_t> CCM_Mode::format_c0() {
533✔
141
   if(m_nonce.size() != 15 - L()) {
533✔
142
      throw Invalid_State("CCM mode must set nonce");
×
143
   }
144
   secure_vector<uint8_t> C(CCM_BS);
533✔
145

146
   const uint8_t a_flags = static_cast<uint8_t>(L() - 1);
533✔
147

148
   C[0] = a_flags;
533✔
149
   copy_mem(&C[1], m_nonce.data(), m_nonce.size());
533✔
150

151
   return C;
533✔
152
}
×
153

154
void CCM_Encryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
317✔
155
   BOTAN_ARG_CHECK(buffer.size() >= offset, "Offset is out of range");
317✔
156

157
   buffer.insert(buffer.begin() + offset, msg_buf().begin(), msg_buf().end());
317✔
158

159
   const size_t sz = buffer.size() - offset;
317✔
160
   uint8_t* buf = buffer.data() + offset;
317✔
161

162
   const secure_vector<uint8_t>& ad = ad_buf();
317✔
163
   BOTAN_ARG_CHECK(ad.size() % CCM_BS == 0, "AD is block size multiple");
317✔
164

165
   const BlockCipher& E = cipher();
317✔
166

167
   secure_vector<uint8_t> T(CCM_BS);
317✔
168
   E.encrypt(format_b0(sz), T);
532✔
169

170
   for(size_t i = 0; i != ad.size(); i += CCM_BS) {
558✔
171
      xor_buf(T.data(), &ad[i], CCM_BS);
343✔
172
      E.encrypt(T);
686✔
173
   }
174

175
   secure_vector<uint8_t> C = format_c0();
215✔
176
   secure_vector<uint8_t> S0(CCM_BS);
215✔
177
   E.encrypt(C, S0);
215✔
178
   inc(C);
215✔
179

180
   secure_vector<uint8_t> X(CCM_BS);
215✔
181

182
   const uint8_t* buf_end = &buf[sz];
215✔
183

184
   while(buf != buf_end) {
3,051✔
185
      const size_t to_proc = std::min<size_t>(CCM_BS, buf_end - buf);
2,836✔
186

187
      xor_buf(T.data(), buf, to_proc);
2,836✔
188
      E.encrypt(T);
2,836✔
189

190
      E.encrypt(C, X);
2,836✔
191
      xor_buf(buf, X.data(), to_proc);
2,836✔
192
      inc(C);
2,836✔
193

194
      buf += to_proc;
2,836✔
195
   }
196

197
   T ^= S0;
215✔
198

199
   buffer += std::make_pair(T.data(), tag_size());
215✔
200

201
   reset();
430✔
202
}
860✔
203

204
void CCM_Decryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
420✔
205
   BOTAN_ARG_CHECK(buffer.size() >= offset, "Offset is out of range");
420✔
206

207
   buffer.insert(buffer.begin() + offset, msg_buf().begin(), msg_buf().end());
420✔
208

209
   const size_t sz = buffer.size() - offset;
420✔
210
   uint8_t* buf = buffer.data() + offset;
420✔
211

212
   BOTAN_ARG_CHECK(sz >= tag_size(), "input did not include the tag");
420✔
213

214
   const secure_vector<uint8_t>& ad = ad_buf();
352✔
215
   BOTAN_ARG_CHECK(ad.size() % CCM_BS == 0, "AD is block size multiple");
352✔
216

217
   const BlockCipher& E = cipher();
352✔
218

219
   secure_vector<uint8_t> T(CCM_BS);
352✔
220
   E.encrypt(format_b0(sz - tag_size()), T);
772✔
221

222
   for(size_t i = 0; i != ad.size(); i += CCM_BS) {
868✔
223
      xor_buf(T.data(), &ad[i], CCM_BS);
550✔
224
      E.encrypt(T);
1,100✔
225
   }
226

227
   secure_vector<uint8_t> C = format_c0();
318✔
228

229
   secure_vector<uint8_t> S0(CCM_BS);
420✔
230
   E.encrypt(C, S0);
318✔
231
   inc(C);
318✔
232

233
   secure_vector<uint8_t> X(CCM_BS);
420✔
234

235
   const uint8_t* buf_end = &buf[sz - tag_size()];
318✔
236

237
   while(buf != buf_end) {
3,347✔
238
      const size_t to_proc = std::min<size_t>(CCM_BS, buf_end - buf);
3,029✔
239

240
      E.encrypt(C, X);
3,029✔
241
      xor_buf(buf, X.data(), to_proc);
3,029✔
242
      inc(C);
3,029✔
243

244
      xor_buf(T.data(), buf, to_proc);
3,029✔
245
      E.encrypt(T);
3,029✔
246

247
      buf += to_proc;
3,029✔
248
   }
249

250
   T ^= S0;
318✔
251

252
   if(!constant_time_compare(T.data(), buf_end, tag_size())) {
318✔
253
      throw Invalid_Authentication_Tag("CCM tag check failed");
102✔
254
   }
255

256
   buffer.resize(buffer.size() - tag_size());
216✔
257

258
   reset();
432✔
259
}
1,170✔
260

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