diff options
author | lloyd <[email protected]> | 2013-03-27 16:10:55 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2013-03-27 16:10:55 +0000 |
commit | e7d24d7884025c2051450a9c9d9ce0f944a8fa4a (patch) | |
tree | 1fb4af6e8541c7ee8cef757799fcb73eb56ed339 | |
parent | 35ac296082030fffde867cbac768815efe271522 (diff) |
Add an AEAD_Filter that wraps an AEAD_Mode, plus various bug fixes.
-rw-r--r-- | src/aead/aead.h | 6 | ||||
-rw-r--r-- | src/aead/eax/eax.cpp | 14 | ||||
-rw-r--r-- | src/aead/gcm/gcm.cpp | 18 | ||||
-rw-r--r-- | src/aead/ocb/ocb.cpp | 35 | ||||
-rw-r--r-- | src/engine/core_engine/core_modes.cpp | 38 | ||||
-rw-r--r-- | src/filters/aead_filt/aead_filt.cpp | 92 | ||||
-rw-r--r-- | src/filters/aead_filt/aead_filt.h | 52 | ||||
-rw-r--r-- | src/filters/aead_filt/info.txt | 6 |
8 files changed, 210 insertions, 51 deletions
diff --git a/src/aead/aead.h b/src/aead/aead.h index af6f0e76a..736de85e1 100644 --- a/src/aead/aead.h +++ b/src/aead/aead.h @@ -57,6 +57,12 @@ class AEAD_Mode : public SymmetricAlgorithm */ virtual secure_vector<byte> start(const byte nonce[], size_t nonce_len) = 0; + template<typename Alloc> + secure_vector<byte> start_vec(const std::vector<byte, Alloc>& nonce) + { + return start(&nonce[0], nonce.size()); + } + /** * Update (encrypt or decrypt) some data. Input must be in size * update_granularity() byte blocks. diff --git a/src/aead/eax/eax.cpp b/src/aead/eax/eax.cpp index 8a7287062..fa0496f42 100644 --- a/src/aead/eax/eax.cpp +++ b/src/aead/eax/eax.cpp @@ -119,7 +119,7 @@ void EAX_Encryption::finish(secure_vector<byte>& buffer) xor_buf(data_mac, m_nonce_mac, data_mac.size()); xor_buf(data_mac, m_ad_mac, data_mac.size()); - buffer += data_mac; + buffer += std::make_pair(&data_mac[0], tag_size()); } void EAX_Decryption::update(secure_vector<byte>& buffer) @@ -133,15 +133,15 @@ void EAX_Decryption::finish(secure_vector<byte>& buffer) BOTAN_ASSERT(buffer.size() >= tag_size(), "Have the tag as part of final input"); - const size_t input_length = buffer.size() - tag_size(); + const size_t remaining = buffer.size() - tag_size(); - if(input_length) // handle any remaining input + if(remaining) // handle any remaining input { - m_cmac->update(&buffer[0], buffer.size()); - m_ctr->cipher(&buffer[0], &buffer[0], buffer.size()); + m_cmac->update(&buffer[0], remaining); + m_ctr->cipher(&buffer[0], &buffer[0], remaining); } - const byte* included_tag = &buffer[input_length]; + const byte* included_tag = &buffer[remaining]; secure_vector<byte> mac = m_cmac->final(); mac ^= m_nonce_mac; @@ -149,6 +149,8 @@ void EAX_Decryption::finish(secure_vector<byte>& buffer) if(!same_mem(&mac[0], included_tag, tag_size())) throw Integrity_Failure("EAX tag check failed"); + + buffer.resize(remaining); } } diff --git a/src/aead/gcm/gcm.cpp b/src/aead/gcm/gcm.cpp index 628dcc270..a067d162e 100644 --- a/src/aead/gcm/gcm.cpp +++ b/src/aead/gcm/gcm.cpp @@ -27,6 +27,8 @@ gcm_multiply(const secure_vector<byte>& x, u64bit Z[2] = { 0, 0 }; + // Both CLMUL and SSE2 versions would be useful + for(size_t i = 0; i != 2; ++i) { u64bit X = load_be<u64bit>(&x[0], i); @@ -192,7 +194,7 @@ void GCM_Encryption::finish(secure_vector<byte>& buffer) m_mac ^= m_enc_y0; - buffer += m_mac; + buffer += std::make_pair(&m_mac[0], tag_size()); } void GCM_Decryption::update(secure_vector<byte>& buffer) @@ -207,22 +209,26 @@ void GCM_Decryption::finish(secure_vector<byte>& buffer) BOTAN_ASSERT(buffer.size() >= tag_size(), "Have the tag as part of final input"); + const size_t remaining = buffer.size() - tag_size(); + // handle any final input before the tag - if(size_t input_length = buffer.size() - tag_size()) + if(remaining) { - ghash_update(m_H, m_mac, &buffer[0], input_length); - m_ctr->cipher(&buffer[0], &buffer[0], input_length); - m_text_len += input_length; + ghash_update(m_H, m_mac, &buffer[0], remaining); + m_ctr->cipher(&buffer[0], &buffer[0], remaining); + m_text_len += remaining; } ghash_finalize(m_H, m_mac, m_ad_len, m_text_len); m_mac ^= m_enc_y0; - const byte* included_tag = &buffer[buffer.size() - tag_size()]; + const byte* included_tag = &buffer[remaining]; if(!same_mem(&m_mac[0], included_tag, tag_size())) throw Integrity_Failure("GCM tag check failed"); + + buffer.resize(remaining); } } diff --git a/src/aead/ocb/ocb.cpp b/src/aead/ocb/ocb.cpp index 5bd42766f..50b33960f 100644 --- a/src/aead/ocb/ocb.cpp +++ b/src/aead/ocb/ocb.cpp @@ -11,9 +11,6 @@ #include <botan/internal/bit_ops.h> #include <algorithm> -#include <botan/hex.h> -#include <iostream> - namespace Botan { // Has to be in Botan namespace so unique_ptr can reference it @@ -377,33 +374,34 @@ void OCB_Decryption::finish(secure_vector<byte>& buffer) { BOTAN_ASSERT(buffer.size() >= tag_size(), "We have the tag"); - if(const size_t remaining_ctext = buffer.size() - tag_size()) + const size_t remaining = buffer.size() - tag_size(); + + if(remaining) { - const size_t final_full_blocks = remaining_ctext / BS; - const size_t remainder_bytes = remaining_ctext - (final_full_blocks * BS); + const size_t final_full_blocks = remaining / BS; + const size_t final_bytes = remaining - (final_full_blocks * BS); decrypt(&buffer[0], final_full_blocks); - if(remainder_bytes) + if(final_bytes) { - BOTAN_ASSERT(remainder_bytes < BS, "Only a partial block left"); + BOTAN_ASSERT(final_bytes < BS, "Only a partial block left"); - byte* remainder = &buffer[buffer.size() - remainder_bytes]; + byte* remainder = &buffer[remaining - final_bytes]; m_offset ^= m_L->star(); // Offset_* secure_vector<byte> pad(BS); m_cipher->encrypt(m_offset, pad); // P_* - xor_buf(&remainder[0], &pad[0], remainder_bytes); + xor_buf(&remainder[0], &pad[0], final_bytes); - xor_buf(&m_checksum[0], &remainder[0], remainder_bytes); - m_checksum[remainder_bytes] ^= 0x80; + xor_buf(&m_checksum[0], &remainder[0], final_bytes); + m_checksum[final_bytes] ^= 0x80; } } - const byte* included_tag = &buffer[buffer.size() - tag_size()]; - + // compute the mac secure_vector<byte> mac = m_offset; mac ^= m_checksum; mac ^= m_L->dollar(); @@ -412,12 +410,19 @@ void OCB_Decryption::finish(secure_vector<byte>& buffer) mac ^= m_ad_hash; + // reset state zeroise(m_checksum); zeroise(m_offset); m_block_index = 0; - if(!same_mem(&mac[0], included_tag, m_tag_size)) + // compare mac + const byte* included_tag = &buffer[remaining]; + + if(!same_mem(&mac[0], included_tag, tag_size())) throw Integrity_Failure("OCB tag check failed"); + + // remove tag from end of message + buffer.resize(remaining); } } diff --git a/src/engine/core_engine/core_modes.cpp b/src/engine/core_engine/core_modes.cpp index b30097eaa..588c5d7a2 100644 --- a/src/engine/core_engine/core_modes.cpp +++ b/src/engine/core_engine/core_modes.cpp @@ -36,20 +36,26 @@ #include <botan/ctr.h> #endif -#if defined(BOTAN_HAS_EAX) +#if defined(BOTAN_HAS_XTS) + #include <botan/xts.h> +#endif + +#if defined(BOTAN_HAS_AEAD_FILTER) + +#include <botan/aead_filt.h> + +#if defined(BOTAN_HAS_AEAD_EAX) #include <botan/eax.h> #endif -#if defined(BOTAN_HAS_OCB) +#if defined(BOTAN_HAS_AEAD_OCB) #include <botan/ocb.h> #endif -#if defined(BOTAN_HAS_GCM) +#if defined(BOTAN_HAS_AEAD_GCM) #include <botan/gcm.h> #endif -#if defined(BOTAN_HAS_XTS) - #include <botan/xts.h> #endif namespace Botan { @@ -135,26 +141,30 @@ Keyed_Filter* get_cipher_mode(const BlockCipher* block_cipher, #endif } -#if defined(BOTAN_HAS_OCB) +#if defined(BOTAN_HAS_AEAD_FILTER) + +#if defined(BOTAN_HAS_AEAD_OCB) if(mode == "OCB") { if(direction == ENCRYPTION) - return new OCB_Encryption(block_cipher->clone(), 16); + return new AEAD_Filter(new OCB_Encryption(block_cipher->clone(), 16)); else - return new OCB_Decryption(block_cipher->clone(), 16); + return new AEAD_Filter(new OCB_Decryption(block_cipher->clone(), 16)); } #endif -#if defined(BOTAN_HAS_GCM) +#if defined(BOTAN_HAS_AEAD_GCM) if(mode == "GCM") { if(direction == ENCRYPTION) - return new GCM_Encryption(block_cipher->clone(), 16); + return new AEAD_Filter(new GCM_Encryption(block_cipher->clone(), 16)); else - return new GCM_Decryption(block_cipher->clone(), 16); + return new AEAD_Filter(new GCM_Decryption(block_cipher->clone(), 16)); } #endif +#endif + #if defined(BOTAN_HAS_XTS) if(mode == "XTS") { @@ -189,13 +199,13 @@ Keyed_Filter* get_cipher_mode(const BlockCipher* block_cipher, } #endif -#if defined(BOTAN_HAS_EAX) +#if defined(BOTAN_HAS_AEAD_EAX) if(mode_name == "EAX") { if(direction == ENCRYPTION) - return new EAX_Encryption(block_cipher->clone(), bits); + return new AEAD_Filter(new EAX_Encryption(block_cipher->clone(), bits / 8)); else - return new EAX_Decryption(block_cipher->clone(), bits); + return new AEAD_Filter(new EAX_Decryption(block_cipher->clone(), bits / 8)); } #endif } diff --git a/src/filters/aead_filt/aead_filt.cpp b/src/filters/aead_filt/aead_filt.cpp new file mode 100644 index 000000000..a3c465a8f --- /dev/null +++ b/src/filters/aead_filt/aead_filt.cpp @@ -0,0 +1,92 @@ +/* +* Filter interface for AEAD modes +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/aead_filt.h> + +namespace Botan { + +AEAD_Filter::AEAD_Filter(AEAD_Mode* aead) : + Buffered_Filter(aead->update_granularity(), + aead->minimum_final_size()), + m_aead(aead) + { + } + +std::string AEAD_Filter::name() const + { + return m_aead->name(); + } + +void AEAD_Filter::Nonce_State::update(const InitializationVector& iv) + { + m_nonce = unlock(iv.bits_of()); + m_fresh_nonce = true; + } + +std::vector<byte> AEAD_Filter::Nonce_State::get() + { + BOTAN_ASSERT(m_fresh_nonce, "The nonce is fresh for this message"); + + m_fresh_nonce = false; + return m_nonce; + } + +void AEAD_Filter::set_associated_data(const byte ad[], size_t ad_len) + { + m_aead->set_associated_data(ad, ad_len); + } + +void AEAD_Filter::set_iv(const InitializationVector& iv) + { + m_nonce.update(iv); + } + +void AEAD_Filter::set_key(const SymmetricKey& key) + { + m_aead->set_key(key); + } + +Key_Length_Specification AEAD_Filter::key_spec() const + { + return m_aead->key_spec(); + } + +bool AEAD_Filter::valid_iv_length(size_t length) const + { + return m_aead->valid_nonce_length(length); + } + +void AEAD_Filter::write(const byte input[], size_t input_length) + { + Buffered_Filter::write(input, input_length); + } + +void AEAD_Filter::end_msg() + { + Buffered_Filter::end_msg(); + } + +void AEAD_Filter::start_msg() + { + send(m_aead->start_vec(m_nonce.get())); + } + +void AEAD_Filter::buffered_block(const byte input[], size_t input_length) + { + secure_vector<byte> buf(input, input + input_length); + m_aead->update(buf); + send(buf); + } + +void AEAD_Filter::buffered_final(const byte input[], size_t input_length) + { + secure_vector<byte> buf(input, input + input_length); + m_aead->finish(buf); + send(buf); + } + +} diff --git a/src/filters/aead_filt/aead_filt.h b/src/filters/aead_filt/aead_filt.h index 77818c17e..590a60655 100644 --- a/src/filters/aead_filt/aead_filt.h +++ b/src/filters/aead_filt/aead_filt.h @@ -1,20 +1,29 @@ /* -* Interface for AEAD modes +* Filter interface for AEAD modes * (C) 2013 Jack Lloyd * * Distributed under the terms of the Botan license */ -#ifndef BOTAN_AEAD_H__ -#define BOTAN_AEAD_H__ +#ifndef BOTAN_AEAD_FILTER_H__ +#define BOTAN_AEAD_FILTER_H__ #include <botan/key_filt.h> +#include <botan/buf_filt.h> +#include <botan/aead.h> +#include <memory> namespace Botan { -class BOTAN_DLL AEAD_Filter : public Keyed_Filter +/** +* Filter interface for AEAD modes like EAX and GCM +*/ +class BOTAN_DLL AEAD_Filter : public Keyed_Filter, + private Buffered_Filter { public: + AEAD_Filter(AEAD_Mode* aead); + /** * Set associated data that is not included in the ciphertext but * that should be authenticated. Must be called after set_key @@ -23,14 +32,39 @@ class BOTAN_DLL AEAD_Filter : public Keyed_Filter * @param ad the associated data * @param ad_len length of add in bytes */ - virtual void set_associated_data(const byte ad[], size_t ad_len) = 0; + void set_associated_data(const byte ad[], size_t ad_len); + + void set_iv(const InitializationVector& iv) override; + + void set_key(const SymmetricKey& key) override; + + Key_Length_Specification key_spec() const override; - virtual void set_nonce(const byte nonce[], size_t nonce_len) = 0; + bool valid_iv_length(size_t length) const override; - void set_iv(const InitializationVector& iv) override + std::string name() const override; + + private: + void write(const byte input[], size_t input_length) override; + void start_msg() override; + void end_msg() override; + + void buffered_block(const byte input[], size_t input_length) override; + void buffered_final(const byte input[], size_t input_length) override; + + class Nonce_State { - set_nonce(iv.begin(), iv.length()); - } + public: + void update(const InitializationVector& iv); + std::vector<byte> get(); + private: + bool m_fresh_nonce = false; + std::vector<byte> m_nonce; + }; + + Nonce_State m_nonce; + std::unique_ptr<AEAD_Mode> m_aead; + }; } diff --git a/src/filters/aead_filt/info.txt b/src/filters/aead_filt/info.txt index b43aab2f6..7df9cc619 100644 --- a/src/filters/aead_filt/info.txt +++ b/src/filters/aead_filt/info.txt @@ -1 +1,5 @@ -define AEAD +define AEAD_FILTER + +<requires> +aead +</requires> |