diff options
author | lloyd <[email protected]> | 2013-03-27 15:16:15 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2013-03-27 15:16:15 +0000 |
commit | 35ac296082030fffde867cbac768815efe271522 (patch) | |
tree | 3af739d0df6c6f3700fd382ec678ba7ced99a8e1 | |
parent | 7703ed769010f9ef4d037be1e9d1183a854f8348 (diff) |
Convert OCB to new AEAD interface
-rw-r--r-- | checks/ocb.cpp | 58 | ||||
-rw-r--r-- | src/aead/gcm/gcm.cpp | 1 | ||||
-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); }; } |