diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/aead/aead.h | 87 | ||||
-rw-r--r-- | src/aead/eax/eax.cpp | 156 | ||||
-rw-r--r-- | src/aead/eax/eax.h | 105 | ||||
-rw-r--r-- | src/aead/eax/info.txt (renamed from src/filters/aead/eax/info.txt) | 2 | ||||
-rw-r--r-- | src/aead/gcm/gcm.cpp (renamed from src/filters/aead/gcm/gcm.cpp) | 139 | ||||
-rw-r--r-- | src/aead/gcm/gcm.h | 100 | ||||
-rw-r--r-- | src/aead/gcm/info.txt (renamed from src/filters/aead/gcm/info.txt) | 2 | ||||
-rw-r--r-- | src/aead/info.txt | 1 | ||||
-rw-r--r-- | src/aead/ocb/info.txt (renamed from src/filters/aead/ocb/info.txt) | 2 | ||||
-rw-r--r-- | src/aead/ocb/ocb.cpp (renamed from src/filters/aead/ocb/ocb.cpp) | 232 | ||||
-rw-r--r-- | src/aead/ocb/ocb.h (renamed from src/filters/aead/ocb/ocb.h) | 57 | ||||
-rw-r--r-- | src/engine/core_engine/core_modes.cpp | 38 | ||||
-rw-r--r-- | src/filters/aead/aead_filt.h | 38 | ||||
-rw-r--r-- | src/filters/aead/eax/eax.cpp | 183 | ||||
-rw-r--r-- | src/filters/aead/eax/eax.h | 130 | ||||
-rw-r--r-- | src/filters/aead/gcm/gcm.h | 101 | ||||
-rw-r--r-- | src/filters/aead/info.txt | 1 | ||||
-rw-r--r-- | src/filters/aead_filt/aead_filt.cpp | 105 | ||||
-rw-r--r-- | src/filters/aead_filt/aead_filt.h | 72 | ||||
-rw-r--r-- | src/filters/aead_filt/info.txt | 5 | ||||
-rw-r--r-- | src/selftest/info.txt | 1 | ||||
-rw-r--r-- | src/selftest/selftest.cpp | 18 | ||||
-rw-r--r-- | src/utils/parsing.cpp | 2 |
23 files changed, 882 insertions, 695 deletions
diff --git a/src/aead/aead.h b/src/aead/aead.h new file mode 100644 index 000000000..736de85e1 --- /dev/null +++ b/src/aead/aead.h @@ -0,0 +1,87 @@ +/* +* 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; + + 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. + * @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..fa0496f42 --- /dev/null +++ b/src/aead/eax/eax.cpp @@ -0,0 +1,156 @@ +/* +* 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)); + } + +void EAX_Mode::clear() + { + m_cipher.reset(); + m_ctr.reset(); + m_cmac.reset(); + zeroise(m_ad_mac); + zeroise(m_nonce_mac); + } + +std::string EAX_Mode::name() const + { + return (m_cipher->name() + "/EAX"); + } + +size_t EAX_Mode::update_granularity() const + { + return 8 * m_cipher->parallel_bytes(); + } + +Key_Length_Specification EAX_Mode::key_spec() const + { + return m_cipher->key_spec(); + } + +/* +* 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>(); + } + +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 += std::make_pair(&data_mac[0], tag_size()); + } + +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 remaining = buffer.size() - tag_size(); + + if(remaining) // handle any remaining input + { + m_cmac->update(&buffer[0], remaining); + m_ctr->cipher(&buffer[0], &buffer[0], remaining); + } + + const byte* included_tag = &buffer[remaining]; + + 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"); + + buffer.resize(remaining); + } + +} diff --git a/src/aead/eax/eax.h b/src/aead/eax/eax.h new file mode 100644 index 000000000..f3562f755 --- /dev/null +++ b/src/aead/eax/eax.h @@ -0,0 +1,105 @@ +/* +* 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/block_cipher.h> +#include <botan/stream_cipher.h> +#include <botan/mac.h> +#include <memory> + +namespace Botan { + +/** +* EAX base class +*/ +class BOTAN_DLL EAX_Mode : public AEAD_Mode + { + public: + 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; + + size_t update_granularity() const; + + Key_Length_Specification key_spec() const override; + + // EAX supports arbitrary nonce lengths + bool valid_nonce_length(size_t) const override { return true; } + + void clear(); + 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) {} + + size_t minimum_final_size() const override { return 0; } + + 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..94924e682 100644 --- a/src/filters/aead/eax/info.txt +++ b/src/aead/eax/info.txt @@ -1,4 +1,4 @@ -define EAX +define AEAD_EAX <requires> block diff --git a/src/filters/aead/gcm/gcm.cpp b/src/aead/gcm/gcm.cpp index 32a763df7..a067d162e 100644 --- a/src/filters/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); @@ -90,12 +92,11 @@ void ghash_finalize(const secure_vector<byte>& H, /* * GCM_Mode Constructor */ -GCM_Mode::GCM_Mode(BlockCipher* cipher, size_t tag_size, bool decrypting) : - Buffered_Filter(cipher->parallel_bytes(), decrypting ? tag_size : 0), - m_tag_size(tag_size), m_cipher_name(cipher->name()), +GCM_Mode::GCM_Mode(BlockCipher* cipher, size_t tag_size) : + m_tag_size(tag_size), + m_cipher_name(cipher->name()), m_H(16), m_H_ad(16), m_mac(16), - m_ad_len(0), m_text_len(0), - m_ctr_buf(8 * cipher->parallel_bytes()) + m_ad_len(0), m_text_len(0) { if(cipher->block_size() != BS) throw std::invalid_argument("OCB requires a 128 bit cipher so cannot be used with " + @@ -107,9 +108,35 @@ GCM_Mode::GCM_Mode(BlockCipher* cipher, size_t tag_size, bool decrypting) : throw Invalid_Argument(name() + ": Bad tag size " + std::to_string(m_tag_size)); } -void GCM_Mode::set_key(const SymmetricKey& key) +void GCM_Mode::clear() + { + zeroise(m_H); + zeroise(m_H_ad); + zeroise(m_mac); + zeroise(m_enc_y0); + m_ad_len = 0; + m_text_len = 0; + m_ctr.reset(); + } + +std::string GCM_Mode::name() const + { + return (m_cipher_name + "/GCM"); + } + +size_t GCM_Mode::update_granularity() const + { + return 4096; // CTR-BE's internal block size + } + +Key_Length_Specification GCM_Mode::key_spec() const + { + return m_ctr->key_spec(); + } + +void GCM_Mode::key_schedule(const byte key[], size_t keylen) { - m_ctr->set_key(key); + m_ctr->set_key(key, keylen); const std::vector<byte> zeros(BS); m_ctr->set_iv(&zeros[0], zeros.size()); @@ -118,9 +145,6 @@ void GCM_Mode::set_key(const SymmetricKey& key) m_ctr->cipher(&m_H[0], &m_H[0], m_H.size()); } -/* -* Set the GCM associated data -*/ void GCM_Mode::set_associated_data(const byte ad[], size_t ad_len) { zeroise(m_H_ad); @@ -129,10 +153,7 @@ void GCM_Mode::set_associated_data(const byte ad[], size_t ad_len) m_ad_len = ad_len; } -/* -* Set the GCM nonce -*/ -void GCM_Mode::set_nonce(const byte nonce[], size_t nonce_len) +secure_vector<byte> GCM_Mode::start(const byte nonce[], size_t nonce_len) { secure_vector<byte> y0(BS); @@ -151,97 +172,63 @@ void GCM_Mode::set_nonce(const byte nonce[], size_t nonce_len) m_enc_y0.resize(BS); m_ctr->encipher(m_enc_y0); - } -/* -* Do setup at the start of each message -*/ -void GCM_Mode::start_msg() - { m_text_len = 0; m_mac = m_H_ad; - } -/* -* Return the name of this cipher mode -*/ -std::string GCM_Mode::name() const - { - return (m_cipher_name + "/GCM"); - } - -void GCM_Mode::write(const byte input[], size_t length) - { - Buffered_Filter::write(input, length); + return secure_vector<byte>(); } -void GCM_Mode::end_msg() +void GCM_Encryption::update(secure_vector<byte>& buffer) { - Buffered_Filter::end_msg(); + m_ctr->cipher(&buffer[0], &buffer[0], buffer.size()); + ghash_update(m_H, m_mac, &buffer[0], buffer.size()); + m_text_len += buffer.size(); } -void GCM_Encryption::buffered_block(const byte input[], size_t length) +void GCM_Encryption::finish(secure_vector<byte>& buffer) { - while(length) - { - size_t copied = std::min<size_t>(length, m_ctr_buf.size()); - - m_ctr->cipher(input, &m_ctr_buf[0], copied); - ghash_update(m_H, m_mac, &m_ctr_buf[0], copied); - m_text_len += copied; - - send(m_ctr_buf, copied); - - input += copied; - length -= copied; - } - } - -void GCM_Encryption::buffered_final(const byte input[], size_t input_length) - { - buffered_block(input, input_length); + update(buffer); ghash_finalize(m_H, m_mac, m_ad_len, m_text_len); m_mac ^= m_enc_y0; - send(m_mac, m_tag_size); + buffer += std::make_pair(&m_mac[0], tag_size()); } -void GCM_Decryption::buffered_block(const byte input[], size_t length) +void GCM_Decryption::update(secure_vector<byte>& buffer) { - while(length) - { - size_t copied = std::min<size_t>(length, m_ctr_buf.size()); - - ghash_update(m_H, m_mac, &input[0], copied); - m_ctr->cipher(input, &m_ctr_buf[0], copied); - m_text_len += copied; - - send(m_ctr_buf, copied); - - input += copied; - length -= copied; - } + ghash_update(m_H, m_mac, &buffer[0], buffer.size()); + m_ctr->cipher(&buffer[0], &buffer[0], buffer.size()); + m_text_len += buffer.size(); } -void GCM_Decryption::buffered_final(const byte input[], size_t input_length) +void GCM_Decryption::finish(secure_vector<byte>& buffer) { - BOTAN_ASSERT(input_length >= m_tag_size, "Have the tag as part of final input"); + BOTAN_ASSERT(buffer.size() >= tag_size(), + "Have the tag as part of final input"); - const byte* included_tag = &input[input_length - m_tag_size]; - input_length -= m_tag_size; + const size_t remaining = buffer.size() - tag_size(); - if(input_length) // handle any remaining input - buffered_block(input, input_length); + // handle any final input before the tag + if(remaining) + { + 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; - if(!same_mem(&m_mac[0], included_tag, m_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/gcm/gcm.h b/src/aead/gcm/gcm.h new file mode 100644 index 000000000..cf7d94ced --- /dev/null +++ b/src/aead/gcm/gcm.h @@ -0,0 +1,100 @@ +/* +* GCM Mode +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_GCM_H__ +#define BOTAN_GCM_H__ + +#include <botan/aead.h> +#include <botan/block_cipher.h> +#include <botan/stream_cipher.h> +#include <memory> + +namespace Botan { + +/** +* GCM Mode +*/ +class BOTAN_DLL GCM_Mode : public AEAD_Mode + { + public: + 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; + + size_t update_granularity() const; + + Key_Length_Specification key_spec() const override; + + // GCM supports arbitrary nonce lengths + bool valid_nonce_length(size_t) const override { return true; } + + void clear(); + protected: + void key_schedule(const byte key[], size_t length) override; + + GCM_Mode(BlockCipher* cipher, size_t tag_size); + + size_t tag_size() const { return m_tag_size; } + + static const size_t BS = 16; + + const size_t m_tag_size; + const std::string m_cipher_name; + + std::unique_ptr<StreamCipher> m_ctr; + secure_vector<byte> m_H; + secure_vector<byte> m_H_ad; + secure_vector<byte> m_mac; + secure_vector<byte> m_enc_y0; + size_t m_ad_len, m_text_len; + }; + +/** +* GCM Encryption +*/ +class BOTAN_DLL GCM_Encryption : public GCM_Mode + { + public: + /** + * @param cipher the 128 bit block cipher to use + * @param tag_size is how big the auth tag will be + */ + GCM_Encryption(BlockCipher* cipher, size_t tag_size = 16) : + GCM_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; + }; + +/** +* GCM Decryption +*/ +class BOTAN_DLL GCM_Decryption : public GCM_Mode + { + public: + /** + * @param cipher the 128 bit block cipher to use + * @param tag_size is how big the auth tag will be + */ + GCM_Decryption(BlockCipher* cipher, size_t tag_size = 16) : + GCM_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/gcm/info.txt b/src/aead/gcm/info.txt index 52e677a03..698cd0803 100644 --- a/src/filters/aead/gcm/info.txt +++ b/src/aead/gcm/info.txt @@ -1,4 +1,4 @@ -define GCM +define AEAD_GCM <requires> block diff --git a/src/aead/info.txt b/src/aead/info.txt new file mode 100644 index 000000000..c2985ea85 --- /dev/null +++ b/src/aead/info.txt @@ -0,0 +1 @@ +define AEAD_MODES diff --git a/src/filters/aead/ocb/info.txt b/src/aead/ocb/info.txt index 0ee41681d..8d6a93ed9 100644 --- a/src/filters/aead/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/ocb/ocb.cpp b/src/aead/ocb/ocb.cpp index eb10b6e9f..50b33960f 100644 --- a/src/filters/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 @@ -59,13 +56,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 +103,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 +156,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 +173,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 +239,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 +246,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 +272,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); + + if(remainder_bytes) + { + BOTAN_ASSERT(remainder_bytes < BS, "Only a partial block left"); + byte* remainder = &buffer[buffer.size() - remainder_bytes]; - m_offset ^= m_L->star(); // Offset_* + xor_buf(&m_checksum[0], &remainder[0], remainder_bytes); + m_checksum[remainder_bytes] ^= 0x80; - secure_vector<byte> buf(BS); - m_cipher->encrypt(m_offset, buf); - xor_buf(&buf[0], &input[0], input_length); + m_offset ^= m_L->star(); // Offset_* - send(buf, input_length); // final ciphertext + 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 +313,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 +330,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 +337,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 +363,45 @@ 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"); + + decrypt(&buffer[0], buffer.size() / BS); + } - const byte* included_tag = &input[input_length - m_tag_size]; - input_length -= m_tag_size; +void OCB_Decryption::finish(secure_vector<byte>& buffer) + { + BOTAN_ASSERT(buffer.size() >= tag_size(), "We have the tag"); - 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; - } + const size_t remaining = buffer.size() - tag_size(); - if(input_length) + if(remaining) { - BOTAN_ASSERT(input_length < BS, "Only a partial block left"); + const size_t final_full_blocks = remaining / BS; + const size_t final_bytes = remaining - (final_full_blocks * BS); - m_offset ^= m_L->star(); // Offset_* + decrypt(&buffer[0], final_full_blocks); - secure_vector<byte> buf(BS); - m_cipher->encrypt(m_offset, buf); // P_* + if(final_bytes) + { + BOTAN_ASSERT(final_bytes < BS, "Only a partial block left"); + + byte* remainder = &buffer[remaining - final_bytes]; - xor_buf(&buf[0], &input[0], input_length); + m_offset ^= m_L->star(); // Offset_* - xor_buf(&m_checksum[0], &buf[0], input_length); - m_checksum[input_length] ^= 0x80; + secure_vector<byte> pad(BS); + m_cipher->encrypt(m_offset, pad); // P_* - send(buf, input_length); // final plaintext + xor_buf(&remainder[0], &pad[0], final_bytes); + + xor_buf(&m_checksum[0], &remainder[0], final_bytes); + m_checksum[final_bytes] ^= 0x80; + } } - // now compute the tag + // compute the mac secure_vector<byte> mac = m_offset; mac ^= m_checksum; mac ^= m_L->dollar(); @@ -407,12 +410,19 @@ void OCB_Decryption::buffered_final(const byte input[], size_t input_length) 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/filters/aead/ocb/ocb.h b/src/aead/ocb/ocb.h index 0a1cbcaff..9d10c2656 100644 --- a/src/filters/aead/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); }; } 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/aead_filt.h b/src/filters/aead/aead_filt.h deleted file mode 100644 index 77818c17e..000000000 --- a/src/filters/aead/aead_filt.h +++ /dev/null @@ -1,38 +0,0 @@ -/* -* Interface for AEAD modes -* (C) 2013 Jack Lloyd -* -* Distributed under the terms of the Botan license -*/ - -#ifndef BOTAN_AEAD_H__ -#define BOTAN_AEAD_H__ - -#include <botan/key_filt.h> - -namespace Botan { - -class BOTAN_DLL AEAD_Filter : public Keyed_Filter - { - public: - /** - * 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. - * - * @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 void set_nonce(const byte nonce[], size_t nonce_len) = 0; - - void set_iv(const InitializationVector& iv) override - { - set_nonce(iv.begin(), iv.length()); - } - }; - -} - -#endif 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 diff --git a/src/filters/aead/gcm/gcm.h b/src/filters/aead/gcm/gcm.h deleted file mode 100644 index a04a6b8c0..000000000 --- a/src/filters/aead/gcm/gcm.h +++ /dev/null @@ -1,101 +0,0 @@ -/* -* GCM Mode -* (C) 2013 Jack Lloyd -* -* Distributed under the terms of the Botan license -*/ - -#ifndef BOTAN_GCM_H__ -#define BOTAN_GCM_H__ - -#include <botan/aead_filt.h> -#include <botan/buf_filt.h> -#include <botan/block_cipher.h> -#include <botan/stream_cipher.h> -#include <memory> - -namespace Botan { - -/** -* GCM Mode -*/ -class BOTAN_DLL GCM_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; - - /** - * @note must be called before start_msg or not at all - */ - void set_associated_data(const byte ad[], size_t ad_len) override; - - Key_Length_Specification key_spec() const override { return m_ctr->key_spec(); } - - // GCM supports arbitrary IV lengths - bool valid_iv_length(size_t) const override { return true; } - - std::string name() const override; - protected: - GCM_Mode(BlockCipher* cipher, size_t tag_size, bool decrypting); - - static const size_t BS = 16; - - const size_t m_tag_size; - const std::string m_cipher_name; - - std::unique_ptr<StreamCipher> m_ctr; - secure_vector<byte> m_H; - secure_vector<byte> m_H_ad; - secure_vector<byte> m_mac; - secure_vector<byte> m_enc_y0; - size_t m_ad_len, m_text_len; - secure_vector<byte> m_ctr_buf; - - private: - void write(const byte[], size_t); - void start_msg(); - void end_msg(); - }; - -/** -* GCM Encryption -*/ -class BOTAN_DLL GCM_Encryption : public GCM_Mode - { - public: - /** - * @param ciph the cipher to use - * @param tag_size is how big the auth tag will be - */ - GCM_Encryption(BlockCipher* ciph, size_t tag_size = 16) : - GCM_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; - }; - -/** -* GCM Decryption -*/ -class BOTAN_DLL GCM_Decryption : public GCM_Mode - { - public: - /** - * @param ciph the cipher to use - * @param tag_size is how big the auth tag will be - */ - GCM_Decryption(BlockCipher* cipher, size_t tag_size = 16) : - GCM_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 diff --git a/src/filters/aead/info.txt b/src/filters/aead/info.txt deleted file mode 100644 index b43aab2f6..000000000 --- a/src/filters/aead/info.txt +++ /dev/null @@ -1 +0,0 @@ -define AEAD diff --git a/src/filters/aead_filt/aead_filt.cpp b/src/filters/aead_filt/aead_filt.cpp new file mode 100644 index 000000000..f70b8eafe --- /dev/null +++ b/src/filters/aead_filt/aead_filt.cpp @@ -0,0 +1,105 @@ +/* +* 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; + + while(input_length) + { + const size_t take = std::min(m_aead->update_granularity(), input_length); + + buf.resize(take); + copy_mem(&buf[0], input, take); + + m_aead->update(buf); + + send(buf); + + input += take; + input_length -= take; + } + } + +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 new file mode 100644 index 000000000..590a60655 --- /dev/null +++ b/src/filters/aead_filt/aead_filt.h @@ -0,0 +1,72 @@ +/* +* Filter interface for AEAD modes +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#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 { + +/** +* 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 + * and before end_msg. + * + * @param ad the associated data + * @param ad_len length of add in bytes + */ + 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; + + bool valid_iv_length(size_t length) const 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 + { + 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; + + }; + +} + +#endif diff --git a/src/filters/aead_filt/info.txt b/src/filters/aead_filt/info.txt new file mode 100644 index 000000000..7df9cc619 --- /dev/null +++ b/src/filters/aead_filt/info.txt @@ -0,0 +1,5 @@ +define AEAD_FILTER + +<requires> +aead +</requires> diff --git a/src/selftest/info.txt b/src/selftest/info.txt index 1a53ea021..e4e9f28dc 100644 --- a/src/selftest/info.txt +++ b/src/selftest/info.txt @@ -3,5 +3,6 @@ define SELFTESTS <requires> algo_factory filters +aead_filt core_engine </requires> diff --git a/src/selftest/selftest.cpp b/src/selftest/selftest.cpp index 4be4f8751..b989d889d 100644 --- a/src/selftest/selftest.cpp +++ b/src/selftest/selftest.cpp @@ -12,8 +12,6 @@ #include <botan/internal/core_engine.h> #include <botan/internal/stl_util.h> -#include <iostream> - namespace Botan { namespace { @@ -126,18 +124,18 @@ algorithm_kat_detailed(const SCAN_Name& algo_name, else if(!dec->valid_iv_length(0)) throw Invalid_IV_Length(algo, iv.length()); -#if defined(BOTAN_HAS_AEAD) + const std::vector<byte> ad = hex_decode(search_map(vars, std::string("ad"))); - if(AEAD_Filter* enc_aead = dynamic_cast<AEAD_Filter*>(enc)) + if(!ad.empty()) { - const std::vector<byte> ad = hex_decode(search_map(vars, std::string("ad"))); - - enc_aead->set_associated_data(&ad[0], ad.size()); + if(AEAD_Filter* enc_aead = dynamic_cast<AEAD_Filter*>(enc)) + { + enc_aead->set_associated_data(&ad[0], ad.size()); - if(AEAD_Filter* dec_aead = dynamic_cast<AEAD_Filter*>(dec)) - dec_aead->set_associated_data(&ad[0], ad.size()); + if(AEAD_Filter* dec_aead = dynamic_cast<AEAD_Filter*>(dec)) + dec_aead->set_associated_data(&ad[0], ad.size()); + } } -#endif all_results[provider + " (encrypt)"] = test_filter_kat(enc, input, output); all_results[provider + " (decrypt)"] = test_filter_kat(dec, output, input); diff --git a/src/utils/parsing.cpp b/src/utils/parsing.cpp index 1e90f2f6e..486f5fdef 100644 --- a/src/utils/parsing.cpp +++ b/src/utils/parsing.cpp @@ -14,7 +14,7 @@ namespace Botan { u32bit to_u32bit(const std::string& str) { - return std::stoul(str); + return std::stoul(str, nullptr); } /* |