Botan 2.1.0 Crypto and TLS for C++11

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

ccm.cpp
Go to the documentation of this file.
1 /*
2 * CCM Mode Encryption
3 * (C) 2013 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/ccm.h>
10 #include <botan/parsing.h>
11
12 namespace Botan {
13
14 // 128-bit cipher is intrinsic to CCM definition
15 static const size_t CCM_BS = 16;
16
17 /*
18 * CCM_Mode Constructor
19 */
20 CCM_Mode::CCM_Mode(BlockCipher* cipher, size_t tag_size, size_t L) :
21 m_tag_size(tag_size),
22 m_L(L),
23 m_cipher(cipher)
24 {
25 if(m_cipher->block_size() != CCM_BS)
26 throw Invalid_Argument(m_cipher->name() + " cannot be used with CCM mode");
27
28 if(L < 2 || L > 8)
29 throw Invalid_Argument("Invalid CCM L value " + std::to_string(L));
30
31 if(tag_size < 4 || tag_size > 16 || tag_size % 2 != 0)
32 throw Invalid_Argument("invalid CCM tag length " + std::to_string(tag_size));
33 }
34
35 void CCM_Mode::clear()
36 {
37 m_cipher->clear();
38 reset();
39 }
40
41 void CCM_Mode::reset()
42 {
43 m_nonce.clear();
44 m_msg_buf.clear();
45 m_ad_buf.clear();
46 }
47
48 std::string CCM_Mode::name() const
49 {
50 return (m_cipher->name() + "/CCM(" + std::to_string(tag_size()) + "," + std::to_string(L())) + ")";
51 }
52
53 bool CCM_Mode::valid_nonce_length(size_t n) const
54 {
55 return (n == (15-L()));
56 }
57
58 size_t CCM_Mode::default_nonce_length() const
59 {
60 return (15-L());
61 }
62
63 size_t CCM_Mode::update_granularity() const
64 {
65 /*
66 This value does not particularly matter as regardless CCM_Mode::update
67 buffers all input, so in theory this could be 1. However as for instance
68 Transform_Filter creates update_granularity() uint8_t buffers, use a
69 somewhat large size to avoid bouncing on a tiny buffer.
70 */
71 return m_cipher->parallel_bytes();
72 }
73
74 Key_Length_Specification CCM_Mode::key_spec() const
75 {
76 return m_cipher->key_spec();
77 }
78
79 void CCM_Mode::key_schedule(const uint8_t key[], size_t length)
80 {
81 m_cipher->set_key(key, length);
82 }
83
84 void CCM_Mode::set_associated_data(const uint8_t ad[], size_t length)
85 {
86 m_ad_buf.clear();
87
88 if(length)
89 {
90 // FIXME: support larger AD using length encoding rules
91 BOTAN_ASSERT(length < (0xFFFF - 0xFF), "Supported CCM AD length");
92
93 m_ad_buf.push_back(get_byte(0, static_cast<uint16_t>(length)));
94 m_ad_buf.push_back(get_byte(1, static_cast<uint16_t>(length)));
95 m_ad_buf += std::make_pair(ad, length);
96 while(m_ad_buf.size() % CCM_BS)
97 m_ad_buf.push_back(0); // pad with zeros to full block size
98 }
99 }
100
101 void CCM_Mode::start_msg(const uint8_t nonce[], size_t nonce_len)
102 {
103 if(!valid_nonce_length(nonce_len))
104 throw Invalid_IV_Length(name(), nonce_len);
105
106 m_nonce.assign(nonce, nonce + nonce_len);
107 m_msg_buf.clear();
108 }
109
110 size_t CCM_Mode::process(uint8_t buf[], size_t sz)
111 {
112 m_msg_buf.insert(m_msg_buf.end(), buf, buf + sz);
113 return 0; // no output until finished
114 }
115
116 void CCM_Mode::encode_length(size_t len, uint8_t out[])
117 {
118 const size_t len_bytes = L();
119
120 BOTAN_ASSERT(len_bytes < sizeof(size_t), "Length field fits");
121
122 for(size_t i = 0; i != len_bytes; ++i)
123 out[len_bytes-1-i] = get_byte(sizeof(size_t)-1-i, len);
124
125 BOTAN_ASSERT((len >> (len_bytes*8)) == 0, "Message length fits in field");
126 }
127
128 void CCM_Mode::inc(secure_vector<uint8_t>& C)
129 {
130 for(size_t i = 0; i != C.size(); ++i)
131 if(++C[C.size()-i-1])
132 break;
133 }
134
135 secure_vector<uint8_t> CCM_Mode::format_b0(size_t sz)
136 {
137 secure_vector<uint8_t> B0(CCM_BS);
138
139 const uint8_t b_flags = (m_ad_buf.size() ? 64 : 0) + (((tag_size()/2)-1) << 3) + (L()-1);
140
141 B0[0] = b_flags;
142 copy_mem(&B0[1], m_nonce.data(), m_nonce.size());
143 encode_length(sz, &B0[m_nonce.size()+1]);
144
145 return B0;
146 }
147
148 secure_vector<uint8_t> CCM_Mode::format_c0()
149 {
150 secure_vector<uint8_t> C(CCM_BS);
151
152 const uint8_t a_flags = L()-1;
153
154 C[0] = a_flags;
155 copy_mem(&C[1], m_nonce.data(), m_nonce.size());
156
157 return C;
158 }
159
160 void CCM_Encryption::finish(secure_vector<uint8_t>& buffer, size_t offset)
161 {
162 BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
163
164 buffer.insert(buffer.begin() + offset, msg_buf().begin(), msg_buf().end());
165
166 const size_t sz = buffer.size() - offset;
167 uint8_t* buf = buffer.data() + offset;
168
169 const secure_vector<uint8_t>& ad = ad_buf();
170 BOTAN_ASSERT(ad.size() % CCM_BS == 0, "AD is block size multiple");
171
172 const BlockCipher& E = cipher();
173
174 secure_vector<uint8_t> T(CCM_BS);
175 E.encrypt(format_b0(sz), T);
176
177 for(size_t i = 0; i != ad.size(); i += CCM_BS)
178 {
179 xor_buf(T.data(), &ad[i], CCM_BS);
180 E.encrypt(T);
181 }
182
183 secure_vector<uint8_t> C = format_c0();
184 secure_vector<uint8_t> S0(CCM_BS);
185 E.encrypt(C, S0);
186 inc(C);
187
188 secure_vector<uint8_t> X(CCM_BS);
189
190 const uint8_t* buf_end = &buf[sz];
191
192 while(buf != buf_end)
193 {
194 const size_t to_proc = std::min<size_t>(CCM_BS, buf_end - buf);
195
196 xor_buf(T.data(), buf, to_proc);
197 E.encrypt(T);
198
199 E.encrypt(C, X);
200 xor_buf(buf, X.data(), to_proc);
201 inc(C);
202
203 buf += to_proc;
204 }
205
206 T ^= S0;
207
208 buffer += std::make_pair(T.data(), tag_size());
209 }
210
211 void CCM_Decryption::finish(secure_vector<uint8_t>& buffer, size_t offset)
212 {
213 BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
214
215 buffer.insert(buffer.begin() + offset, msg_buf().begin(), msg_buf().end());
216
217 const size_t sz = buffer.size() - offset;
218 uint8_t* buf = buffer.data() + offset;
219
220 BOTAN_ASSERT(sz >= tag_size(), "We have the tag");
221
222 const secure_vector<uint8_t>& ad = ad_buf();
223 BOTAN_ASSERT(ad.size() % CCM_BS == 0, "AD is block size multiple");
224
225 const BlockCipher& E = cipher();
226
227 secure_vector<uint8_t> T(CCM_BS);
228 E.encrypt(format_b0(sz - tag_size()), T);
229
230 for(size_t i = 0; i != ad.size(); i += CCM_BS)
231 {
232 xor_buf(T.data(), &ad[i], CCM_BS);
233 E.encrypt(T);
234 }
235
236 secure_vector<uint8_t> C = format_c0();
237
238 secure_vector<uint8_t> S0(CCM_BS);
239 E.encrypt(C, S0);
240 inc(C);
241
242 secure_vector<uint8_t> X(CCM_BS);
243
244 const uint8_t* buf_end = &buf[sz - tag_size()];
245
246 while(buf != buf_end)
247 {
248 const size_t to_proc = std::min<size_t>(CCM_BS, buf_end - buf);
249
250 E.encrypt(C, X);
251 xor_buf(buf, X.data(), to_proc);
252 inc(C);
253
254 xor_buf(T.data(), buf, to_proc);
255 E.encrypt(T);
256
257 buf += to_proc;
258 }
259
260 T ^= S0;
261
262 if(!same_mem(T.data(), buf_end, tag_size()))
263 throw Integrity_Failure("CCM tag check failed");
264
265 buffer.resize(buffer.size() - tag_size());
266 }
267
268 }
Botan::xor_buf
void xor_buf(T out[], const T in[], size_t length)
Definition: mem_ops.h:115
Botan::CCM_Mode::default_nonce_length
size_t default_nonce_length() const override
Definition: ccm.cpp:58
Botan::Invalid_Argument
Definition: exceptn.h:34
Botan::CCM_Mode::update_granularity
size_t update_granularity() const override
Definition: ccm.cpp:63
Botan::CCM_Mode::format_c0
secure_vector< uint8_t > format_c0()
Definition: ccm.cpp:148
Botan::same_mem
bool same_mem(const T *p1, const T *p2, size_t n)
Definition: mem_ops.h:98
Botan::CCM_Mode::L
size_t L() const
Definition: ccm.h:49
Botan::CCM_Encryption::finish
void finish(secure_vector< uint8_t > &final_block, size_t offset=0) override
Definition: ccm.cpp:160
Botan::Integrity_Failure
Definition: exceptn.h:198
Botan::Key_Length_Specification
Definition: key_spec.h:18
Botan::ASN1::to_string
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:47
Botan::Invalid_IV_Length
Definition: exceptn.h:109
BOTAN_ASSERT
#define BOTAN_ASSERT(expr, assertion_made)
Definition: assert.h:27
Botan::CCM_Mode::set_associated_data
void set_associated_data(const uint8_t ad[], size_t ad_len) override
Definition: ccm.cpp:84
Botan::CCM_Mode::valid_nonce_length
bool valid_nonce_length(size_t) const override
Definition: ccm.cpp:53
Botan::secure_vector
std::vector< T, secure_allocator< T >> secure_vector
Definition: secmem.h:121
Botan::CCM_Mode::cipher
const BlockCipher & cipher() const
Definition: ccm.h:51
Botan::CCM_Mode::encode_length
void encode_length(size_t len, uint8_t out[])
Definition: ccm.cpp:116
Botan::CCM_Mode::process
size_t process(uint8_t buf[], size_t sz) override
Definition: ccm.cpp:110
Botan::CCM_Mode::clear
void clear() override
Definition: ccm.cpp:35
Botan::CCM_Mode::name
std::string name() const override
Definition: ccm.cpp:48
Botan::CCM_Mode::inc
void inc(secure_vector< uint8_t > &C)
Definition: ccm.cpp:128
Botan::copy_mem
void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:68
Botan
Definition: alg_id.cpp:13
Botan::CCM_Mode::reset
void reset() override
Definition: ccm.cpp:41
Botan::CCM_Decryption::finish
void finish(secure_vector< uint8_t > &final_block, size_t offset=0) override
Definition: ccm.cpp:211
Botan::CCM_Mode::CCM_Mode
CCM_Mode(BlockCipher *cipher, size_t tag_size, size_t L)
Definition: ccm.cpp:20
Botan::get_byte
uint8_t get_byte(size_t byte_num, T input)
Definition: loadstor.h:47
Botan::CCM_Mode::ad_buf
const secure_vector< uint8_t > & ad_buf() const
Definition: ccm.h:57
Botan::CCM_Mode::format_b0
secure_vector< uint8_t > format_b0(size_t msg_size)
Definition: ccm.cpp:135
Botan::CCM_Mode::key_spec
Key_Length_Specification key_spec() const override
Definition: ccm.cpp:74
Botan::CCM_Mode::msg_buf
secure_vector< uint8_t > & msg_buf()
Definition: ccm.h:59
Botan::CCM_Mode::tag_size
size_t tag_size() const override
Definition: ccm.h:44
Botan::BlockCipher
Definition: block_cipher.h:19