Botan 3.3.0
Crypto and TLS for C&
ccm.cpp
Go to the documentation of this file.
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/ct_utils.h>
12#include <botan/internal/fmt.h>
13#include <botan/internal/loadstor.h>
14
15namespace Botan {
16
17// 128-bit cipher is intrinsic to CCM definition
18static const size_t CCM_BS = 16;
19
20/*
21* CCM_Mode Constructor
22*/
23CCM_Mode::CCM_Mode(std::unique_ptr<BlockCipher> cipher, size_t tag_size, size_t L) :
24 m_tag_size(tag_size), m_L(L), m_cipher(std::move(cipher)) {
25 if(m_cipher->block_size() != CCM_BS) {
26 throw Invalid_Argument(m_cipher->name() + " cannot be used with CCM mode");
27 }
28
29 if(L < 2 || L > 8) {
30 throw Invalid_Argument(fmt("Invalid CCM L value {}", L));
31 }
32
33 if(tag_size < 4 || tag_size > 16 || tag_size % 2 != 0) {
34 throw Invalid_Argument(fmt("Invalid CCM tag length {}", tag_size));
35 }
36}
37
39 m_cipher->clear();
40 reset();
41}
42
44 m_nonce.clear();
45 m_msg_buf.clear();
46 m_ad_buf.clear();
47}
48
49std::string CCM_Mode::name() const {
50 return fmt("{}/CCM({},{})", m_cipher->name(), tag_size(), L());
51}
52
53bool CCM_Mode::valid_nonce_length(size_t n) const {
54 return (n == (15 - L()));
55}
56
58 return (15 - L());
59}
60
62 return 1;
63}
64
66 // Completely arbitrary
67 return m_cipher->parallel_bytes();
68}
69
71 return true;
72}
73
75 return m_cipher->key_spec();
76}
77
79 return m_cipher->has_keying_material();
80}
81
82void CCM_Mode::key_schedule(std::span<const uint8_t> key) {
83 m_cipher->set_key(key);
84}
85
86void CCM_Mode::set_associated_data_n(size_t idx, std::span<const uint8_t> ad) {
87 BOTAN_ARG_CHECK(idx == 0, "CCM: cannot handle non-zero index in set_associated_data_n");
88
89 m_ad_buf.clear();
90
91 if(!ad.empty()) {
92 // FIXME: support larger AD using length encoding rules
93 BOTAN_ARG_CHECK(ad.size() < (0xFFFF - 0xFF), "Supported CCM AD length");
94
95 m_ad_buf.push_back(get_byte<0>(static_cast<uint16_t>(ad.size())));
96 m_ad_buf.push_back(get_byte<1>(static_cast<uint16_t>(ad.size())));
97 m_ad_buf.insert(m_ad_buf.end(), ad.begin(), ad.end());
98 while(m_ad_buf.size() % CCM_BS) {
99 m_ad_buf.push_back(0); // pad with zeros to full block size
100 }
101 }
102}
103
104void CCM_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) {
105 if(!valid_nonce_length(nonce_len)) {
106 throw Invalid_IV_Length(name(), nonce_len);
107 }
108
109 m_nonce.assign(nonce, nonce + nonce_len);
110 m_msg_buf.clear();
111}
112
113size_t CCM_Mode::process_msg(uint8_t buf[], size_t sz) {
114 BOTAN_STATE_CHECK(!m_nonce.empty());
115 m_msg_buf.insert(m_msg_buf.end(), buf, buf + sz);
116 return 0; // no output until finished
117}
118
119void CCM_Mode::encode_length(uint64_t len, uint8_t out[]) {
120 const size_t len_bytes = L();
121
122 BOTAN_ASSERT_NOMSG(len_bytes >= 2 && len_bytes <= 8);
123
124 for(size_t i = 0; i != len_bytes; ++i) {
125 out[len_bytes - 1 - i] = get_byte_var(sizeof(uint64_t) - 1 - i, len);
126 }
127
128 if(len_bytes < 8 && (len >> (len_bytes * 8)) > 0) {
129 throw Encoding_Error("CCM message length too long to encode in L field");
130 }
131}
132
134 for(size_t i = 0; i != C.size(); ++i) {
135 if(++C[C.size() - i - 1]) {
136 break;
137 }
138 }
139}
140
142 if(m_nonce.size() != 15 - L()) {
143 throw Invalid_State("CCM mode must set nonce");
144 }
145 secure_vector<uint8_t> B0(CCM_BS);
146
147 const uint8_t b_flags =
148 static_cast<uint8_t>((!m_ad_buf.empty() ? 64 : 0) + (((tag_size() / 2) - 1) << 3) + (L() - 1));
149
150 B0[0] = b_flags;
151 copy_mem(&B0[1], m_nonce.data(), m_nonce.size());
152 encode_length(sz, &B0[m_nonce.size() + 1]);
153
154 return B0;
155}
156
158 if(m_nonce.size() != 15 - L()) {
159 throw Invalid_State("CCM mode must set nonce");
160 }
161 secure_vector<uint8_t> C(CCM_BS);
162
163 const uint8_t a_flags = static_cast<uint8_t>(L() - 1);
164
165 C[0] = a_flags;
166 copy_mem(&C[1], m_nonce.data(), m_nonce.size());
167
168 return C;
169}
170
171void CCM_Encryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
172 BOTAN_ARG_CHECK(buffer.size() >= offset, "Offset is out of range");
173
174 buffer.insert(buffer.begin() + offset, msg_buf().begin(), msg_buf().end());
175
176 const size_t sz = buffer.size() - offset;
177 uint8_t* buf = buffer.data() + offset;
178
179 const secure_vector<uint8_t>& ad = ad_buf();
180 BOTAN_ARG_CHECK(ad.size() % CCM_BS == 0, "AD is block size multiple");
181
182 const BlockCipher& E = cipher();
183
185 E.encrypt(format_b0(sz), T);
186
187 for(size_t i = 0; i != ad.size(); i += CCM_BS) {
188 xor_buf(T.data(), &ad[i], CCM_BS);
189 E.encrypt(T);
190 }
191
192 secure_vector<uint8_t> C = format_c0();
193 secure_vector<uint8_t> S0(CCM_BS);
194 E.encrypt(C, S0);
195 inc(C);
196
197 secure_vector<uint8_t> X(CCM_BS);
198
199 const uint8_t* buf_end = &buf[sz];
200
201 while(buf != buf_end) {
202 const size_t to_proc = std::min<size_t>(CCM_BS, buf_end - buf);
203
204 xor_buf(T.data(), buf, to_proc);
205 E.encrypt(T);
206
207 E.encrypt(C, X);
208 xor_buf(buf, X.data(), to_proc);
209 inc(C);
210
211 buf += to_proc;
212 }
213
214 T ^= S0;
215
216 buffer += std::make_pair(T.data(), tag_size());
217
218 reset();
219}
220
221void CCM_Decryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
222 BOTAN_ARG_CHECK(buffer.size() >= offset, "Offset is out of range");
223
224 buffer.insert(buffer.begin() + offset, msg_buf().begin(), msg_buf().end());
225
226 const size_t sz = buffer.size() - offset;
227 uint8_t* buf = buffer.data() + offset;
228
229 BOTAN_ARG_CHECK(sz >= tag_size(), "input did not include the tag");
230
231 const secure_vector<uint8_t>& ad = ad_buf();
232 BOTAN_ARG_CHECK(ad.size() % CCM_BS == 0, "AD is block size multiple");
233
234 const BlockCipher& E = cipher();
235
236 secure_vector<uint8_t> T(CCM_BS);
237 E.encrypt(format_b0(sz - tag_size()), T);
238
239 for(size_t i = 0; i != ad.size(); i += CCM_BS) {
240 xor_buf(T.data(), &ad[i], CCM_BS);
241 E.encrypt(T);
242 }
243
244 secure_vector<uint8_t> C = format_c0();
245
246 secure_vector<uint8_t> S0(CCM_BS);
247 E.encrypt(C, S0);
248 inc(C);
249
250 secure_vector<uint8_t> X(CCM_BS);
251
252 const uint8_t* buf_end = &buf[sz - tag_size()];
253
254 while(buf != buf_end) {
255 const size_t to_proc = std::min<size_t>(CCM_BS, buf_end - buf);
256
257 E.encrypt(C, X);
258 xor_buf(buf, X.data(), to_proc);
259 inc(C);
260
261 xor_buf(T.data(), buf, to_proc);
262 E.encrypt(T);
263
264 buf += to_proc;
265 }
266
267 T ^= S0;
268
269 if(!CT::is_equal(T.data(), buf_end, tag_size()).as_bool()) {
270 throw Invalid_Authentication_Tag("CCM tag check failed");
271 }
272
273 buffer.resize(buffer.size() - tag_size());
274
275 reset();
276}
277
278} // namespace Botan
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:59
#define BOTAN_STATE_CHECK(expr)
Definition assert.h:41
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:29
void encrypt(const uint8_t in[], uint8_t out[]) const
size_t ideal_granularity() const final
Definition ccm.cpp:65
bool requires_entire_message() const final
Definition ccm.cpp:70
void reset() final
Definition ccm.cpp:43
static void inc(secure_vector< uint8_t > &C)
Definition ccm.cpp:133
size_t update_granularity() const final
Definition ccm.cpp:61
void clear() final
Definition ccm.cpp:38
secure_vector< uint8_t > & msg_buf()
Definition ccm.h:62
const BlockCipher & cipher() const
Definition ccm.h:54
void encode_length(uint64_t len, uint8_t out[])
Definition ccm.cpp:119
size_t L() const
Definition ccm.h:52
size_t tag_size() const final
Definition ccm.h:45
Key_Length_Specification key_spec() const final
Definition ccm.cpp:74
bool valid_nonce_length(size_t) const final
Definition ccm.cpp:53
void set_associated_data_n(size_t idx, std::span< const uint8_t > ad) final
Definition ccm.cpp:86
secure_vector< uint8_t > format_c0()
Definition ccm.cpp:157
bool has_keying_material() const final
Definition ccm.cpp:78
std::string name() const final
Definition ccm.cpp:49
const secure_vector< uint8_t > & ad_buf() const
Definition ccm.h:60
CCM_Mode(std::unique_ptr< BlockCipher > cipher, size_t tag_size, size_t L)
Definition ccm.cpp:23
secure_vector< uint8_t > format_b0(size_t msg_size)
Definition ccm.cpp:141
size_t default_nonce_length() const final
Definition ccm.cpp:57
FE_25519 X
Definition ge.cpp:25
FE_25519 T
Definition ge.cpp:34
CT::Mask< T > is_equal(const T x[], const T y[], size_t len)
Definition ct_utils.h:339
std::string fmt(std::string_view format, const T &... args)
Definition fmt.h:53
constexpr void xor_buf(ranges::contiguous_output_range< uint8_t > auto &&out, ranges::contiguous_range< uint8_t > auto &&in)
Definition mem_ops.h:340
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:61
constexpr uint8_t get_byte_var(size_t byte_num, T input)
Definition loadstor.h:27
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:146