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

randombit / botan / 5111374265

29 May 2023 11:19AM UTC coverage: 92.227% (+0.5%) from 91.723%
5111374265

push

github

randombit
Next release will be 3.1.0. Update release notes

75588 of 81959 relevant lines covered (92.23%)

11886470.91 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
   if(L < 2 || L > 8)
236✔
28
      throw Invalid_Argument(fmt("Invalid CCM L value {}", L));
×
29

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

34
void CCM_Mode::clear() {
68✔
35
   m_cipher->clear();
68✔
36
   reset();
136✔
37
}
68✔
38

39
void CCM_Mode::reset() {
810✔
40
   m_nonce.clear();
371✔
41
   m_msg_buf.clear();
810✔
42
   m_ad_buf.clear();
810✔
43
}
303✔
44

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

47
bool CCM_Mode::valid_nonce_length(size_t n) const { return (n == (15 - L())); }
643✔
48

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

51
size_t CCM_Mode::update_granularity() const { return 1; }
237✔
52

53
size_t CCM_Mode::ideal_granularity() const {
204✔
54
   // Completely arbitrary
55
   return m_cipher->parallel_bytes();
204✔
56
}
57

58
bool CCM_Mode::requires_entire_message() const { return true; }
66✔
59

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

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

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

66
void CCM_Mode::set_associated_data_n(size_t idx, std::span<const uint8_t> ad) {
673✔
67
   BOTAN_ARG_CHECK(idx == 0, "CCM: cannot handle non-zero index in set_associated_data_n");
673✔
68

69
   m_ad_buf.clear();
673✔
70

71
   if(!ad.empty()) {
673✔
72
      // FIXME: support larger AD using length encoding rules
73
      BOTAN_ARG_CHECK(ad.size() < (0xFFFF - 0xFF), "Supported CCM AD length");
649✔
74

75
      m_ad_buf.push_back(get_byte<0>(static_cast<uint16_t>(ad.size())));
649✔
76
      m_ad_buf.push_back(get_byte<1>(static_cast<uint16_t>(ad.size())));
649✔
77
      m_ad_buf.insert(m_ad_buf.end(), ad.begin(), ad.end());
649✔
78
      while(m_ad_buf.size() % CCM_BS)
5,980✔
79
         m_ad_buf.push_back(0);  // pad with zeros to full block size
5,331✔
80
   }
81
}
673✔
82

83
void CCM_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) {
609✔
84
   if(!valid_nonce_length(nonce_len))
609✔
85
      throw Invalid_IV_Length(name(), nonce_len);
×
86

87
   m_nonce.assign(nonce, nonce + nonce_len);
609✔
88
   m_msg_buf.clear();
609✔
89
}
609✔
90

91
size_t CCM_Mode::process_msg(uint8_t buf[], size_t sz) {
1,749✔
92
   BOTAN_STATE_CHECK(!m_nonce.empty());
1,749✔
93
   m_msg_buf.insert(m_msg_buf.end(), buf, buf + sz);
1,613✔
94
   return 0;  // no output until finished
1,613✔
95
}
96

97
void CCM_Mode::encode_length(uint64_t len, uint8_t out[]) {
541✔
98
   const size_t len_bytes = L();
541✔
99

100
   BOTAN_ASSERT_NOMSG(len_bytes >= 2 && len_bytes <= 8);
541✔
101

102
   for(size_t i = 0; i != len_bytes; ++i)
2,167✔
103
      out[len_bytes - 1 - i] = get_byte_var(sizeof(uint64_t) - 1 - i, len);
1,626✔
104

105
   if(len_bytes < 8 && (len >> (len_bytes * 8)) > 0)
541✔
106
      throw Encoding_Error("CCM message length too long to encode in L field");
×
107
}
541✔
108

109
void CCM_Mode::inc(secure_vector<uint8_t>& C) {
6,456✔
110
   for(size_t i = 0; i != C.size(); ++i)
6,456✔
111
      if(++C[C.size() - i - 1])
6,456✔
112
         break;
113
}
×
114

115
secure_vector<uint8_t> CCM_Mode::format_b0(size_t sz) {
677✔
116
   if(m_nonce.size() != 15 - L())
677✔
117
      throw Invalid_State("CCM mode must set nonce");
136✔
118
   secure_vector<uint8_t> B0(CCM_BS);
541✔
119

120
   const uint8_t b_flags =
541✔
121
      static_cast<uint8_t>((!m_ad_buf.empty() ? 64 : 0) + (((tag_size() / 2) - 1) << 3) + (L() - 1));
561✔
122

123
   B0[0] = b_flags;
541✔
124
   copy_mem(&B0[1], m_nonce.data(), m_nonce.size());
541✔
125
   encode_length(sz, &B0[m_nonce.size() + 1]);
541✔
126

127
   return B0;
541✔
128
}
×
129

130
secure_vector<uint8_t> CCM_Mode::format_c0() {
541✔
131
   if(m_nonce.size() != 15 - L())
541✔
132
      throw Invalid_State("CCM mode must set nonce");
×
133
   secure_vector<uint8_t> C(CCM_BS);
541✔
134

135
   const uint8_t a_flags = static_cast<uint8_t>(L() - 1);
541✔
136

137
   C[0] = a_flags;
541✔
138
   copy_mem(&C[1], m_nonce.data(), m_nonce.size());
541✔
139

140
   return C;
541✔
141
}
×
142

143
void CCM_Encryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
321✔
144
   BOTAN_ARG_CHECK(buffer.size() >= offset, "Offset is out of range");
321✔
145

146
   buffer.insert(buffer.begin() + offset, msg_buf().begin(), msg_buf().end());
321✔
147

148
   const size_t sz = buffer.size() - offset;
321✔
149
   uint8_t* buf = buffer.data() + offset;
321✔
150

151
   const secure_vector<uint8_t>& ad = ad_buf();
321✔
152
   BOTAN_ARG_CHECK(ad.size() % CCM_BS == 0, "AD is block size multiple");
321✔
153

154
   const BlockCipher& E = cipher();
321✔
155

156
   secure_vector<uint8_t> T(CCM_BS);
321✔
157
   E.encrypt(format_b0(sz), T);
540✔
158

159
   for(size_t i = 0; i != ad.size(); i += CCM_BS) {
566✔
160
      xor_buf(T.data(), &ad[i], CCM_BS);
347✔
161
      E.encrypt(T);
694✔
162
   }
163

164
   secure_vector<uint8_t> C = format_c0();
219✔
165
   secure_vector<uint8_t> S0(CCM_BS);
219✔
166
   E.encrypt(C, S0);
219✔
167
   inc(C);
219✔
168

169
   secure_vector<uint8_t> X(CCM_BS);
219✔
170

171
   const uint8_t* buf_end = &buf[sz];
219✔
172

173
   while(buf != buf_end) {
3,080✔
174
      const size_t to_proc = std::min<size_t>(CCM_BS, buf_end - buf);
2,861✔
175

176
      xor_buf(T.data(), buf, to_proc);
2,861✔
177
      E.encrypt(T);
2,861✔
178

179
      E.encrypt(C, X);
2,861✔
180
      xor_buf(buf, X.data(), to_proc);
2,861✔
181
      inc(C);
2,861✔
182

183
      buf += to_proc;
2,861✔
184
   }
185

186
   T ^= S0;
219✔
187

188
   buffer += std::make_pair(T.data(), tag_size());
219✔
189

190
   reset();
438✔
191
}
876✔
192

193
void CCM_Decryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
424✔
194
   BOTAN_ARG_CHECK(buffer.size() >= offset, "Offset is out of range");
424✔
195

196
   buffer.insert(buffer.begin() + offset, msg_buf().begin(), msg_buf().end());
424✔
197

198
   const size_t sz = buffer.size() - offset;
424✔
199
   uint8_t* buf = buffer.data() + offset;
424✔
200

201
   BOTAN_ARG_CHECK(sz >= tag_size(), "input did not include the tag");
424✔
202

203
   const secure_vector<uint8_t>& ad = ad_buf();
356✔
204
   BOTAN_ARG_CHECK(ad.size() % CCM_BS == 0, "AD is block size multiple");
356✔
205

206
   const BlockCipher& E = cipher();
356✔
207

208
   secure_vector<uint8_t> T(CCM_BS);
356✔
209
   E.encrypt(format_b0(sz - tag_size()), T);
780✔
210

211
   for(size_t i = 0; i != ad.size(); i += CCM_BS) {
876✔
212
      xor_buf(T.data(), &ad[i], CCM_BS);
554✔
213
      E.encrypt(T);
1,108✔
214
   }
215

216
   secure_vector<uint8_t> C = format_c0();
322✔
217

218
   secure_vector<uint8_t> S0(CCM_BS);
424✔
219
   E.encrypt(C, S0);
322✔
220
   inc(C);
322✔
221

222
   secure_vector<uint8_t> X(CCM_BS);
424✔
223

224
   const uint8_t* buf_end = &buf[sz - tag_size()];
322✔
225

226
   while(buf != buf_end) {
3,376✔
227
      const size_t to_proc = std::min<size_t>(CCM_BS, buf_end - buf);
3,054✔
228

229
      E.encrypt(C, X);
3,054✔
230
      xor_buf(buf, X.data(), to_proc);
3,054✔
231
      inc(C);
3,054✔
232

233
      xor_buf(T.data(), buf, to_proc);
3,054✔
234
      E.encrypt(T);
3,054✔
235

236
      buf += to_proc;
3,054✔
237
   }
238

239
   T ^= S0;
322✔
240

241
   if(!constant_time_compare(T.data(), buf_end, tag_size()))
322✔
242
      throw Invalid_Authentication_Tag("CCM tag check failed");
102✔
243

244
   buffer.resize(buffer.size() - tag_size());
220✔
245

246
   reset();
440✔
247
}
1,186✔
248

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