Botan  2.13.0
Crypto and TLS for C++11
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/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_ARG_CHECK(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  BOTAN_STATE_CHECK(m_nonce.size() > 0);
113  m_msg_buf.insert(m_msg_buf.end(), buf, buf + sz);
114  return 0; // no output until finished
115  }
116 
117 void CCM_Mode::encode_length(uint64_t len, uint8_t out[])
118  {
119  const size_t len_bytes = L();
120 
121  BOTAN_ASSERT_NOMSG(len_bytes >= 2 && len_bytes <= 8);
122 
123  for(size_t i = 0; i != len_bytes; ++i)
124  out[len_bytes-1-i] = get_byte(sizeof(uint64_t)-1-i, len);
125 
126  if(len_bytes < 8 && (len >> (len_bytes*8)) > 0)
127  throw Encoding_Error("CCM message length too long to encode in L field");
128  }
129 
131  {
132  for(size_t i = 0; i != C.size(); ++i)
133  if(++C[C.size()-i-1])
134  break;
135  }
136 
138  {
139  if(m_nonce.size() != 15-L())
140  throw Invalid_State("CCM mode must set nonce");
141  secure_vector<uint8_t> B0(CCM_BS);
142 
143  const uint8_t b_flags =
144  static_cast<uint8_t>((m_ad_buf.size() ? 64 : 0) + (((tag_size()/2)-1) << 3) + (L()-1));
145 
146  B0[0] = b_flags;
147  copy_mem(&B0[1], m_nonce.data(), m_nonce.size());
148  encode_length(sz, &B0[m_nonce.size()+1]);
149 
150  return B0;
151  }
152 
154  {
155  if(m_nonce.size() != 15-L())
156  throw Invalid_State("CCM mode must set nonce");
157  secure_vector<uint8_t> C(CCM_BS);
158 
159  const uint8_t a_flags = static_cast<uint8_t>(L() - 1);
160 
161  C[0] = a_flags;
162  copy_mem(&C[1], m_nonce.data(), m_nonce.size());
163 
164  return C;
165  }
166 
167 void CCM_Encryption::finish(secure_vector<uint8_t>& buffer, size_t offset)
168  {
169  BOTAN_ARG_CHECK(buffer.size() >= offset, "Offset is sane");
170 
171  buffer.insert(buffer.begin() + offset, msg_buf().begin(), msg_buf().end());
172 
173  const size_t sz = buffer.size() - offset;
174  uint8_t* buf = buffer.data() + offset;
175 
176  const secure_vector<uint8_t>& ad = ad_buf();
177  BOTAN_ARG_CHECK(ad.size() % CCM_BS == 0, "AD is block size multiple");
178 
179  const BlockCipher& E = cipher();
180 
181  secure_vector<uint8_t> T(CCM_BS);
182  E.encrypt(format_b0(sz), T);
183 
184  for(size_t i = 0; i != ad.size(); i += CCM_BS)
185  {
186  xor_buf(T.data(), &ad[i], CCM_BS);
187  E.encrypt(T);
188  }
189 
191  secure_vector<uint8_t> S0(CCM_BS);
192  E.encrypt(C, S0);
193  inc(C);
194 
195  secure_vector<uint8_t> X(CCM_BS);
196 
197  const uint8_t* buf_end = &buf[sz];
198 
199  while(buf != buf_end)
200  {
201  const size_t to_proc = std::min<size_t>(CCM_BS, buf_end - buf);
202 
203  xor_buf(T.data(), buf, to_proc);
204  E.encrypt(T);
205 
206  E.encrypt(C, X);
207  xor_buf(buf, X.data(), to_proc);
208  inc(C);
209 
210  buf += to_proc;
211  }
212 
213  T ^= S0;
214 
215  buffer += std::make_pair(T.data(), tag_size());
216 
217  reset();
218  }
219 
220 void CCM_Decryption::finish(secure_vector<uint8_t>& buffer, size_t offset)
221  {
222  BOTAN_ARG_CHECK(buffer.size() >= offset, "Offset is sane");
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_ASSERT(sz >= tag_size(), "We have 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  {
241  xor_buf(T.data(), &ad[i], CCM_BS);
242  E.encrypt(T);
243  }
244 
246 
247  secure_vector<uint8_t> S0(CCM_BS);
248  E.encrypt(C, S0);
249  inc(C);
250 
251  secure_vector<uint8_t> X(CCM_BS);
252 
253  const uint8_t* buf_end = &buf[sz - tag_size()];
254 
255  while(buf != buf_end)
256  {
257  const size_t to_proc = std::min<size_t>(CCM_BS, buf_end - buf);
258 
259  E.encrypt(C, X);
260  xor_buf(buf, X.data(), to_proc);
261  inc(C);
262 
263  xor_buf(T.data(), buf, to_proc);
264  E.encrypt(T);
265 
266  buf += to_proc;
267  }
268 
269  T ^= S0;
270 
271  if(!constant_time_compare(T.data(), buf_end, tag_size()))
272  throw Invalid_Authentication_Tag("CCM tag check failed");
273 
274  buffer.resize(buffer.size() - tag_size());
275 
276  reset();
277  }
278 
279 }
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:153
size_t L() const
Definition: ccm.h:51
const BlockCipher & cipher() const
Definition: ccm.h:53
void finish(secure_vector< uint8_t > &final_block, size_t offset=0) override
Definition: ccm.cpp:167
constexpr uint8_t get_byte(size_t byte_num, T input)
Definition: loadstor.h:41
void encode_length(uint64_t len, uint8_t out[])
Definition: ccm.cpp:117
bool constant_time_compare(const uint8_t x[], const uint8_t y[], size_t len)
Definition: mem_ops.h:82
#define BOTAN_STATE_CHECK(expr)
Definition: assert.h:49
#define BOTAN_ASSERT_NOMSG(expr)
Definition: assert.h:68
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:213
#define BOTAN_ASSERT(expr, assertion_made)
Definition: assert.h:55
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:232
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:130
void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:132
Definition: alg_id.cpp:13
#define BOTAN_ARG_CHECK(expr, msg)
Definition: assert.h:37
void reset() override
Definition: ccm.cpp:41
void finish(secure_vector< uint8_t > &final_block, size_t offset=0) override
Definition: ccm.cpp:220
CCM_Mode(BlockCipher *cipher, size_t tag_size, size_t L)
Definition: ccm.cpp:20
fe T
Definition: ge.cpp:37
std::vector< T, secure_allocator< T > > secure_vector
Definition: secmem.h:65
secure_vector< uint8_t > format_b0(size_t msg_size)
Definition: ccm.cpp:137
Key_Length_Specification key_spec() const override
Definition: ccm.cpp:74
const secure_vector< uint8_t > & ad_buf() const
Definition: ccm.h:59
secure_vector< uint8_t > & msg_buf()
Definition: ccm.h:61
size_t tag_size() const override
Definition: ccm.h:46