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