aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorlloyd <[email protected]>2013-03-27 15:16:15 +0000
committerlloyd <[email protected]>2013-03-27 15:16:15 +0000
commit35ac296082030fffde867cbac768815efe271522 (patch)
tree3af739d0df6c6f3700fd382ec678ba7ced99a8e1
parent7703ed769010f9ef4d037be1e9d1183a854f8348 (diff)
Convert OCB to new AEAD interface
-rw-r--r--checks/ocb.cpp58
-rw-r--r--src/aead/gcm/gcm.cpp1
-rw-r--r--src/aead/ocb/info.txt (renamed from src/filters/aead_filt/ocb/info.txt)2
-rw-r--r--src/aead/ocb/ocb.cpp (renamed from src/filters/aead_filt/ocb/ocb.cpp)219
-rw-r--r--src/aead/ocb/ocb.h (renamed from src/filters/aead_filt/ocb/ocb.h)57
5 files changed, 174 insertions, 163 deletions
diff --git a/checks/ocb.cpp b/checks/ocb.cpp
index 78be74bef..c5d38c65b 100644
--- a/checks/ocb.cpp
+++ b/checks/ocb.cpp
@@ -1,7 +1,6 @@
#include "validate.h"
-#include <botan/pipe.h>
#include <botan/ocb.h>
#include <botan/hex.h>
#include <botan/sha2_32.h>
@@ -19,31 +18,35 @@ std::vector<byte> ocb_encrypt(const SymmetricKey& key,
{
//std::unique_ptr<AEAD_Mode> ocb = get_aead("AES-128/OCB", ENCRYPTION);
- OCB_Encryption* ocb = new OCB_Encryption(new AES_128);
+ OCB_Encryption ocb(new AES_128);
- ocb->set_key(key);
- ocb->set_nonce(&nonce[0], nonce.size());
- ocb->set_associated_data(ad, ad_len);
+ ocb.set_key(key);
+ ocb.set_associated_data(ad, ad_len);
- Pipe pipe(ocb);
- pipe.process_msg(pt, pt_len);
- return unlock(pipe.read_all());
+ ocb.start(&nonce[0], nonce.size());
+
+ secure_vector<byte> buf(pt, pt+pt_len);
+ ocb.finish(buf);
+
+ return unlock(buf);
}
std::vector<byte> ocb_decrypt(const SymmetricKey& key,
const std::vector<byte>& nonce,
- const byte pt[], size_t pt_len,
+ const byte ct[], size_t ct_len,
const byte ad[], size_t ad_len)
{
- OCB_Decryption* ocb = new OCB_Decryption(new AES_128);
+ OCB_Decryption ocb(new AES_128);
+
+ ocb.set_key(key);
+ ocb.set_associated_data(ad, ad_len);
- ocb->set_key(key);
- ocb->set_nonce(&nonce[0], nonce.size());
- ocb->set_associated_data(ad, ad_len);
+ ocb.start(&nonce[0], nonce.size());
- Pipe pipe(ocb);
- pipe.process_msg(pt, pt_len);
- return unlock(pipe.read_all());
+ secure_vector<byte> buf(ct, ct+ct_len);
+ ocb.finish(buf);
+
+ return unlock(buf);
}
template<typename Alloc, typename Alloc2>
@@ -65,26 +68,27 @@ std::vector<byte> ocb_decrypt(const SymmetricKey& key,
}
std::vector<byte> ocb_encrypt(OCB_Encryption& ocb,
- Pipe& pipe,
const std::vector<byte>& nonce,
const std::vector<byte>& pt,
const std::vector<byte>& ad)
{
- ocb.set_nonce(&nonce[0], nonce.size());
ocb.set_associated_data(&ad[0], ad.size());
- pipe.process_msg(pt);
- return unlock(pipe.read_all(Pipe::LAST_MESSAGE));
+ ocb.start(&nonce[0], nonce.size());
+
+ secure_vector<byte> buf(pt.begin(), pt.end());
+ ocb.finish(buf);
+
+ return unlock(buf);
}
void test_ocb_long_filters()
{
SymmetricKey key("00000000000000000000000000000000");
- OCB_Encryption* ocb = new OCB_Encryption(new AES_128);
+ OCB_Encryption ocb(new AES_128);
- ocb->set_key(key);
- Pipe pipe(ocb);
+ ocb.set_key(key);
const std::vector<byte> empty;
std::vector<byte> N(12);
@@ -95,9 +99,9 @@ void test_ocb_long_filters()
const std::vector<byte> S(i);
N[11] = i;
- const std::vector<byte> C1 = ocb_encrypt(*ocb, pipe, N, S, S);
- const std::vector<byte> C2 = ocb_encrypt(*ocb, pipe, N, S, empty);
- const std::vector<byte> C3 = ocb_encrypt(*ocb, pipe, N, empty, S);
+ const std::vector<byte> C1 = ocb_encrypt(ocb, N, S, S);
+ const std::vector<byte> C2 = ocb_encrypt(ocb, N, S, empty);
+ const std::vector<byte> C3 = ocb_encrypt(ocb, N, empty, S);
//std::cout << "C_" << i << " = " << hex_encode(C1) << " " << hex_encode(C2) << " " << hex_encode(C3) << "\n";
@@ -120,7 +124,7 @@ void test_ocb_long_filters()
//std::cout << "SHA-256(C) = " << C_hash << "\n";
N[11] = 0;
- const std::vector<byte> cipher = ocb_encrypt(*ocb, pipe, N, empty, C);
+ const std::vector<byte> cipher = ocb_encrypt(ocb, N, empty, C);
const std::string expected = "B2B41CBF9B05037DA7F16C24A35C1C94";
diff --git a/src/aead/gcm/gcm.cpp b/src/aead/gcm/gcm.cpp
index 0ff73b034..628dcc270 100644
--- a/src/aead/gcm/gcm.cpp
+++ b/src/aead/gcm/gcm.cpp
@@ -225,5 +225,4 @@ void GCM_Decryption::finish(secure_vector<byte>& buffer)
throw Integrity_Failure("GCM tag check failed");
}
-
}
diff --git a/src/filters/aead_filt/ocb/info.txt b/src/aead/ocb/info.txt
index 0ee41681d..8d6a93ed9 100644
--- a/src/filters/aead_filt/ocb/info.txt
+++ b/src/aead/ocb/info.txt
@@ -1,4 +1,4 @@
-define OCB
+define AEAD_OCB
<requires>
block
diff --git a/src/filters/aead_filt/ocb/ocb.cpp b/src/aead/ocb/ocb.cpp
index eb10b6e9f..5bd42766f 100644
--- a/src/filters/aead_filt/ocb/ocb.cpp
+++ b/src/aead/ocb/ocb.cpp
@@ -59,13 +59,10 @@ class Nonce_State
secure_vector<byte> update_nonce(const byte nonce[],
size_t nonce_len);
-
- bool fresh_nonce() { bool b = false; std::swap(b, m_fresh); return b; }
private:
const BlockCipher& m_cipher;
secure_vector<byte> m_last_nonce;
secure_vector<byte> m_stretch;
- bool m_fresh = false;
};
secure_vector<byte>
@@ -109,7 +106,6 @@ Nonce_State::update_nonce(const byte nonce[], size_t nonce_len)
offset[i] |= (m_stretch[i+shift_bytes+1] >> (8-shift_bits));
}
- m_fresh = true;
return offset;
}
@@ -163,16 +159,16 @@ secure_vector<byte> ocb_hash(const L_computer& L,
}
-OCB_Mode::OCB_Mode(BlockCipher* cipher, size_t tag_size, bool decrypting) :
- Buffered_Filter(cipher->parallel_bytes(), decrypting ? tag_size : 0),
- m_cipher(cipher), m_tag_size(tag_size),
+OCB_Mode::OCB_Mode(BlockCipher* cipher, size_t tag_size) :
+ m_cipher(cipher),
+ m_tag_size(tag_size),
m_ad_hash(BS), m_offset(BS), m_checksum(BS)
{
if(m_cipher->block_size() != BS)
throw std::invalid_argument("OCB requires a 128 bit cipher so cannot be used with " +
m_cipher->name());
- if(m_tag_size != 16) // 64, 96 bits also supported
+ if(m_tag_size != 16) // fixme: 64, 96 bits also supported
throw std::invalid_argument("OCB cannot produce a " + std::to_string(m_tag_size) +
" byte tag");
@@ -180,53 +176,65 @@ OCB_Mode::OCB_Mode(BlockCipher* cipher, size_t tag_size, bool decrypting) :
OCB_Mode::~OCB_Mode() { /* for unique_ptr destructor */ }
-std::string OCB_Mode::name() const
+void OCB_Mode::clear()
{
- return m_cipher->name() + "/OCB"; // include tag size
+ m_cipher.reset();
+ m_L.reset();
+ zeroise(m_ad_hash);
+ zeroise(m_offset);
+ zeroise(m_checksum);
}
-void OCB_Mode::set_key(const SymmetricKey& key)
+bool OCB_Mode::valid_nonce_length(size_t length) const
{
- m_cipher->set_key(key);
- m_L.reset(new L_computer(*m_cipher));
- m_nonce_state.reset(new Nonce_State(*m_cipher));
+ return (length > 0 && length < 16);
}
-void OCB_Mode::set_nonce(const byte nonce[], size_t nonce_len)
+std::string OCB_Mode::name() const
{
- if(!valid_iv_length(nonce_len))
- throw Invalid_IV_Length(name(), nonce_len);
+ return m_cipher->name() + "/OCB"; // include tag size
+ }
- BOTAN_ASSERT(m_nonce_state, "A key was set");
+size_t OCB_Mode::update_granularity() const
+ {
+ return 8 * m_cipher->parallel_bytes();
+ }
- m_offset = m_nonce_state->update_nonce(nonce, nonce_len);
+Key_Length_Specification OCB_Mode::key_spec() const
+ {
+ return m_cipher->key_spec();
}
-void OCB_Mode::start_msg()
+void OCB_Mode::key_schedule(const byte key[], size_t length)
{
- BOTAN_ASSERT(m_nonce_state->fresh_nonce(), "Nonce state is fresh");
+ m_cipher->set_key(key, length);
+ m_L.reset(new L_computer(*m_cipher));
+ m_nonce_state.reset(new Nonce_State(*m_cipher));
}
void OCB_Mode::set_associated_data(const byte ad[], size_t ad_len)
{
+ BOTAN_ASSERT(m_L, "A key was set");
m_ad_hash = ocb_hash(*m_L, *m_cipher, &ad[0], ad_len);
}
-void OCB_Mode::write(const byte input[], size_t length)
+secure_vector<byte> OCB_Mode::start(const byte nonce[], size_t nonce_len)
{
- Buffered_Filter::write(input, length);
- }
+ if(!valid_nonce_length(nonce_len))
+ throw Invalid_IV_Length(name(), nonce_len);
-void OCB_Mode::end_msg()
- {
- Buffered_Filter::end_msg();
+ BOTAN_ASSERT(m_nonce_state, "A key was set");
+
+ m_offset = m_nonce_state->update_nonce(nonce, nonce_len);
+ zeroise(m_checksum);
+ m_block_index = 0;
+
+ return secure_vector<byte>();
}
-void OCB_Encryption::buffered_block(const byte input[], size_t input_length)
+void OCB_Encryption::encrypt(byte buffer[], size_t blocks)
{
- BOTAN_ASSERT(input_length % BS == 0, "Input length is an even number of blocks");
-
- const size_t blocks = input_length / BS;
+ const L_computer& L = *m_L; // convenient name
const size_t par_bytes = m_cipher->parallel_bytes();
@@ -234,9 +242,6 @@ void OCB_Encryption::buffered_block(const byte input[], size_t input_length)
const size_t par_blocks = par_bytes / BS;
- const L_computer& L = *m_L; // convenient name
-
- secure_vector<byte> ctext_buf(par_bytes);
secure_vector<byte> csum_accum(par_bytes);
secure_vector<byte> offsets(par_bytes);
@@ -244,27 +249,25 @@ void OCB_Encryption::buffered_block(const byte input[], size_t input_length)
while(blocks_left)
{
- const size_t to_proc = std::min(blocks_left, par_blocks);
- const size_t proc_bytes = to_proc * BS;
+ const size_t proc_blocks = std::min(blocks_left, par_blocks);
+ const size_t proc_bytes = proc_blocks * BS;
- xor_buf(&csum_accum[0], &input[0], proc_bytes);
-
- for(size_t i = 0; i != to_proc; ++i)
- {
+ for(size_t i = 0; i != proc_blocks; ++i)
+ { // could be done in parallel
m_offset ^= L(ctz(++m_block_index));
copy_mem(&offsets[BS*i], &m_offset[0], BS);
}
- copy_mem(&ctext_buf[0], &input[0], proc_bytes);
+ xor_buf(&csum_accum[0], &buffer[0], proc_bytes);
- ctext_buf ^= offsets;
- m_cipher->encrypt(ctext_buf);
- ctext_buf ^= offsets;
+ xor_buf(&buffer[0], &offsets[0], proc_bytes);
- send(ctext_buf, proc_bytes);
+ m_cipher->encrypt_n(&buffer[0], &buffer[0], proc_blocks);
- input += proc_bytes;
- blocks_left -= to_proc;
+ xor_buf(&buffer[0], &offsets[0], proc_bytes);
+
+ buffer += proc_bytes;
+ blocks_left -= proc_blocks;
}
// fold into checksum
@@ -272,31 +275,36 @@ void OCB_Encryption::buffered_block(const byte input[], size_t input_length)
m_checksum[i % BS] ^= csum_accum[i];
}
-void OCB_Encryption::buffered_final(const byte input[], size_t input_length)
+void OCB_Encryption::update(secure_vector<byte>& buffer)
{
- if(input_length >= BS)
- {
- const size_t final_blocks = input_length / BS;
- const size_t final_bytes = final_blocks * BS;
- buffered_block(input, final_bytes);
- input += final_bytes;
- input_length -= final_bytes;
- }
+ BOTAN_ASSERT(buffer.size() % BS == 0, "Input length is an even number of blocks");
- if(input_length)
+ encrypt(&buffer[0], buffer.size() / BS);
+ }
+
+void OCB_Encryption::finish(secure_vector<byte>& buffer)
+ {
+ if(!buffer.empty())
{
- BOTAN_ASSERT(input_length < BS, "Only a partial block left");
+ const size_t final_full_blocks = buffer.size() / BS;
+ const size_t remainder_bytes = buffer.size() - (final_full_blocks * BS);
- xor_buf(&m_checksum[0], &input[0], input_length);
- m_checksum[input_length] ^= 0x80;
+ encrypt(&buffer[0], final_full_blocks);
- m_offset ^= m_L->star(); // Offset_*
+ if(remainder_bytes)
+ {
+ BOTAN_ASSERT(remainder_bytes < BS, "Only a partial block left");
+ byte* remainder = &buffer[buffer.size() - remainder_bytes];
- secure_vector<byte> buf(BS);
- m_cipher->encrypt(m_offset, buf);
- xor_buf(&buf[0], &input[0], input_length);
+ xor_buf(&m_checksum[0], &remainder[0], remainder_bytes);
+ m_checksum[remainder_bytes] ^= 0x80;
- send(buf, input_length); // final ciphertext
+ m_offset ^= m_L->star(); // Offset_*
+
+ secure_vector<byte> buf(BS);
+ m_cipher->encrypt(m_offset, buf);
+ xor_buf(&remainder[0], &buf[0], remainder_bytes);
+ }
}
// now compute the tag
@@ -308,18 +316,16 @@ void OCB_Encryption::buffered_final(const byte input[], size_t input_length)
mac ^= m_ad_hash;
- send(mac);
+ buffer += mac;
zeroise(m_checksum);
zeroise(m_offset);
m_block_index = 0;
}
-void OCB_Decryption::buffered_block(const byte input[], size_t input_length)
+void OCB_Decryption::decrypt(byte buffer[], size_t blocks)
{
- BOTAN_ASSERT(input_length % BS == 0, "Input length is an even number of blocks");
-
- const size_t blocks = input_length / BS;
+ const L_computer& L = *m_L; // convenient name
const size_t par_bytes = m_cipher->parallel_bytes();
@@ -327,9 +333,6 @@ void OCB_Decryption::buffered_block(const byte input[], size_t input_length)
const size_t par_blocks = par_bytes / BS;
- const L_computer& L = *m_L; // convenient name
-
- secure_vector<byte> ptext_buf(par_bytes);
secure_vector<byte> csum_accum(par_bytes);
secure_vector<byte> offsets(par_bytes);
@@ -337,27 +340,25 @@ void OCB_Decryption::buffered_block(const byte input[], size_t input_length)
while(blocks_left)
{
- const size_t to_proc = std::min(blocks_left, par_blocks);
- const size_t proc_bytes = to_proc * BS;
+ const size_t proc_blocks = std::min(blocks_left, par_blocks);
+ const size_t proc_bytes = proc_blocks * BS;
- for(size_t i = 0; i != to_proc; ++i)
- {
+ for(size_t i = 0; i != proc_blocks; ++i)
+ { // could be done in parallel
m_offset ^= L(ctz(++m_block_index));
copy_mem(&offsets[BS*i], &m_offset[0], BS);
}
- copy_mem(&ptext_buf[0], &input[0], proc_bytes);
+ xor_buf(&buffer[0], &offsets[0], proc_bytes);
- ptext_buf ^= offsets;
- m_cipher->decrypt(ptext_buf);
- ptext_buf ^= offsets;
+ m_cipher->decrypt_n(&buffer[0], &buffer[0], proc_blocks);
- xor_buf(&csum_accum[0], &ptext_buf[0], proc_bytes);
+ xor_buf(&buffer[0], &offsets[0], proc_bytes);
- send(ptext_buf, proc_bytes);
+ xor_buf(&csum_accum[0], &buffer[0], proc_bytes);
- input += proc_bytes;
- blocks_left -= to_proc;
+ buffer += proc_bytes;
+ blocks_left -= proc_blocks;
}
// fold into checksum
@@ -365,40 +366,44 @@ void OCB_Decryption::buffered_block(const byte input[], size_t input_length)
m_checksum[i % BS] ^= csum_accum[i];
}
-void OCB_Decryption::buffered_final(const byte input[], size_t input_length)
+void OCB_Decryption::update(secure_vector<byte>& buffer)
{
- BOTAN_ASSERT(input_length >= m_tag_size, "We have the tag");
+ BOTAN_ASSERT(buffer.size() % BS == 0, "Input length is an even number of blocks");
- const byte* included_tag = &input[input_length - m_tag_size];
- input_length -= m_tag_size;
+ decrypt(&buffer[0], buffer.size() / BS);
+ }
- if(input_length >= BS)
- {
- const size_t final_blocks = input_length / BS;
- const size_t final_bytes = final_blocks * BS;
- buffered_block(input, final_bytes);
- input += final_bytes;
- input_length -= final_bytes;
- }
+void OCB_Decryption::finish(secure_vector<byte>& buffer)
+ {
+ BOTAN_ASSERT(buffer.size() >= tag_size(), "We have the tag");
- if(input_length)
+ if(const size_t remaining_ctext = buffer.size() - tag_size())
{
- BOTAN_ASSERT(input_length < BS, "Only a partial block left");
+ const size_t final_full_blocks = remaining_ctext / BS;
+ const size_t remainder_bytes = remaining_ctext - (final_full_blocks * BS);
+
+ decrypt(&buffer[0], final_full_blocks);
+
+ if(remainder_bytes)
+ {
+ BOTAN_ASSERT(remainder_bytes < BS, "Only a partial block left");
- m_offset ^= m_L->star(); // Offset_*
+ byte* remainder = &buffer[buffer.size() - remainder_bytes];
- secure_vector<byte> buf(BS);
- m_cipher->encrypt(m_offset, buf); // P_*
+ m_offset ^= m_L->star(); // Offset_*
- xor_buf(&buf[0], &input[0], input_length);
+ secure_vector<byte> pad(BS);
+ m_cipher->encrypt(m_offset, pad); // P_*
- xor_buf(&m_checksum[0], &buf[0], input_length);
- m_checksum[input_length] ^= 0x80;
+ xor_buf(&remainder[0], &pad[0], remainder_bytes);
- send(buf, input_length); // final plaintext
+ xor_buf(&m_checksum[0], &remainder[0], remainder_bytes);
+ m_checksum[remainder_bytes] ^= 0x80;
+ }
}
- // now compute the tag
+ const byte* included_tag = &buffer[buffer.size() - tag_size()];
+
secure_vector<byte> mac = m_offset;
mac ^= m_checksum;
mac ^= m_L->dollar();
diff --git a/src/filters/aead_filt/ocb/ocb.h b/src/aead/ocb/ocb.h
index 0a1cbcaff..9d10c2656 100644
--- a/src/filters/aead_filt/ocb/ocb.h
+++ b/src/aead/ocb/ocb.h
@@ -8,7 +8,7 @@
#ifndef BOTAN_OCB_H__
#define BOTAN_OCB_H__
-#include <botan/aead_filt.h>
+#include <botan/aead.h>
#include <botan/block_cipher.h>
#include <botan/buf_filt.h>
#include <memory>
@@ -27,36 +27,36 @@ class Nonce_State;
* @see Free Licenses http://www.cs.ucdavis.edu/~rogaway/ocb/license.htm
* @see OCB home page http://www.cs.ucdavis.edu/~rogaway/ocb
*/
-class BOTAN_DLL OCB_Mode : public AEAD_Filter,
- private Buffered_Filter
+class BOTAN_DLL OCB_Mode : public AEAD_Mode
{
public:
- void set_key(const SymmetricKey& key) override;
-
- void set_nonce(const byte nonce[], size_t nonce_len) override;
+ secure_vector<byte> start(const byte nonce[], size_t nonce_len) override;
void set_associated_data(const byte ad[], size_t ad_len) override;
- Key_Length_Specification key_spec() const override { return m_cipher->key_spec(); }
-
std::string name() const override;
- bool valid_iv_length(size_t length) const override
- {
- return (length > 0 && length < 16);
- }
+ size_t update_granularity() const;
- ~OCB_Mode();
+ Key_Length_Specification key_spec() const override;
+
+ bool valid_nonce_length(size_t) const override;
+ void clear();
+
+ ~OCB_Mode();
protected:
+ static const size_t BS = 16; // intrinsic to OCB definition
+
/**
* @param cipher the 128-bit block cipher to use
* @param tag_size is how big the auth tag will be
- * @param decrypting true if decrypting
*/
- OCB_Mode(BlockCipher* cipher, size_t tag_size, bool decrypting);
+ OCB_Mode(BlockCipher* cipher, size_t tag_size);
- static const size_t BS = 16; // intrinsic to OCB definition
+ void key_schedule(const byte key[], size_t length) override;
+
+ size_t tag_size() const { return m_tag_size; }
// fixme make these private
std::unique_ptr<BlockCipher> m_cipher;
@@ -68,12 +68,7 @@ class BOTAN_DLL OCB_Mode : public AEAD_Filter,
secure_vector<byte> m_ad_hash;
secure_vector<byte> m_offset;
secure_vector<byte> m_checksum;
-
private:
- void write(const byte input[], size_t input_length) override;
- void start_msg() override;
- void end_msg() override;
-
std::unique_ptr<Nonce_State> m_nonce_state;
};
@@ -85,11 +80,15 @@ class BOTAN_DLL OCB_Encryption : public OCB_Mode
* @param tag_size is how big the auth tag will be
*/
OCB_Encryption(BlockCipher* cipher, size_t tag_size = 16) :
- OCB_Mode(cipher, tag_size, false) {}
+ OCB_Mode(cipher, tag_size) {}
+ size_t minimum_final_size() const override { return 0; }
+
+ void update(secure_vector<byte>& blocks) override;
+
+ void finish(secure_vector<byte>& final_block) override;
private:
- void buffered_block(const byte input[], size_t input_length) override;
- void buffered_final(const byte input[], size_t input_length) override;
+ void encrypt(byte input[], size_t blocks);
};
class BOTAN_DLL OCB_Decryption : public OCB_Mode
@@ -100,11 +99,15 @@ class BOTAN_DLL OCB_Decryption : public OCB_Mode
* @param tag_size is how big the auth tag will be
*/
OCB_Decryption(BlockCipher* cipher, size_t tag_size = 16) :
- OCB_Mode(cipher, tag_size, true) {}
+ OCB_Mode(cipher, tag_size) {}
+
+ size_t minimum_final_size() const override { return tag_size(); }
+
+ void update(secure_vector<byte>& blocks) override;
+ void finish(secure_vector<byte>& final_block) override;
private:
- void buffered_block(const byte input[], size_t input_length) override;
- void buffered_final(const byte input[], size_t input_length) override;
+ void decrypt(byte input[], size_t blocks);
};
}