Botan  2.11.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 >= 1 && 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  secure_vector<uint8_t> B0(CCM_BS);
140 
141  const uint8_t b_flags =
142  static_cast<uint8_t>((m_ad_buf.size() ? 64 : 0) + (((tag_size()/2)-1) << 3) + (L()-1));
143 
144  B0[0] = b_flags;
145  copy_mem(&B0[1], m_nonce.data(), m_nonce.size());
146  encode_length(sz, &B0[m_nonce.size()+1]);
147 
148  return B0;
149  }
150 
152  {
153  secure_vector<uint8_t> C(CCM_BS);
154 
155  const uint8_t a_flags = static_cast<uint8_t>(L() - 1);
156 
157  C[0] = a_flags;
158  copy_mem(&C[1], m_nonce.data(), m_nonce.size());
159 
160  return C;
161  }
162 
163 void CCM_Encryption::finish(secure_vector<uint8_t>& buffer, size_t offset)
164  {
165  BOTAN_ARG_CHECK(buffer.size() >= offset, "Offset is sane");
166 
167  buffer.insert(buffer.begin() + offset, msg_buf().begin(), msg_buf().end());
168 
169  const size_t sz = buffer.size() - offset;
170  uint8_t* buf = buffer.data() + offset;
171 
172  const secure_vector<uint8_t>& ad = ad_buf();
173  BOTAN_ARG_CHECK(ad.size() % CCM_BS == 0, "AD is block size multiple");
174 
175  const BlockCipher& E = cipher();
176 
177  secure_vector<uint8_t> T(CCM_BS);
178  E.encrypt(format_b0(sz), T);
179 
180  for(size_t i = 0; i != ad.size(); i += CCM_BS)
181  {
182  xor_buf(T.data(), &ad[i], CCM_BS);
183  E.encrypt(T);
184  }
185 
187  secure_vector<uint8_t> S0(CCM_BS);
188  E.encrypt(C, S0);
189  inc(C);
190 
191  secure_vector<uint8_t> X(CCM_BS);
192 
193  const uint8_t* buf_end = &buf[sz];
194 
195  while(buf != buf_end)
196  {
197  const size_t to_proc = std::min<size_t>(CCM_BS, buf_end - buf);
198 
199  xor_buf(T.data(), buf, to_proc);
200  E.encrypt(T);
201 
202  E.encrypt(C, X);
203  xor_buf(buf, X.data(), to_proc);
204  inc(C);
205 
206  buf += to_proc;
207  }
208 
209  T ^= S0;
210 
211  buffer += std::make_pair(T.data(), tag_size());
212  }
213 
214 void CCM_Decryption::finish(secure_vector<uint8_t>& buffer, size_t offset)
215  {
216  BOTAN_ARG_CHECK(buffer.size() >= offset, "Offset is sane");
217 
218  buffer.insert(buffer.begin() + offset, msg_buf().begin(), msg_buf().end());
219 
220  const size_t sz = buffer.size() - offset;
221  uint8_t* buf = buffer.data() + offset;
222 
223  BOTAN_ASSERT(sz >= tag_size(), "We have the tag");
224 
225  const secure_vector<uint8_t>& ad = ad_buf();
226  BOTAN_ARG_CHECK(ad.size() % CCM_BS == 0, "AD is block size multiple");
227 
228  const BlockCipher& E = cipher();
229 
230  secure_vector<uint8_t> T(CCM_BS);
231  E.encrypt(format_b0(sz - tag_size()), T);
232 
233  for(size_t i = 0; i != ad.size(); i += CCM_BS)
234  {
235  xor_buf(T.data(), &ad[i], CCM_BS);
236  E.encrypt(T);
237  }
238 
240 
241  secure_vector<uint8_t> S0(CCM_BS);
242  E.encrypt(C, S0);
243  inc(C);
244 
245  secure_vector<uint8_t> X(CCM_BS);
246 
247  const uint8_t* buf_end = &buf[sz - tag_size()];
248 
249  while(buf != buf_end)
250  {
251  const size_t to_proc = std::min<size_t>(CCM_BS, buf_end - buf);
252 
253  E.encrypt(C, X);
254  xor_buf(buf, X.data(), to_proc);
255  inc(C);
256 
257  xor_buf(T.data(), buf, to_proc);
258  E.encrypt(T);
259 
260  buf += to_proc;
261  }
262 
263  T ^= S0;
264 
265  if(!constant_time_compare(T.data(), buf_end, tag_size()))
266  throw Invalid_Authentication_Tag("CCM tag check failed");
267 
268  buffer.resize(buffer.size() - tag_size());
269  }
270 
271 }
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:151
size_t L() const
Definition: ccm.h:49
const BlockCipher & cipher() const
Definition: ccm.h:51
void finish(secure_vector< uint8_t > &final_block, size_t offset=0) override
Definition: ccm.cpp:163
constexpr uint8_t get_byte(size_t byte_num, T input)
Definition: loadstor.h:39
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:81
#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:202
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:122
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:214
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:57
secure_vector< uint8_t > & msg_buf()
Definition: ccm.h:59
size_t tag_size() const override
Definition: ccm.h:44