9#include <botan/internal/ocb.h>
11#include <botan/block_cipher.h>
12#include <botan/internal/bit_ops.h>
13#include <botan/internal/ct_utils.h>
14#include <botan/internal/poly_dbl.h>
19class L_computer
final {
21 explicit L_computer(
const BlockCipher& cipher) :
22 m_BS(cipher.block_size()), m_max_blocks(cipher.parallel_bytes() / m_BS) {
23 m_L_star.resize(m_BS);
24 cipher.encrypt(m_L_star);
25 m_L_dollar = poly_double(star());
37 m_L.push_back(poly_double(dollar()));
39 while(m_L.size() < 8) {
40 m_L.push_back(poly_double(m_L.back()));
43 m_offset_buf.resize(m_BS * m_max_blocks);
46 void init(
const secure_vector<uint8_t>& offset) { m_offset = offset; }
48 bool initialized()
const {
return m_offset.empty() ==
false; }
50 const secure_vector<uint8_t>& star()
const {
return m_L_star; }
52 const secure_vector<uint8_t>& dollar()
const {
return m_L_dollar; }
54 const secure_vector<uint8_t>& offset()
const {
return m_offset; }
56 const secure_vector<uint8_t>& get(
size_t i)
const {
57 while(m_L.size() <= i) {
58 m_L.push_back(poly_double(m_L.back()));
64 const uint8_t* compute_offsets(
size_t block_index,
size_t blocks) {
67 uint8_t* offsets = m_offset_buf.data();
69 if(block_index % 4 == 0) {
70 const secure_vector<uint8_t>& L0 = get(0);
71 const secure_vector<uint8_t>& L1 = get(1);
78 const size_t ntz4 =
var_ctz32(
static_cast<uint32_t
>(block_index));
80 xor_buf(offsets, m_offset.data(), L0.data(), m_BS);
83 xor_buf(offsets, offsets - m_BS, L1.data(), m_BS);
86 xor_buf(m_offset.data(), L1.data(), m_BS);
87 copy_mem(offsets, m_offset.data(), m_BS);
90 xor_buf(m_offset.data(), get(ntz4).data(), m_BS);
91 copy_mem(offsets, m_offset.data(), m_BS);
98 for(
size_t i = 0; i != blocks; ++i) {
99 const size_t ntz =
var_ctz32(
static_cast<uint32_t
>(block_index + i + 1));
100 xor_buf(m_offset.data(), get(ntz).data(), m_BS);
101 copy_mem(offsets, m_offset.data(), m_BS);
105 return m_offset_buf.data();
109 static secure_vector<uint8_t> poly_double(
const secure_vector<uint8_t>& in) {
110 secure_vector<uint8_t> out(in.size());
115 const size_t m_BS, m_max_blocks;
116 secure_vector<uint8_t> m_L_dollar, m_L_star;
117 secure_vector<uint8_t> m_offset;
118 mutable std::vector<secure_vector<uint8_t>> m_L;
119 secure_vector<uint8_t> m_offset_buf;
127secure_vector<uint8_t> ocb_hash(
const L_computer& L,
const BlockCipher& cipher,
const uint8_t ad[],
size_t ad_len) {
128 const size_t BS = cipher.block_size();
129 secure_vector<uint8_t> sum(BS);
130 secure_vector<uint8_t> offset(BS);
132 secure_vector<uint8_t> buf(BS);
134 const size_t ad_blocks = (ad_len / BS);
135 const size_t ad_remainder = (ad_len % BS);
137 for(
size_t i = 0; i != ad_blocks; ++i) {
139 offset ^= L.get(
var_ctz32(
static_cast<uint32_t
>(i + 1)));
141 xor_buf(buf.data(), &ad[BS * i], BS);
149 xor_buf(buf.data(), &ad[BS * ad_blocks], ad_remainder);
150 buf[ad_remainder] ^= 0x80;
161 m_cipher(std::move(cipher)),
162 m_checksum(m_cipher->parallel_bytes()),
163 m_ad_hash(m_cipher->block_size()),
164 m_tag_size(tag_size),
165 m_block_size(m_cipher->block_size()),
166 m_par_blocks(m_cipher->parallel_bytes() / m_block_size) {
174 BOTAN_ARG_CHECK(BS == 16 || BS == 24 || BS == 32 || BS == 64,
"Invalid block size for OCB");
176 BOTAN_ARG_CHECK(m_tag_size % 4 == 0 && m_tag_size >= 8 && m_tag_size <= BS && m_tag_size <= 32,
177 "Invalid OCB tag length");
192 m_last_nonce.clear();
224 return m_cipher->has_keying_material();
227void OCB_Mode::key_schedule(std::span<const uint8_t> key) {
233 BOTAN_ARG_CHECK(idx == 0,
"OCB: cannot handle non-zero index in set_associated_data_n");
241 BOTAN_ASSERT(BS == 16 || BS == 24 || BS == 32 || BS == 64,
"OCB block size is supported");
243 const size_t MASKLEN = (BS == 16 ? 6 : ((BS == 24) ? 7 : 8));
245 const uint8_t BOTTOM_MASK =
static_cast<uint8_t
>((
static_cast<uint16_t
>(1) << MASKLEN) - 1);
247 m_nonce_buf.resize(BS);
248 clear_mem(&m_nonce_buf[0], m_nonce_buf.size());
250 copy_mem(&m_nonce_buf[BS - nonce_len], nonce, nonce_len);
251 m_nonce_buf[0] =
static_cast<uint8_t
>(((
tag_size() * 8) % (BS * 8)) << (BS <= 16 ? 1 : 0));
253 m_nonce_buf[BS - nonce_len - 1] ^= 1;
255 const uint8_t bottom = m_nonce_buf[BS - 1] & BOTTOM_MASK;
256 m_nonce_buf[BS - 1] &= ~BOTTOM_MASK;
258 const bool need_new_stretch = (m_last_nonce != m_nonce_buf);
260 if(need_new_stretch) {
261 m_last_nonce = m_nonce_buf;
286 for(
size_t i = 0; i != BS / 2; ++i) {
287 m_nonce_buf.push_back(m_nonce_buf[i] ^ m_nonce_buf[i + 1]);
289 }
else if(BS == 24) {
290 for(
size_t i = 0; i != 16; ++i) {
291 m_nonce_buf.push_back(m_nonce_buf[i] ^ m_nonce_buf[i + 5]);
293 }
else if(BS == 32) {
294 for(
size_t i = 0; i != BS; ++i) {
295 m_nonce_buf.push_back(m_nonce_buf[i] ^ (m_nonce_buf[i] << 1) ^ (m_nonce_buf[i + 1] >> 7));
297 }
else if(BS == 64) {
298 for(
size_t i = 0; i != BS / 2; ++i) {
299 m_nonce_buf.push_back(m_nonce_buf[i] ^ m_nonce_buf[i + 22]);
303 m_stretch = m_nonce_buf;
307 const size_t shift_bytes = bottom / 8;
308 const size_t shift_bits = bottom % 8;
310 BOTAN_ASSERT(m_stretch.size() >= BS + shift_bytes + 1,
"Size ok");
313 for(
size_t i = 0; i != BS; ++i) {
314 m_offset[i] = (m_stretch[i + shift_bytes] << shift_bits);
315 m_offset[i] |= (m_stretch[i + shift_bytes + 1] >> (8 - shift_bits));
321void OCB_Mode::start_msg(
const uint8_t nonce[],
size_t nonce_len) {
323 throw Invalid_IV_Length(
name(), nonce_len);
328 m_L->init(update_nonce(nonce, nonce_len));
333void OCB_Encryption::encrypt(uint8_t buffer[],
size_t blocks) {
340 const size_t proc_blocks = std::min(blocks,
par_blocks());
341 const size_t proc_bytes = proc_blocks * BS;
347 m_cipher->encrypt_n_xex(buffer, offsets, proc_blocks);
349 buffer += proc_bytes;
350 blocks -= proc_blocks;
355size_t OCB_Encryption::process_msg(uint8_t buf[],
size_t sz) {
361void OCB_Encryption::finish_msg(secure_vector<uint8_t>& buffer,
size_t offset) {
368 const size_t sz = buffer.size() - offset;
369 uint8_t* buf = buffer.data() + offset;
371 secure_vector<uint8_t> mac(BS);
374 const size_t final_full_blocks = sz / BS;
375 const size_t remainder_bytes = sz - (final_full_blocks * BS);
377 encrypt(buf, final_full_blocks);
380 if(remainder_bytes) {
381 BOTAN_ASSERT(remainder_bytes < BS,
"Only a partial block left");
382 uint8_t* remainder = &buf[sz - remainder_bytes];
390 secure_vector<uint8_t> pad(BS);
392 xor_buf(remainder, pad.data(), remainder_bytes);
401 for(
size_t i = 0; i !=
m_checksum.size(); i += BS) {
405 xor_buf(mac.data(),
m_L->dollar().data(), BS);
409 buffer += std::make_pair(mac.data(),
tag_size());
415void OCB_Decryption::decrypt(uint8_t buffer[],
size_t blocks) {
422 const size_t proc_blocks = std::min(blocks,
par_blocks());
423 const size_t proc_bytes = proc_blocks * BS;
427 m_cipher->decrypt_n_xex(buffer, offsets, proc_blocks);
431 buffer += proc_bytes;
432 blocks -= proc_blocks;
437size_t OCB_Decryption::process_msg(uint8_t buf[],
size_t sz) {
443void OCB_Decryption::finish_msg(secure_vector<uint8_t>& buffer,
size_t offset) {
450 const size_t sz = buffer.size() - offset;
451 uint8_t* buf = buffer.data() + offset;
455 const size_t remaining = sz -
tag_size();
457 secure_vector<uint8_t> mac(BS);
460 const size_t final_full_blocks = remaining / BS;
461 const size_t final_bytes = remaining - (final_full_blocks * BS);
463 decrypt(buf, final_full_blocks);
464 mac ^=
m_L->offset();
467 BOTAN_ASSERT(final_bytes < BS,
"Only a partial block left");
469 uint8_t* remainder = &buf[remaining - final_bytes];
472 secure_vector<uint8_t> pad(BS);
474 xor_buf(remainder, pad.data(), final_bytes);
486 for(
size_t i = 0; i !=
m_checksum.size(); i += BS) {
490 mac ^=
m_L->dollar();
499 const uint8_t* included_tag = &buf[remaining];
502 throw Invalid_Authentication_Tag(
"OCB tag check failed");
506 buffer.resize(remaining + offset);
#define BOTAN_STATE_CHECK(expr)
#define BOTAN_ARG_CHECK(expr, msg)
#define BOTAN_ASSERT(expr, assertion_made)
std::string name() const override final
size_t block_size() const
size_t par_blocks() const
size_t tag_size() const override final
bool has_keying_material() const override final
size_t ideal_granularity() const override final
bool valid_nonce_length(size_t) const override final
void reset() override final
secure_vector< uint8_t > m_checksum
std::unique_ptr< BlockCipher > m_cipher
secure_vector< uint8_t > m_ad_hash
void clear() override final
void set_associated_data_n(size_t idx, std::span< const uint8_t > ad) override final
size_t update_granularity() const override final
Key_Length_Specification key_spec() const override final
OCB_Mode(std::unique_ptr< BlockCipher > cipher, size_t tag_size)
std::unique_ptr< L_computer > m_L
void assert_key_material_set() const
int(* final)(unsigned char *, CTX *)
CT::Mask< T > is_equal(const T x[], const T y[], size_t len)
void zeroise(std::vector< T, Alloc > &vec)
constexpr size_t var_ctz32(uint32_t n)
constexpr void xor_buf(ranges::contiguous_output_range< uint8_t > auto &&out, ranges::contiguous_range< uint8_t > auto &&in)
std::vector< T, secure_allocator< T > > secure_vector
void poly_double_n(uint8_t out[], const uint8_t in[], size_t n)
constexpr void copy_mem(T *out, const T *in, size_t n)
constexpr void clear_mem(T *ptr, size_t n)