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