Coverage Report

Created: 2020-06-30 13:58

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