Botan  2.15.0
Crypto and TLS for C++11
ocb.cpp
Go to the documentation of this file.
1 /*
2 * OCB Mode
3 * (C) 2013,2017 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/ocb.h>
10 #include <botan/block_cipher.h>
11 #include <botan/internal/poly_dbl.h>
12 #include <botan/internal/bit_ops.h>
13 
14 namespace Botan {
15 
16 // Has to be in Botan namespace so unique_ptr can reference it
17 class L_computer final
18  {
19  public:
20  explicit L_computer(const BlockCipher& cipher) :
21  m_BS(cipher.block_size()),
22  m_max_blocks(cipher.parallel_bytes() / m_BS)
23  {
24  m_L_star.resize(m_BS);
25  cipher.encrypt(m_L_star);
26  m_L_dollar = poly_double(star());
27  m_L.push_back(poly_double(dollar()));
28 
29  while(m_L.size() < 8)
30  m_L.push_back(poly_double(m_L.back()));
31 
32  m_offset_buf.resize(m_BS * m_max_blocks);
33  }
34 
35  void init(const secure_vector<uint8_t>& offset)
36  {
37  m_offset = offset;
38  }
39 
40  bool initialized() const { return m_offset.empty() == false; }
41 
42  const secure_vector<uint8_t>& star() const { return m_L_star; }
43  const secure_vector<uint8_t>& dollar() const { return m_L_dollar; }
44  const secure_vector<uint8_t>& offset() const { return m_offset; }
45 
46  const secure_vector<uint8_t>& get(size_t i) const
47  {
48  while(m_L.size() <= i)
49  m_L.push_back(poly_double(m_L.back()));
50 
51  return m_L[i];
52  }
53 
54  const uint8_t*
55  compute_offsets(size_t block_index, size_t blocks)
56  {
57  BOTAN_ASSERT(blocks <= m_max_blocks, "OCB offsets");
58 
59  uint8_t* offsets = m_offset_buf.data();
60 
61  if(block_index % 4 == 0)
62  {
63  const secure_vector<uint8_t>& L0 = get(0);
64  const secure_vector<uint8_t>& L1 = get(1);
65 
66  while(blocks >= 4)
67  {
68  // ntz(4*i+1) == 0
69  // ntz(4*i+2) == 1
70  // ntz(4*i+3) == 0
71  block_index += 4;
72  const size_t ntz4 = var_ctz32(static_cast<uint32_t>(block_index));
73 
74  xor_buf(offsets, m_offset.data(), L0.data(), m_BS);
75  offsets += m_BS;
76 
77  xor_buf(offsets, offsets - m_BS, L1.data(), m_BS);
78  offsets += m_BS;
79 
80  xor_buf(m_offset.data(), L1.data(), m_BS);
81  copy_mem(offsets, m_offset.data(), m_BS);
82  offsets += m_BS;
83 
84  xor_buf(m_offset.data(), get(ntz4).data(), m_BS);
85  copy_mem(offsets, m_offset.data(), m_BS);
86  offsets += m_BS;
87 
88  blocks -= 4;
89  }
90  }
91 
92  for(size_t i = 0; i != blocks; ++i)
93  { // could be done in parallel
94  const size_t ntz = var_ctz32(static_cast<uint32_t>(block_index + i + 1));
95  xor_buf(m_offset.data(), get(ntz).data(), m_BS);
96  copy_mem(offsets, m_offset.data(), m_BS);
97  offsets += m_BS;
98  }
99 
100  return m_offset_buf.data();
101  }
102 
103  private:
104  secure_vector<uint8_t> poly_double(const secure_vector<uint8_t>& in) const
105  {
106  secure_vector<uint8_t> out(in.size());
107  poly_double_n(out.data(), in.data(), out.size());
108  return out;
109  }
110 
111  const size_t m_BS, m_max_blocks;
112  secure_vector<uint8_t> m_L_dollar, m_L_star;
113  secure_vector<uint8_t> m_offset;
114  mutable std::vector<secure_vector<uint8_t>> m_L;
115  secure_vector<uint8_t> m_offset_buf;
116  };
117 
118 namespace {
119 
120 /*
121 * OCB's HASH
122 */
123 secure_vector<uint8_t> ocb_hash(const L_computer& L,
124  const BlockCipher& cipher,
125  const uint8_t ad[], size_t ad_len)
126  {
127  const size_t BS = cipher.block_size();
128  secure_vector<uint8_t> sum(BS);
129  secure_vector<uint8_t> offset(BS);
130 
131  secure_vector<uint8_t> buf(BS);
132 
133  const size_t ad_blocks = (ad_len / BS);
134  const size_t ad_remainder = (ad_len % BS);
135 
136  for(size_t i = 0; i != ad_blocks; ++i)
137  {
138  // this loop could run in parallel
139  offset ^= L.get(var_ctz32(static_cast<uint32_t>(i+1)));
140  buf = offset;
141  xor_buf(buf.data(), &ad[BS*i], BS);
142  cipher.encrypt(buf);
143  sum ^= buf;
144  }
145 
146  if(ad_remainder)
147  {
148  offset ^= L.star();
149  buf = offset;
150  xor_buf(buf.data(), &ad[BS*ad_blocks], ad_remainder);
151  buf[ad_remainder] ^= 0x80;
152  cipher.encrypt(buf);
153  sum ^= buf;
154  }
155 
156  return sum;
157  }
158 
159 }
160 
161 OCB_Mode::OCB_Mode(BlockCipher* cipher, size_t tag_size) :
162  m_cipher(cipher),
163  m_checksum(m_cipher->parallel_bytes()),
164  m_ad_hash(m_cipher->block_size()),
165  m_tag_size(tag_size),
166  m_block_size(m_cipher->block_size()),
167  m_par_blocks(m_cipher->parallel_bytes() / m_block_size)
168  {
169  const size_t BS = block_size();
170 
171  /*
172  * draft-krovetz-ocb-wide-d1 specifies OCB for several other block
173  * sizes but only 128, 192, 256 and 512 bit are currently supported
174  * by this implementation.
175  */
176  BOTAN_ARG_CHECK(BS == 16 || BS == 24 || BS == 32 || BS == 64,
177  "Invalid block size for OCB");
178 
179  BOTAN_ARG_CHECK(m_tag_size % 4 == 0 &&
180  m_tag_size >= 8 && m_tag_size <= BS &&
181  m_tag_size <= 32,
182  "Invalid OCB tag length");
183  }
184 
185 OCB_Mode::~OCB_Mode() { /* for unique_ptr destructor */ }
186 
188  {
189  m_cipher->clear();
190  m_L.reset(); // add clear here?
191  reset();
192  }
193 
195  {
196  m_block_index = 0;
199  m_last_nonce.clear();
200  m_stretch.clear();
201  }
202 
203 bool OCB_Mode::valid_nonce_length(size_t length) const
204  {
205  if(length == 0)
206  return false;
207  if(block_size() == 16)
208  return length < 16;
209  else
210  return length < (block_size() - 1);
211  }
212 
213 std::string OCB_Mode::name() const
214  {
215  return m_cipher->name() + "/OCB"; // include tag size?
216  }
217 
219  {
220  return (m_par_blocks * block_size());
221  }
222 
224  {
225  return m_cipher->key_spec();
226  }
227 
228 void OCB_Mode::key_schedule(const uint8_t key[], size_t length)
229  {
230  m_cipher->set_key(key, length);
231  m_L.reset(new L_computer(*m_cipher));
232  }
233 
234 void OCB_Mode::set_associated_data(const uint8_t ad[], size_t ad_len)
235  {
236  verify_key_set(m_L != nullptr);
237  m_ad_hash = ocb_hash(*m_L, *m_cipher, ad, ad_len);
238  }
239 
241 OCB_Mode::update_nonce(const uint8_t nonce[], size_t nonce_len)
242  {
243  const size_t BS = block_size();
244 
245  BOTAN_ASSERT(BS == 16 || BS == 24 || BS == 32 || BS == 64,
246  "OCB block size is supported");
247 
248  const size_t MASKLEN = (BS == 16 ? 6 : ((BS == 24) ? 7 : 8));
249 
250  const uint8_t BOTTOM_MASK =
251  static_cast<uint8_t>((static_cast<uint16_t>(1) << MASKLEN) - 1);
252 
253  m_nonce_buf.resize(BS);
254  clear_mem(&m_nonce_buf[0], m_nonce_buf.size());
255 
256  copy_mem(&m_nonce_buf[BS - nonce_len], nonce, nonce_len);
257  m_nonce_buf[0] = static_cast<uint8_t>(((tag_size()*8) % (BS*8)) << (BS <= 16 ? 1 : 0));
258 
259  m_nonce_buf[BS - nonce_len - 1] ^= 1;
260 
261  const uint8_t bottom = m_nonce_buf[BS-1] & BOTTOM_MASK;
262  m_nonce_buf[BS-1] &= ~BOTTOM_MASK;
263 
264  const bool need_new_stretch = (m_last_nonce != m_nonce_buf);
265 
266  if(need_new_stretch)
267  {
268  m_last_nonce = m_nonce_buf;
269 
270  m_cipher->encrypt(m_nonce_buf);
271 
272  /*
273  The loop bounds (BS vs BS/2) are derived from the relation
274  between the block size and the MASKLEN. Using the terminology
275  of draft-krovetz-ocb-wide, we have to derive enough bits in
276  ShiftedKtop to read up to BLOCKLEN+bottom bits from Stretch.
277 
278  +----------+---------+-------+---------+
279  | BLOCKLEN | RESIDUE | SHIFT | MASKLEN |
280  +----------+---------+-------+---------+
281  | 32 | 141 | 17 | 4 |
282  | 64 | 27 | 25 | 5 |
283  | 96 | 1601 | 33 | 6 |
284  | 128 | 135 | 8 | 6 |
285  | 192 | 135 | 40 | 7 |
286  | 256 | 1061 | 1 | 8 |
287  | 384 | 4109 | 80 | 8 |
288  | 512 | 293 | 176 | 8 |
289  | 1024 | 524355 | 352 | 9 |
290  +----------+---------+-------+---------+
291  */
292  if(BS == 16)
293  {
294  for(size_t i = 0; i != BS / 2; ++i)
295  m_nonce_buf.push_back(m_nonce_buf[i] ^ m_nonce_buf[i+1]);
296  }
297  else if(BS == 24)
298  {
299  for(size_t i = 0; i != 16; ++i)
300  m_nonce_buf.push_back(m_nonce_buf[i] ^ m_nonce_buf[i+5]);
301  }
302  else if(BS == 32)
303  {
304  for(size_t i = 0; i != BS; ++i)
305  m_nonce_buf.push_back(m_nonce_buf[i] ^ (m_nonce_buf[i] << 1) ^ (m_nonce_buf[i+1] >> 7));
306  }
307  else if(BS == 64)
308  {
309  for(size_t i = 0; i != BS / 2; ++i)
310  m_nonce_buf.push_back(m_nonce_buf[i] ^ m_nonce_buf[i+22]);
311  }
312 
313  m_stretch = m_nonce_buf;
314  }
315 
316  // now set the offset from stretch and bottom
317  const size_t shift_bytes = bottom / 8;
318  const size_t shift_bits = bottom % 8;
319 
320  BOTAN_ASSERT(m_stretch.size() >= BS + shift_bytes + 1, "Size ok");
321 
322  m_offset.resize(BS);
323  for(size_t i = 0; i != BS; ++i)
324  {
325  m_offset[i] = (m_stretch[i+shift_bytes] << shift_bits);
326  m_offset[i] |= (m_stretch[i+shift_bytes+1] >> (8-shift_bits));
327  }
328 
329  return m_offset;
330  }
331 
332 void OCB_Mode::start_msg(const uint8_t nonce[], size_t nonce_len)
333  {
334  if(!valid_nonce_length(nonce_len))
335  throw Invalid_IV_Length(name(), nonce_len);
336 
337  verify_key_set(m_L != nullptr);
338 
339  m_L->init(update_nonce(nonce, nonce_len));
341  m_block_index = 0;
342  }
343 
344 void OCB_Encryption::encrypt(uint8_t buffer[], size_t blocks)
345  {
346  verify_key_set(m_L != nullptr);
347  BOTAN_STATE_CHECK(m_L->initialized());
348 
349  const size_t BS = block_size();
350 
351  while(blocks)
352  {
353  const size_t proc_blocks = std::min(blocks, par_blocks());
354  const size_t proc_bytes = proc_blocks * BS;
355 
356  const uint8_t* offsets = m_L->compute_offsets(m_block_index, proc_blocks);
357 
358  xor_buf(m_checksum.data(), buffer, proc_bytes);
359 
360  m_cipher->encrypt_n_xex(buffer, offsets, proc_blocks);
361 
362  buffer += proc_bytes;
363  blocks -= proc_blocks;
364  m_block_index += proc_blocks;
365  }
366  }
367 
368 size_t OCB_Encryption::process(uint8_t buf[], size_t sz)
369  {
370  BOTAN_ASSERT(sz % update_granularity() == 0, "Invalid OCB input size");
371  encrypt(buf, sz / block_size());
372  return sz;
373  }
374 
375 void OCB_Encryption::finish(secure_vector<uint8_t>& buffer, size_t offset)
376  {
377  verify_key_set(m_L != nullptr);
378 
379  const size_t BS = block_size();
380 
381  BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
382  const size_t sz = buffer.size() - offset;
383  uint8_t* buf = buffer.data() + offset;
384 
385  secure_vector<uint8_t> mac(BS);
386 
387  if(sz)
388  {
389  const size_t final_full_blocks = sz / BS;
390  const size_t remainder_bytes = sz - (final_full_blocks * BS);
391 
392  encrypt(buf, final_full_blocks);
393  mac = m_L->offset();
394 
395  if(remainder_bytes)
396  {
397  BOTAN_ASSERT(remainder_bytes < BS, "Only a partial block left");
398  uint8_t* remainder = &buf[sz - remainder_bytes];
399 
400  xor_buf(m_checksum.data(), remainder, remainder_bytes);
401  m_checksum[remainder_bytes] ^= 0x80;
402 
403  // Offset_*
404  mac ^= m_L->star();
405 
406  secure_vector<uint8_t> pad(BS);
407  m_cipher->encrypt(mac, pad);
408  xor_buf(remainder, pad.data(), remainder_bytes);
409  }
410  }
411  else
412  {
413  mac = m_L->offset();
414  }
415 
416  // now compute the tag
417 
418  // fold checksum
419  for(size_t i = 0; i != m_checksum.size(); i += BS)
420  {
421  xor_buf(mac.data(), m_checksum.data() + i, BS);
422  }
423 
424  xor_buf(mac.data(), m_L->dollar().data(), BS);
425  m_cipher->encrypt(mac);
426  xor_buf(mac.data(), m_ad_hash.data(), BS);
427 
428  buffer += std::make_pair(mac.data(), tag_size());
429 
431  m_block_index = 0;
432  }
433 
434 void OCB_Decryption::decrypt(uint8_t buffer[], size_t blocks)
435  {
436  verify_key_set(m_L != nullptr);
437  BOTAN_STATE_CHECK(m_L->initialized());
438 
439  const size_t BS = block_size();
440 
441  while(blocks)
442  {
443  const size_t proc_blocks = std::min(blocks, par_blocks());
444  const size_t proc_bytes = proc_blocks * BS;
445 
446  const uint8_t* offsets = m_L->compute_offsets(m_block_index, proc_blocks);
447 
448  m_cipher->decrypt_n_xex(buffer, offsets, proc_blocks);
449 
450  xor_buf(m_checksum.data(), buffer, proc_bytes);
451 
452  buffer += proc_bytes;
453  blocks -= proc_blocks;
454  m_block_index += proc_blocks;
455  }
456  }
457 
458 size_t OCB_Decryption::process(uint8_t buf[], size_t sz)
459  {
460  BOTAN_ASSERT(sz % update_granularity() == 0, "Invalid OCB input size");
461  decrypt(buf, sz / block_size());
462  return sz;
463  }
464 
465 void OCB_Decryption::finish(secure_vector<uint8_t>& buffer, size_t offset)
466  {
467  verify_key_set(m_L != nullptr);
468 
469  const size_t BS = block_size();
470 
471  BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
472  const size_t sz = buffer.size() - offset;
473  uint8_t* buf = buffer.data() + offset;
474 
475  BOTAN_ASSERT(sz >= tag_size(), "We have the tag");
476 
477  const size_t remaining = sz - tag_size();
478 
479  secure_vector<uint8_t> mac(BS);
480 
481  if(remaining)
482  {
483  const size_t final_full_blocks = remaining / BS;
484  const size_t final_bytes = remaining - (final_full_blocks * BS);
485 
486  decrypt(buf, final_full_blocks);
487  mac ^= m_L->offset();
488 
489  if(final_bytes)
490  {
491  BOTAN_ASSERT(final_bytes < BS, "Only a partial block left");
492 
493  uint8_t* remainder = &buf[remaining - final_bytes];
494 
495  mac ^= m_L->star();
496  secure_vector<uint8_t> pad(BS);
497  m_cipher->encrypt(mac, pad); // P_*
498  xor_buf(remainder, pad.data(), final_bytes);
499 
500  xor_buf(m_checksum.data(), remainder, final_bytes);
501  m_checksum[final_bytes] ^= 0x80;
502  }
503  }
504  else
505  mac = m_L->offset();
506 
507  // compute the mac
508 
509  // fold checksum
510  for(size_t i = 0; i != m_checksum.size(); i += BS)
511  {
512  xor_buf(mac.data(), m_checksum.data() + i, BS);
513  }
514 
515  mac ^= m_L->dollar();
516  m_cipher->encrypt(mac);
517  mac ^= m_ad_hash;
518 
519  // reset state
521  m_block_index = 0;
522 
523  // compare mac
524  const uint8_t* included_tag = &buf[remaining];
525 
526  if(!constant_time_compare(mac.data(), included_tag, tag_size()))
527  throw Invalid_Authentication_Tag("OCB tag check failed");
528 
529  // remove tag from end of message
530  buffer.resize(remaining + offset);
531  }
532 
533 }
std::unique_ptr< BlockCipher > m_cipher
Definition: ocb.h:65
void finish(secure_vector< uint8_t > &final_block, size_t offset=0) override
Definition: ocb.cpp:375
size_t var_ctz32(uint32_t n)
Definition: bit_ops.h:139
void verify_key_set(bool cond) const
Definition: sym_algo.h:89
bool valid_nonce_length(size_t) const override
Definition: ocb.cpp:203
void set_associated_data(const uint8_t ad[], size_t ad_len) override
Definition: ocb.cpp:234
void clear_mem(T *ptr, size_t n)
Definition: mem_ops.h:115
int(* final)(unsigned char *, CTX *)
void poly_double_n(uint8_t out[], const uint8_t in[], size_t n)
Definition: poly_dbl.cpp:73
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
size_t tag_size() const override
Definition: ocb.h:46
void reset() override
Definition: ocb.cpp:194
size_t par_blocks() const
Definition: ocb.h:61
#define BOTAN_ASSERT(expr, assertion_made)
Definition: assert.h:55
void xor_buf(uint8_t out[], const uint8_t in[], size_t length)
Definition: mem_ops.h:233
void finish(secure_vector< uint8_t > &final_block, size_t offset=0) override
Definition: ocb.cpp:465
size_t update_granularity() const override
Definition: ocb.cpp:218
void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:133
Definition: alg_id.cpp:13
#define BOTAN_ARG_CHECK(expr, msg)
Definition: assert.h:37
std::unique_ptr< L_computer > m_L
Definition: ocb.h:66
size_t block_size() const
Definition: ocb.h:60
int(* init)(CTX *)
secure_vector< uint8_t > m_ad_hash
Definition: ocb.h:71
OCB_Mode(BlockCipher *cipher, size_t tag_size)
Definition: ocb.cpp:161
secure_vector< uint8_t > m_checksum
Definition: ocb.h:70
size_t process(uint8_t buf[], size_t size) override
Definition: ocb.cpp:368
std::vector< T, secure_allocator< T > > secure_vector
Definition: secmem.h:65
size_t m_block_index
Definition: ocb.h:68
void clear() override
Definition: ocb.cpp:187
std::string name() const override
Definition: ocb.cpp:213
size_t process(uint8_t buf[], size_t size) override
Definition: ocb.cpp:458
Key_Length_Specification key_spec() const override
Definition: ocb.cpp:223
void zeroise(std::vector< T, Alloc > &vec)
Definition: secmem.h:160