Botan  2.4.0
Crypto and TLS for C++11
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/loadstor.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 
36  {
37  m_cipher->clear();
38  reset();
39  }
40 
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 
59  {
60  return (15-L());
61  }
62 
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 
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 
129  {
130  for(size_t i = 0; i != C.size(); ++i)
131  if(++C[C.size()-i-1])
132  break;
133  }
134 
136  {
137  secure_vector<uint8_t> B0(CCM_BS);
138 
139  const uint8_t b_flags =
140  static_cast<uint8_t>((m_ad_buf.size() ? 64 : 0) + (((tag_size()/2)-1) << 3) + (L()-1));
141 
142  B0[0] = b_flags;
143  copy_mem(&B0[1], m_nonce.data(), m_nonce.size());
144  encode_length(sz, &B0[m_nonce.size()+1]);
145 
146  return B0;
147  }
148 
150  {
151  secure_vector<uint8_t> C(CCM_BS);
152 
153  const uint8_t a_flags = static_cast<uint8_t>(L() - 1);
154 
155  C[0] = a_flags;
156  copy_mem(&C[1], m_nonce.data(), m_nonce.size());
157 
158  return C;
159  }
160 
161 void CCM_Encryption::finish(secure_vector<uint8_t>& buffer, size_t offset)
162  {
163  BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
164 
165  buffer.insert(buffer.begin() + offset, msg_buf().begin(), msg_buf().end());
166 
167  const size_t sz = buffer.size() - offset;
168  uint8_t* buf = buffer.data() + offset;
169 
170  const secure_vector<uint8_t>& ad = ad_buf();
171  BOTAN_ASSERT(ad.size() % CCM_BS == 0, "AD is block size multiple");
172 
173  const BlockCipher& E = cipher();
174 
175  secure_vector<uint8_t> T(CCM_BS);
176  E.encrypt(format_b0(sz), T);
177 
178  for(size_t i = 0; i != ad.size(); i += CCM_BS)
179  {
180  xor_buf(T.data(), &ad[i], CCM_BS);
181  E.encrypt(T);
182  }
183 
185  secure_vector<uint8_t> S0(CCM_BS);
186  E.encrypt(C, S0);
187  inc(C);
188 
189  secure_vector<uint8_t> X(CCM_BS);
190 
191  const uint8_t* buf_end = &buf[sz];
192 
193  while(buf != buf_end)
194  {
195  const size_t to_proc = std::min<size_t>(CCM_BS, buf_end - buf);
196 
197  xor_buf(T.data(), buf, to_proc);
198  E.encrypt(T);
199 
200  E.encrypt(C, X);
201  xor_buf(buf, X.data(), to_proc);
202  inc(C);
203 
204  buf += to_proc;
205  }
206 
207  T ^= S0;
208 
209  buffer += std::make_pair(T.data(), tag_size());
210  }
211 
212 void CCM_Decryption::finish(secure_vector<uint8_t>& buffer, size_t offset)
213  {
214  BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
215 
216  buffer.insert(buffer.begin() + offset, msg_buf().begin(), msg_buf().end());
217 
218  const size_t sz = buffer.size() - offset;
219  uint8_t* buf = buffer.data() + offset;
220 
221  BOTAN_ASSERT(sz >= tag_size(), "We have the tag");
222 
223  const secure_vector<uint8_t>& ad = ad_buf();
224  BOTAN_ASSERT(ad.size() % CCM_BS == 0, "AD is block size multiple");
225 
226  const BlockCipher& E = cipher();
227 
228  secure_vector<uint8_t> T(CCM_BS);
229  E.encrypt(format_b0(sz - tag_size()), T);
230 
231  for(size_t i = 0; i != ad.size(); i += CCM_BS)
232  {
233  xor_buf(T.data(), &ad[i], CCM_BS);
234  E.encrypt(T);
235  }
236 
238 
239  secure_vector<uint8_t> S0(CCM_BS);
240  E.encrypt(C, S0);
241  inc(C);
242 
243  secure_vector<uint8_t> X(CCM_BS);
244 
245  const uint8_t* buf_end = &buf[sz - tag_size()];
246 
247  while(buf != buf_end)
248  {
249  const size_t to_proc = std::min<size_t>(CCM_BS, buf_end - buf);
250 
251  E.encrypt(C, X);
252  xor_buf(buf, X.data(), to_proc);
253  inc(C);
254 
255  xor_buf(T.data(), buf, to_proc);
256  E.encrypt(T);
257 
258  buf += to_proc;
259  }
260 
261  T ^= S0;
262 
263  if(!constant_time_compare(T.data(), buf_end, tag_size()))
264  throw Integrity_Failure("CCM tag check failed");
265 
266  buffer.resize(buffer.size() - tag_size());
267  }
268 
269 }
fe X
Definition: ge.cpp:27
size_t default_nonce_length() const override
Definition: ccm.cpp:58
size_t update_granularity() const override
Definition: ccm.cpp:63
secure_vector< uint8_t > format_c0()
Definition: ccm.cpp:149
size_t L() const
Definition: ccm.h:47
const BlockCipher & cipher() const
Definition: ccm.h:49
void finish(secure_vector< uint8_t > &final_block, size_t offset=0) override
Definition: ccm.cpp:161
bool constant_time_compare(const uint8_t x[], const uint8_t y[], size_t len)
Definition: mem_ops.cpp:44
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:108
#define BOTAN_ASSERT(expr, assertion_made)
Definition: assert.h:29
void set_associated_data(const uint8_t ad[], size_t ad_len) override
Definition: ccm.cpp:84
bool valid_nonce_length(size_t) const override
Definition: ccm.cpp:53
void xor_buf(uint8_t out[], const uint8_t in[], size_t length)
Definition: mem_ops.h:163
void encode_length(size_t len, uint8_t out[])
Definition: ccm.cpp:116
size_t process(uint8_t buf[], size_t sz) override
Definition: ccm.cpp:110
void clear() override
Definition: ccm.cpp:35
std::string name() const override
Definition: ccm.cpp:48
void inc(secure_vector< uint8_t > &C)
Definition: ccm.cpp:128
void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:97
Definition: alg_id.cpp:13
void reset() override
Definition: ccm.cpp:41
void finish(secure_vector< uint8_t > &final_block, size_t offset=0) override
Definition: ccm.cpp:212
CCM_Mode(BlockCipher *cipher, size_t tag_size, size_t L)
Definition: ccm.cpp:20
fe T
Definition: ge.cpp:37
uint8_t get_byte(size_t byte_num, T input)
Definition: loadstor.h:39
std::vector< T, secure_allocator< T > > secure_vector
Definition: secmem.h:88
secure_vector< uint8_t > format_b0(size_t msg_size)
Definition: ccm.cpp:135
Key_Length_Specification key_spec() const override
Definition: ccm.cpp:74
const secure_vector< uint8_t > & ad_buf() const
Definition: ccm.h:55
secure_vector< uint8_t > & msg_buf()
Definition: ccm.h:57
size_t tag_size() const override
Definition: ccm.h:42