diff options
author | lloyd <[email protected]> | 2013-03-20 03:49:02 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2013-03-20 03:49:02 +0000 |
commit | 0dfd29109aa7ce3665aeca3cc95afbafcf2b7be2 (patch) | |
tree | 68d92921139da36a1e44ccc9d52c51fa62a59e55 /src | |
parent | 1d4b469ecd0499559a463f90bd8553ef075061d9 (diff) |
Move EAX to new AEAD_Mode interface
Diffstat (limited to 'src')
-rw-r--r-- | src/aead/aead.h | 81 | ||||
-rw-r--r-- | src/aead/eax/eax.cpp | 143 | ||||
-rw-r--r-- | src/aead/eax/eax.h | 102 | ||||
-rw-r--r-- | src/aead/eax/info.txt (renamed from src/filters/aead/eax/info.txt) | 0 | ||||
-rw-r--r-- | src/aead/info.txt | 1 | ||||
-rw-r--r-- | src/filters/aead/eax/eax.cpp | 183 | ||||
-rw-r--r-- | src/filters/aead/eax/eax.h | 130 |
7 files changed, 327 insertions, 313 deletions
diff --git a/src/aead/aead.h b/src/aead/aead.h new file mode 100644 index 000000000..af6f0e76a --- /dev/null +++ b/src/aead/aead.h @@ -0,0 +1,81 @@ +/* +* Interface for AEAD modes +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_AEAD_MODE_H__ +#define BOTAN_AEAD_MODE_H__ + +#include <botan/sym_algo.h> + +namespace Botan { + +/** +* Interface for AEAD (Authenticated Encryption with Associated Data) +* modes. These modes provide both encryption and message +* authentication, and can authenticate additional per-message data +* which is not included in the ciphertext (for instance a sequence +* number). +*/ +class AEAD_Mode : public SymmetricAlgorithm + { + public: + /** + * @return size of required blocks to update + */ + virtual size_t update_granularity() const = 0; + + /** + * @return required minimium size to finalize() - may be any + * length larger than this. + */ + virtual size_t minimum_final_size() const = 0; + + /** + * Set associated data that is not included in the ciphertext but + * that should be authenticated. Must be called after set_key + * and before end_msg. + * + * Unless reset by another call, the associated data is kept + * between messages. Thus, if the AD does not change, calling + * once (after set_key) is the optimum. + * + * @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; + + virtual bool valid_nonce_length(size_t) const = 0; + + /** + * Begin processing a message. + * + * @param nonce the per message nonce + * @param nonce_len length of nonce + */ + virtual secure_vector<byte> start(const byte nonce[], size_t nonce_len) = 0; + + /** + * Update (encrypt or decrypt) some data. Input must be in size + * update_granularity() byte blocks. + * @param blocks in/out paramter which will possibly be resized + */ + virtual void update(secure_vector<byte>& blocks) = 0; + + /** + * Complete processing of a message. For decryption, may throw an exception + * due to authentication failure. + * + * @param final_block in/out parameter which must be at least + * minimum_final_size() bytes, and will be set to any final output + */ + virtual void finish(secure_vector<byte>& final_block) = 0; + + virtual ~AEAD_Mode() {} + }; + +} + +#endif diff --git a/src/aead/eax/eax.cpp b/src/aead/eax/eax.cpp new file mode 100644 index 000000000..d03d6ec5e --- /dev/null +++ b/src/aead/eax/eax.cpp @@ -0,0 +1,143 @@ +/* +* EAX Mode Encryption +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/eax.h> +#include <botan/cmac.h> +#include <botan/ctr.h> +#include <botan/parsing.h> +#include <botan/internal/xor_buf.h> +#include <algorithm> + +namespace Botan { + +namespace { + +/* +* EAX MAC-based PRF +*/ +secure_vector<byte> eax_prf(byte tag, size_t block_size, + MessageAuthenticationCode& mac, + const byte in[], size_t length) + { + for(size_t i = 0; i != block_size - 1; ++i) + mac.update(0); + mac.update(tag); + mac.update(in, length); + return mac.final(); + } + +} + +/* +* EAX_Mode Constructor +*/ +EAX_Mode::EAX_Mode(BlockCipher* cipher, size_t tag_size) : + m_tag_size(tag_size), + m_cipher(cipher), + m_ctr(new CTR_BE(m_cipher->clone())), + m_cmac(new CMAC(m_cipher->clone())) + { + if(tag_size < 8 || tag_size > m_cmac->output_length()) + throw Invalid_Argument(name() + ": Bad tag size " + std::to_string(tag_size)); + } + +size_t EAX_Mode::update_granularity() const + { + return 8 * m_cipher->parallel_bytes(); + } + +/* +* Set the EAX key +*/ +void EAX_Mode::key_schedule(const byte key[], size_t length) + { + /* + * These could share the key schedule, which is one nice part of EAX, + * but it's much easier to ignore that here... + */ + m_ctr->set_key(key, length); + m_cmac->set_key(key, length); + + m_ad_mac = eax_prf(1, block_size(), *m_cmac, nullptr, 0); + } + +/* +* Set the EAX associated data +*/ +void EAX_Mode::set_associated_data(const byte ad[], size_t length) + { + m_ad_mac = eax_prf(1, block_size(), *m_cmac, ad, length); + } + +secure_vector<byte> EAX_Mode::start(const byte nonce[], size_t nonce_len) + { + m_nonce_mac = eax_prf(0, block_size(), *m_cmac, nonce, nonce_len); + + m_ctr->set_iv(&m_nonce_mac[0], m_nonce_mac.size()); + + for(size_t i = 0; i != block_size() - 1; ++i) + m_cmac->update(0); + m_cmac->update(2); + + return secure_vector<byte>(); + } + +/* +* Return the name of this cipher mode +*/ +std::string EAX_Mode::name() const + { + return (m_cipher->name() + "/EAX"); + } + +void EAX_Encryption::update(secure_vector<byte>& buffer) + { + m_ctr->cipher(&buffer[0], &buffer[0], buffer.size()); + m_cmac->update(&buffer[0], buffer.size()); + } + +void EAX_Encryption::finish(secure_vector<byte>& buffer) + { + update(buffer); + + secure_vector<byte> data_mac = m_cmac->final(); + xor_buf(data_mac, m_nonce_mac, data_mac.size()); + xor_buf(data_mac, m_ad_mac, data_mac.size()); + + buffer += data_mac; + } + +void EAX_Decryption::update(secure_vector<byte>& buffer) + { + m_cmac->update(&buffer[0], buffer.size()); + m_ctr->cipher(&buffer[0], &buffer[0], buffer.size()); + } + +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(); + + if(input_length) // handle any remaining input + { + m_cmac->update(&buffer[0], buffer.size()); + m_ctr->cipher(&buffer[0], &buffer[0], buffer.size()); + } + + const byte* included_tag = &buffer[input_length]; + + secure_vector<byte> mac = m_cmac->final(); + mac ^= m_nonce_mac; + mac ^= m_ad_mac; + + if(!same_mem(&mac[0], included_tag, tag_size())) + throw Integrity_Failure("EAX tag check failed"); + } + +} diff --git a/src/aead/eax/eax.h b/src/aead/eax/eax.h new file mode 100644 index 000000000..f7e1c6387 --- /dev/null +++ b/src/aead/eax/eax.h @@ -0,0 +1,102 @@ +/* +* EAX Mode +* (C) 1999-2007,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_EAX_H__ +#define BOTAN_EAX_H__ + +#include <botan/aead.h> +#include <botan/buf_filt.h> +#include <botan/block_cipher.h> +#include <botan/stream_cipher.h> +#include <botan/mac.h> +#include <memory> + +namespace Botan { + +/** +* EAX Mode +*/ +class BOTAN_DLL EAX_Mode : public AEAD_Mode + { + public: + size_t update_granularity() const; + + secure_vector<byte> start(const byte nonce[], size_t nonce_len) override; + + void set_associated_data(const byte ad[], size_t ad_len) override; + + std::string name() const override; + + Key_Length_Specification key_spec() const override { return m_cipher->key_spec(); } + + // EAX supports arbitrary nonce lengths + bool valid_nonce_length(size_t) const override { return true; } + protected: + void key_schedule(const byte key[], size_t length) override; + + /** + * @param cipher the cipher to use + * @param tag_size is how big the auth tag will be + */ + EAX_Mode(BlockCipher* cipher, size_t tag_size); + + size_t tag_size() const { return m_tag_size; } + + size_t block_size() const { return m_cipher->block_size(); } + + size_t m_tag_size; + + std::unique_ptr<BlockCipher> m_cipher; + std::unique_ptr<StreamCipher> m_ctr; + std::unique_ptr<MessageAuthenticationCode> m_cmac; + + secure_vector<byte> m_ad_mac; + + secure_vector<byte> m_nonce_mac; + }; + +/** +* EAX Encryption +*/ +class BOTAN_DLL EAX_Encryption : public EAX_Mode + { + public: + /** + * @param cipher a 128-bit block cipher + * @param tag_size is how big the auth tag will be + */ + EAX_Encryption(BlockCipher* cipher, size_t tag_size = 16) : + EAX_Mode(cipher, tag_size) {} + + void update(secure_vector<byte>& blocks) override; + + void finish(secure_vector<byte>& final_block) override; + }; + +/** +* EAX Decryption +*/ +class BOTAN_DLL EAX_Decryption : public EAX_Mode + { + public: + /** + * @param cipher a 128-bit block cipher + * @param tag_size is how big the auth tag will be + */ + EAX_Decryption(BlockCipher* cipher, size_t tag_size = 16) : + EAX_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; + }; + +} + +#endif diff --git a/src/filters/aead/eax/info.txt b/src/aead/eax/info.txt index 09d92e724..09d92e724 100644 --- a/src/filters/aead/eax/info.txt +++ b/src/aead/eax/info.txt diff --git a/src/aead/info.txt b/src/aead/info.txt new file mode 100644 index 000000000..eae4b4340 --- /dev/null +++ b/src/aead/info.txt @@ -0,0 +1 @@ +define AEAD_MODE diff --git a/src/filters/aead/eax/eax.cpp b/src/filters/aead/eax/eax.cpp deleted file mode 100644 index d4a982aaf..000000000 --- a/src/filters/aead/eax/eax.cpp +++ /dev/null @@ -1,183 +0,0 @@ -/* -* EAX Mode Encryption -* (C) 1999-2007 Jack Lloyd -* -* Distributed under the terms of the Botan license -*/ - -#include <botan/eax.h> -#include <botan/cmac.h> -#include <botan/ctr.h> -#include <botan/parsing.h> -#include <botan/internal/xor_buf.h> -#include <algorithm> - -namespace Botan { - -namespace { - -/* -* EAX MAC-based PRF -*/ -secure_vector<byte> eax_prf(byte tag, size_t BLOCK_SIZE, - MessageAuthenticationCode& mac, - const byte in[], size_t length) - { - for(size_t i = 0; i != BLOCK_SIZE - 1; ++i) - mac.update(0); - mac.update(tag); - mac.update(in, length); - return mac.final(); - } - -size_t eax_tag_size(size_t tag_size, const BlockCipher& cipher) - { - if(tag_size == 0) - return cipher.block_size(); - return (tag_size / 8); - } - -} - -/* -* EAX_Mode Constructor -*/ -EAX_Mode::EAX_Mode(BlockCipher* cipher, size_t tag_size, bool decrypting) : - Buffered_Filter(cipher->parallel_bytes(), - decrypting ? eax_tag_size(tag_size, *cipher) : 0), - BLOCK_SIZE(cipher->block_size()), - TAG_SIZE(eax_tag_size(tag_size, *cipher)), - cipher_name(cipher->name()), - ctr_buf(DEFAULT_BUFFERSIZE) - { - cmac.reset(new CMAC(cipher->clone())); - ctr.reset(new CTR_BE(cipher)); // CTR_BE takes ownership of cipher - - if(tag_size % 8 != 0 || TAG_SIZE == 0 || TAG_SIZE > cmac->output_length()) - throw Invalid_Argument(name() + ": Bad tag size " + std::to_string(tag_size)); - } - -/* -* Set the EAX key -*/ -void EAX_Mode::set_key(const SymmetricKey& key) - { - /* - * These could share the key schedule, which is one nice part of EAX, - * but it's much easier to ignore that here... - */ - ctr->set_key(key); - cmac->set_key(key); - - ad_mac = eax_prf(1, BLOCK_SIZE, *cmac, nullptr, 0); - } - -/* -* Do setup at the start of each message -*/ -void EAX_Mode::start_msg() - { - for(size_t i = 0; i != BLOCK_SIZE - 1; ++i) - cmac->update(0); - cmac->update(2); - } - -/* -* Set the EAX nonce -*/ -void EAX_Mode::set_nonce(const byte nonce[], size_t nonce_len) - { - nonce_mac = eax_prf(0, BLOCK_SIZE, *cmac, nonce, nonce_len); - ctr->set_iv(&nonce_mac[0], nonce_mac.size()); - } - -/* -* Set the EAX associated data -*/ -void EAX_Mode::set_associated_data(const byte ad[], size_t length) - { - ad_mac = eax_prf(1, BLOCK_SIZE, *cmac, ad, length); - } - -/* -* Return the name of this cipher mode -*/ -std::string EAX_Mode::name() const - { - return (cipher_name + "/EAX"); - } - -void EAX_Mode::write(const byte input[], size_t length) - { - Buffered_Filter::write(input, length); - } - -void EAX_Mode::end_msg() - { - Buffered_Filter::end_msg(); - } - -void EAX_Encryption::buffered_block(const byte input[], size_t length) - { - while(length) - { - size_t copied = std::min<size_t>(length, ctr_buf.size()); - - ctr->cipher(input, &ctr_buf[0], copied); - cmac->update(&ctr_buf[0], copied); - - send(ctr_buf, copied); - - input += copied; - length -= copied; - } - } - -void EAX_Encryption::buffered_final(const byte input[], size_t input_length) - { - buffered_block(input, input_length); - - secure_vector<byte> data_mac = cmac->final(); - xor_buf(data_mac, nonce_mac, data_mac.size()); - xor_buf(data_mac, ad_mac, data_mac.size()); - - send(data_mac, TAG_SIZE); - } - -void EAX_Decryption::buffered_block(const byte input[], size_t length) - { - cmac->update(&input[0], length); - - while(length) - { - size_t copied = std::min<size_t>(length, ctr_buf.size()); - - ctr->cipher(input, &ctr_buf[0], copied); - - send(ctr_buf, copied); - - input += copied; - length -= copied; - } - } - -void EAX_Decryption::buffered_final(const byte input[], size_t input_length) - { - BOTAN_ASSERT(input_length >= TAG_SIZE, "Have the tag as part of final input"); - - const byte* included_tag = &input[input_length - TAG_SIZE]; - input_length -= TAG_SIZE; - - if(input_length) // handle any remaining input - buffered_block(input, input_length); - - secure_vector<byte> mac = cmac->final(); - mac ^= nonce_mac; - mac ^= ad_mac; - - if(!same_mem(&mac[0], included_tag, TAG_SIZE)) - throw Integrity_Failure("EAX tag check failed"); - } - - -} diff --git a/src/filters/aead/eax/eax.h b/src/filters/aead/eax/eax.h deleted file mode 100644 index cf99622a1..000000000 --- a/src/filters/aead/eax/eax.h +++ /dev/null @@ -1,130 +0,0 @@ -/* -* EAX Mode -* (C) 1999-2007,2013 Jack Lloyd -* -* Distributed under the terms of the Botan license -*/ - -#ifndef BOTAN_EAX_H__ -#define BOTAN_EAX_H__ - -#include <botan/aead_filt.h> -#include <botan/buf_filt.h> -#include <botan/block_cipher.h> -#include <botan/stream_cipher.h> -#include <botan/mac.h> -#include <memory> - -namespace Botan { - -/** -* EAX Mode -*/ -class BOTAN_DLL EAX_Mode : public AEAD_Filter, - private Buffered_Filter - { - public: - void set_key(const SymmetricKey& key) override; - - void set_nonce(const byte nonce[], size_t nonce_len) override; - - void set_associated_data(const byte ad[], size_t ad_len) override; - - std::string name() const override; - - Key_Length_Specification key_spec() const override { return ctr->key_spec(); } - - // EAX supports arbitrary IV lengths - bool valid_iv_length(size_t) const override { return true; } - protected: - /** - * @param cipher the cipher to use - * @param tag_size is how big the auth tag will be - */ - EAX_Mode(BlockCipher* cipher, size_t tag_size, bool decrypting); - - void start_msg(); - - /** - * The block size of the underlying cipher - */ - const size_t BLOCK_SIZE; - - /** - * The requested tag name - */ - const size_t TAG_SIZE; - - /** - * The name of the cipher - */ - std::string cipher_name; - - /** - * The stream cipher (CTR mode) - */ - std::unique_ptr<StreamCipher> ctr; - - /** - * The MAC (CMAC) - */ - std::unique_ptr<MessageAuthenticationCode> cmac; - - /** - * The MAC of the nonce - */ - secure_vector<byte> nonce_mac; - - /** - * The MAC of the associated data - */ - secure_vector<byte> ad_mac; - - /** - * A buffer for CTR mode encryption - */ - secure_vector<byte> ctr_buf; - private: - void write(const byte[], size_t); - void end_msg(); - }; - -/** -* EAX Encryption -*/ -class BOTAN_DLL EAX_Encryption : public EAX_Mode - { - public: - /** - * @param ciph the cipher to use - * @param tag_size is how big the auth tag will be - */ - EAX_Encryption(BlockCipher* ciph, size_t tag_size = 0) : - EAX_Mode(ciph, tag_size, false) {} - - private: - void buffered_block(const byte input[], size_t input_length) override; - void buffered_final(const byte input[], size_t input_length) override; - }; - -/** -* EAX Decryption -*/ -class BOTAN_DLL EAX_Decryption : public EAX_Mode - { - public: - /** - * @param ciph the cipher to use - * @param tag_size is how big the auth tag will be - */ - EAX_Decryption(BlockCipher* cipher, size_t tag_size = 0) : - EAX_Mode(cipher, tag_size, true) {} - - private: - void buffered_block(const byte input[], size_t input_length) override; - void buffered_final(const byte input[], size_t input_length) override; - }; - -} - -#endif |