aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/modes/aead/ocb
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2016-09-01 13:40:26 -0400
committerJack Lloyd <[email protected]>2016-09-01 14:16:38 -0400
commit507d926da825fbc1d9d74b4517dbab47702c66b9 (patch)
tree22ac0e4a9c85fb3583d478a41ba1c46aeced5ec3 /src/lib/modes/aead/ocb
parente4656be6a8e601b64c759906bacf543388b3cf22 (diff)
Cipher_Mode API improvements
The Cipher_Mode::update API is more general than needed to just support ciphers (this is due to it previously being an API of Transform which before 8b85b780515 was Cipher_Mode's base class) Define a less general interface `process` which either processes the blocks in-place, producing exactly as much output as there was input, or (SIV/CCM case) saves the entire message for processing in `finish`. These two uses cover all current or anticipated cipher modes. Leaves `update` for compatability with existing callers; all that is needed is an inline function forwarding to `process`. Removes the return type from `start` - in all cipher implementations, this always returned an empty vector. Adds BOTAN_ARG_CHECK macro; right now BOTAN_ASSERT is being used for argument checking in some places, which is not right at all.
Diffstat (limited to 'src/lib/modes/aead/ocb')
-rw-r--r--src/lib/modes/aead/ocb/ocb.cpp113
-rw-r--r--src/lib/modes/aead/ocb/ocb.h9
2 files changed, 52 insertions, 70 deletions
diff --git a/src/lib/modes/aead/ocb/ocb.cpp b/src/lib/modes/aead/ocb/ocb.cpp
index 77126ec7a..e21749f3b 100644
--- a/src/lib/modes/aead/ocb/ocb.cpp
+++ b/src/lib/modes/aead/ocb/ocb.cpp
@@ -33,13 +33,12 @@ class L_computer
size_t block_index,
size_t blocks) const
{
- const size_t BS = m_L_star.size();
- m_offset_buf.resize(blocks * BS);
+ m_offset_buf.resize(blocks * 16);
for(size_t i = 0; i != blocks; ++i)
{ // could be done in parallel
offset ^= get(ctz(block_index + 1 + i));
- copy_mem(&m_offset_buf[BS*i], offset.data(), BS);
+ copy_mem(&m_offset_buf[16*i], offset.data(), 16);
}
return m_offset_buf;
@@ -73,15 +72,13 @@ secure_vector<byte> ocb_hash(const L_computer& L,
const BlockCipher& cipher,
const byte ad[], size_t ad_len)
{
- const size_t BS = cipher.block_size();
+ secure_vector<byte> sum(16);
+ secure_vector<byte> offset(16);
- secure_vector<byte> sum(BS);
- secure_vector<byte> offset(BS);
+ secure_vector<byte> buf(16);
- secure_vector<byte> buf(BS);
-
- const size_t ad_blocks = (ad_len / BS);
- const size_t ad_remainder = (ad_len % BS);
+ const size_t ad_blocks = (ad_len / 16);
+ const size_t ad_remainder = (ad_len % 16);
for(size_t i = 0; i != ad_blocks; ++i)
{
@@ -89,7 +86,7 @@ secure_vector<byte> ocb_hash(const L_computer& L,
offset ^= L(ctz(i+1));
buf = offset;
- xor_buf(buf.data(), &ad[BS*i], BS);
+ xor_buf(buf.data(), &ad[16*i], 16);
cipher.encrypt(buf);
@@ -101,8 +98,8 @@ secure_vector<byte> ocb_hash(const L_computer& L,
offset ^= L.star();
buf = offset;
- xor_buf(buf.data(), &ad[BS*ad_blocks], ad_remainder);
- buf[ad_len % BS] ^= 0x80;
+ xor_buf(buf.data(), &ad[16*ad_blocks], ad_remainder);
+ buf[ad_len % 16] ^= 0x80;
cipher.encrypt(buf);
@@ -116,19 +113,16 @@ secure_vector<byte> ocb_hash(const L_computer& L,
OCB_Mode::OCB_Mode(BlockCipher* cipher, size_t tag_size) :
m_cipher(cipher),
- m_BS(m_cipher->block_size()),
m_checksum(m_cipher->parallel_bytes()),
- m_offset(m_BS),
- m_ad_hash(m_BS),
+ m_offset(16),
+ m_ad_hash(16),
m_tag_size(tag_size)
{
- if(BS() != 16)
- throw Invalid_Argument("OCB is not compatible with " + m_cipher->name());
-
- if(m_tag_size % 4 != 0 || m_tag_size < 8 || m_tag_size > BS())
- throw Invalid_Argument("OCB cannot produce a " + std::to_string(m_tag_size) +
- " byte tag");
+ if(m_cipher->block_size() != 16)
+ throw Invalid_Argument("OCB requires 128 bit cipher");
+ if(m_tag_size % 4 != 0 || m_tag_size < 8 || m_tag_size > 16)
+ throw Invalid_Argument("Invalid OCB tag length");
}
OCB_Mode::~OCB_Mode() { /* for unique_ptr destructor */ }
@@ -178,16 +172,16 @@ void OCB_Mode::set_associated_data(const byte ad[], size_t ad_len)
secure_vector<byte>
OCB_Mode::update_nonce(const byte nonce[], size_t nonce_len)
{
- BOTAN_ASSERT(nonce_len < BS(), "OCB nonce is less than cipher block size");
+ BOTAN_ASSERT(nonce_len < 16, "OCB nonce is less than cipher block size");
- secure_vector<byte> nonce_buf(BS());
+ secure_vector<byte> nonce_buf(16);
- copy_mem(&nonce_buf[BS() - nonce_len], nonce, nonce_len);
+ copy_mem(&nonce_buf[16 - nonce_len], nonce, nonce_len);
nonce_buf[0] = ((tag_size() * 8) % 128) << 1;
- nonce_buf[BS() - nonce_len - 1] = 1;
+ nonce_buf[16 - nonce_len - 1] = 1;
- const byte bottom = nonce_buf[BS()-1] & 0x3F;
- nonce_buf[BS()-1] &= 0xC0;
+ const byte bottom = nonce_buf[16-1] & 0x3F;
+ nonce_buf[16-1] &= 0xC0;
const bool need_new_stretch = (m_last_nonce != nonce_buf);
@@ -197,7 +191,7 @@ OCB_Mode::update_nonce(const byte nonce[], size_t nonce_len)
m_cipher->encrypt(nonce_buf);
- for(size_t i = 0; i != BS() / 2; ++i)
+ for(size_t i = 0; i != 16 / 2; ++i)
nonce_buf.push_back(nonce_buf[i] ^ nonce_buf[i+1]);
m_stretch = nonce_buf;
@@ -208,8 +202,8 @@ OCB_Mode::update_nonce(const byte nonce[], size_t nonce_len)
const size_t shift_bytes = bottom / 8;
const size_t shift_bits = bottom % 8;
- secure_vector<byte> offset(BS());
- for(size_t i = 0; i != BS(); ++i)
+ secure_vector<byte> offset(16);
+ for(size_t i = 0; i != 16; ++i)
{
offset[i] = (m_stretch[i+shift_bytes] << shift_bits);
offset[i] |= (m_stretch[i+shift_bytes+1] >> (8-shift_bits));
@@ -218,7 +212,7 @@ OCB_Mode::update_nonce(const byte nonce[], size_t nonce_len)
return offset;
}
-secure_vector<byte> OCB_Mode::start_raw(const byte nonce[], size_t nonce_len)
+void OCB_Mode::start_msg(const byte nonce[], size_t nonce_len)
{
if(!valid_nonce_length(nonce_len))
throw Invalid_IV_Length(name(), nonce_len);
@@ -228,18 +222,16 @@ secure_vector<byte> OCB_Mode::start_raw(const byte nonce[], size_t nonce_len)
m_offset = update_nonce(nonce, nonce_len);
zeroise(m_checksum);
m_block_index = 0;
-
- return secure_vector<byte>();
}
void OCB_Encryption::encrypt(byte buffer[], size_t blocks)
{
- const size_t par_blocks = m_checksum.size() / BS();
+ const size_t par_blocks = m_checksum.size() / 16;
while(blocks)
{
const size_t proc_blocks = std::min(blocks, par_blocks);
- const size_t proc_bytes = proc_blocks * BS();
+ const size_t proc_bytes = proc_blocks * 16;
const auto& offsets = m_L->compute_offsets(m_offset, m_block_index, proc_blocks);
@@ -255,14 +247,11 @@ void OCB_Encryption::encrypt(byte buffer[], size_t blocks)
}
}
-void OCB_Encryption::update(secure_vector<byte>& buffer, size_t offset)
+size_t OCB_Encryption::process(uint8_t buf[], size_t sz)
{
- BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
- const size_t sz = buffer.size() - offset;
- byte* buf = buffer.data() + offset;
-
- BOTAN_ASSERT(sz % BS() == 0, "Input length is an even number of blocks");
- encrypt(buf, sz / BS());
+ BOTAN_ASSERT(sz % 16 == 0, "Invalid OCB input size");
+ encrypt(buf, sz / 16);
+ return sz;
}
void OCB_Encryption::finish(secure_vector<byte>& buffer, size_t offset)
@@ -273,14 +262,14 @@ void OCB_Encryption::finish(secure_vector<byte>& buffer, size_t offset)
if(sz)
{
- const size_t final_full_blocks = sz / BS();
- const size_t remainder_bytes = sz - (final_full_blocks * BS());
+ const size_t final_full_blocks = sz / 16;
+ const size_t remainder_bytes = sz - (final_full_blocks * 16);
encrypt(buf, final_full_blocks);
if(remainder_bytes)
{
- BOTAN_ASSERT(remainder_bytes < BS(), "Only a partial block left");
+ BOTAN_ASSERT(remainder_bytes < 16, "Only a partial block left");
byte* remainder = &buf[sz - remainder_bytes];
xor_buf(m_checksum.data(), remainder, remainder_bytes);
@@ -288,13 +277,13 @@ void OCB_Encryption::finish(secure_vector<byte>& buffer, size_t offset)
m_offset ^= m_L->star(); // Offset_*
- secure_vector<byte> zeros(BS());
+ secure_vector<byte> zeros(16);
m_cipher->encrypt(m_offset, zeros);
xor_buf(remainder, zeros.data(), remainder_bytes);
}
}
- secure_vector<byte> checksum(BS());
+ secure_vector<byte> checksum(16);
// fold checksum
for(size_t i = 0; i != m_checksum.size(); ++i)
@@ -320,14 +309,14 @@ void OCB_Decryption::decrypt(byte buffer[], size_t blocks)
{
const size_t par_bytes = m_cipher->parallel_bytes();
- BOTAN_ASSERT(par_bytes % BS() == 0, "Cipher is parallel in full blocks");
+ BOTAN_ASSERT(par_bytes % 16 == 0, "Cipher is parallel in full blocks");
- const size_t par_blocks = par_bytes / BS();
+ const size_t par_blocks = par_bytes / 16;
while(blocks)
{
const size_t proc_blocks = std::min(blocks, par_blocks);
- const size_t proc_bytes = proc_blocks * BS();
+ const size_t proc_bytes = proc_blocks * 16;
const auto& offsets = m_L->compute_offsets(m_offset, m_block_index, proc_blocks);
@@ -343,15 +332,11 @@ void OCB_Decryption::decrypt(byte buffer[], size_t blocks)
}
}
-void OCB_Decryption::update(secure_vector<byte>& buffer, size_t offset)
+size_t OCB_Decryption::process(uint8_t buf[], size_t sz)
{
- BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
- const size_t sz = buffer.size() - offset;
- byte* buf = buffer.data() + offset;
-
- BOTAN_ASSERT(sz % BS() == 0, "Input length is an even number of blocks");
-
- decrypt(buf, sz / BS());
+ BOTAN_ASSERT(sz % 16 == 0, "Invalid OCB input size");
+ decrypt(buf, sz / 16);
+ return sz;
}
void OCB_Decryption::finish(secure_vector<byte>& buffer, size_t offset)
@@ -366,20 +351,20 @@ void OCB_Decryption::finish(secure_vector<byte>& buffer, size_t offset)
if(remaining)
{
- const size_t final_full_blocks = remaining / BS();
- const size_t final_bytes = remaining - (final_full_blocks * BS());
+ const size_t final_full_blocks = remaining / 16;
+ const size_t final_bytes = remaining - (final_full_blocks * 16);
decrypt(buf, final_full_blocks);
if(final_bytes)
{
- BOTAN_ASSERT(final_bytes < BS(), "Only a partial block left");
+ BOTAN_ASSERT(final_bytes < 16, "Only a partial block left");
byte* remainder = &buf[remaining - final_bytes];
m_offset ^= m_L->star(); // Offset_*
- secure_vector<byte> pad(BS());
+ secure_vector<byte> pad(16);
m_cipher->encrypt(m_offset, pad); // P_*
xor_buf(remainder, pad.data(), final_bytes);
@@ -389,7 +374,7 @@ void OCB_Decryption::finish(secure_vector<byte>& buffer, size_t offset)
}
}
- secure_vector<byte> checksum(BS());
+ secure_vector<byte> checksum(16);
// fold checksum
for(size_t i = 0; i != m_checksum.size(); ++i)
diff --git a/src/lib/modes/aead/ocb/ocb.h b/src/lib/modes/aead/ocb/ocb.h
index 92edce970..4daa7a81b 100644
--- a/src/lib/modes/aead/ocb/ocb.h
+++ b/src/lib/modes/aead/ocb/ocb.h
@@ -49,20 +49,17 @@ class BOTAN_DLL OCB_Mode : public AEAD_Mode
*/
OCB_Mode(BlockCipher* cipher, size_t tag_size);
- size_t BS() const { return m_BS; }
-
// fixme make these private
std::unique_ptr<BlockCipher> m_cipher;
std::unique_ptr<L_computer> m_L;
- size_t m_BS;
size_t m_block_index = 0;
secure_vector<byte> m_checksum;
secure_vector<byte> m_offset;
secure_vector<byte> m_ad_hash;
private:
- secure_vector<byte> start_raw(const byte nonce[], size_t nonce_len) override;
+ void start_msg(const byte nonce[], size_t nonce_len) override;
void key_schedule(const byte key[], size_t length) override;
@@ -88,7 +85,7 @@ class BOTAN_DLL OCB_Encryption final : public OCB_Mode
size_t minimum_final_size() const override { return 0; }
- void update(secure_vector<byte>& blocks, size_t offset = 0) override;
+ size_t process(uint8_t buf[], size_t size) override;
void finish(secure_vector<byte>& final_block, size_t offset = 0) override;
private:
@@ -113,7 +110,7 @@ class BOTAN_DLL OCB_Decryption final : public OCB_Mode
size_t minimum_final_size() const override { return tag_size(); }
- void update(secure_vector<byte>& blocks, size_t offset = 0) override;
+ size_t process(uint8_t buf[], size_t size) override;
void finish(secure_vector<byte>& final_block, size_t offset = 0) override;
private: