diff options
-rw-r--r-- | checks/bench.cpp | 4 | ||||
-rw-r--r-- | src/aead/aead.h | 111 | ||||
-rw-r--r-- | src/algo_base/transform.h | 86 | ||||
-rw-r--r-- | src/engine/core_engine/core_modes.cpp | 8 | ||||
-rw-r--r-- | src/filters/aead_filt/aead_filt.cpp | 105 | ||||
-rw-r--r-- | src/filters/aead_filt/aead_filt.h | 48 | ||||
-rw-r--r-- | src/filters/filters.h | 2 | ||||
-rw-r--r-- | src/filters/info.txt | 2 | ||||
-rw-r--r-- | src/filters/modes/xts/xts.cpp | 409 | ||||
-rw-r--r-- | src/filters/modes/xts/xts.h | 91 | ||||
-rw-r--r-- | src/filters/transform_filter.cpp | 99 | ||||
-rw-r--r-- | src/filters/transform_filter.h | 67 | ||||
-rw-r--r-- | src/modes/aead/aead.cpp (renamed from src/aead/aead.cpp) | 0 | ||||
-rw-r--r-- | src/modes/aead/aead.h | 59 | ||||
-rw-r--r-- | src/modes/aead/eax/eax.cpp (renamed from src/aead/eax/eax.cpp) | 0 | ||||
-rw-r--r-- | src/modes/aead/eax/eax.h (renamed from src/aead/eax/eax.h) | 0 | ||||
-rw-r--r-- | src/modes/aead/eax/info.txt (renamed from src/aead/eax/info.txt) | 0 | ||||
-rw-r--r-- | src/modes/aead/gcm/gcm.cpp (renamed from src/aead/gcm/gcm.cpp) | 0 | ||||
-rw-r--r-- | src/modes/aead/gcm/gcm.h (renamed from src/aead/gcm/gcm.h) | 0 | ||||
-rw-r--r-- | src/modes/aead/gcm/info.txt (renamed from src/aead/gcm/info.txt) | 0 | ||||
-rw-r--r-- | src/modes/aead/info.txt (renamed from src/aead/info.txt) | 0 | ||||
-rw-r--r-- | src/modes/aead/ocb/info.txt (renamed from src/aead/ocb/info.txt) | 0 | ||||
-rw-r--r-- | src/modes/aead/ocb/ocb.cpp (renamed from src/aead/ocb/ocb.cpp) | 0 | ||||
-rw-r--r-- | src/modes/aead/ocb/ocb.h (renamed from src/aead/ocb/ocb.h) | 0 | ||||
-rw-r--r-- | src/modes/info.txt (renamed from src/filters/modes/xts/info.txt) | 1 | ||||
-rw-r--r-- | src/modes/xts/info.txt | 1 | ||||
-rw-r--r-- | src/modes/xts/xts.cpp | 292 | ||||
-rw-r--r-- | src/modes/xts/xts.h | 86 |
28 files changed, 706 insertions, 765 deletions
diff --git a/checks/bench.cpp b/checks/bench.cpp index ee34b5233..3deff5136 100644 --- a/checks/bench.cpp +++ b/checks/bench.cpp @@ -196,9 +196,7 @@ bool bench_algo(const std::string& algo, continue; filt->set_key(Botan::SymmetricKey(&buf[0], cipher_keylen)); - - if(filt->valid_iv_length(cipher_ivlen / 2)) - filt->set_iv(Botan::InitializationVector(&buf[0], cipher_ivlen)); + filt->set_iv(Botan::InitializationVector(&buf[0], cipher_ivlen)); Botan::Pipe pipe(filt, new Botan::BitBucket); pipe.start_msg(); diff --git a/src/aead/aead.h b/src/aead/aead.h deleted file mode 100644 index 0aa50f348..000000000 --- a/src/aead/aead.h +++ /dev/null @@ -1,111 +0,0 @@ -/* -* 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: - /** - * Returns the size of the output if this mode is used to process - * a message with input_length bytes. Typically this will be - * input_length plus or minus the length of the tag. - */ - virtual size_t output_length(size_t input_length) const = 0; - - /** - * @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; - - /** - * @return Random nonce appropriate for passing to start - */ - //virtual secure_vector<byte> nonce(RandomNumberGenerator& rng) 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 finish. - * - * 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; - - template<typename Alloc> - void set_associated_data_vec(const std::vector<byte, Alloc>& ad) - { - set_associated_data(&ad[0], ad.size()); - } - - 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, size_t offset = 0) = 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 - * @param offset an offset into final_block to begin processing - */ - virtual void finish(secure_vector<byte>& final_block, size_t offset = 0) = 0; - - virtual ~AEAD_Mode() {} - }; - -/** -* Get an AEAD mode by name (eg "AES-128/GCM" or "Serpent/EAX") -*/ -BOTAN_DLL AEAD_Mode* get_aead(const std::string& name, Cipher_Dir direction); - -} - -#endif diff --git a/src/algo_base/transform.h b/src/algo_base/transform.h new file mode 100644 index 000000000..672b39ed0 --- /dev/null +++ b/src/algo_base/transform.h @@ -0,0 +1,86 @@ +/* +* Transformations of data +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_TRANSFORM_H__ +#define BOTAN_TRANSFORM_H__ + +#include <botan/sym_algo.h> + +namespace Botan { + +/** +* Interface for general transformations on data +*/ +class Transformation : public SymmetricAlgorithm + { + public: + /** + * Begin processing a message. + * @param nonce the per message nonce + */ + template<typename Alloc> + secure_vector<byte> start_vec(const std::vector<byte, Alloc>& nonce) + { + return start(&nonce[0], nonce.size()); + } + + /** + * 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; + + /** + * Process 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, size_t offset = 0) = 0; + + /** + * Complete processing of a message. + * + * @param final_block in/out parameter which must be at least + * minimum_final_size() bytes, and will be set to any final output + * @param offset an offset into final_block to begin processing + */ + virtual void finish(secure_vector<byte>& final_block, size_t offset = 0) = 0; + + /** + * Returns the size of the output if this transform is used to process a + * message with input_length bytes. Will throw if unable to give a precise + * answer. + */ + virtual size_t output_length(size_t input_length) const = 0; + + /** + * @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; + + /** + * Return the default size for a nonce + */ + virtual size_t default_nonce_size() const = 0; + + /** + * Return true iff nonce_len is a valid length for the nonce + */ + virtual bool valid_nonce_length(size_t nonce_len) const = 0; + + virtual ~Transformation() {} + }; + +} + +#endif diff --git a/src/engine/core_engine/core_modes.cpp b/src/engine/core_engine/core_modes.cpp index 199b71838..cf972dd5c 100644 --- a/src/engine/core_engine/core_modes.cpp +++ b/src/engine/core_engine/core_modes.cpp @@ -36,7 +36,7 @@ #include <botan/ctr.h> #endif -#if defined(BOTAN_HAS_XTS) +#if defined(BOTAN_HAS_MODE_XTS) #include <botan/xts.h> #endif @@ -141,13 +141,13 @@ Keyed_Filter* get_cipher_mode(const BlockCipher* block_cipher, #endif } -#if defined(BOTAN_HAS_XTS) +#if defined(BOTAN_HAS_MODE_XTS) if(mode == "XTS") { if(direction == ENCRYPTION) - return new XTS_Encryption(block_cipher->clone()); + return new Transformation_Filter(new XTS_Encryption(block_cipher->clone())); else - return new XTS_Decryption(block_cipher->clone()); + return new Transformation_Filter(new XTS_Decryption(block_cipher->clone())); } #endif diff --git a/src/filters/aead_filt/aead_filt.cpp b/src/filters/aead_filt/aead_filt.cpp deleted file mode 100644 index f70b8eafe..000000000 --- a/src/filters/aead_filt/aead_filt.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/* -* 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 index 590a60655..65f73d7d3 100644 --- a/src/filters/aead_filt/aead_filt.h +++ b/src/filters/aead_filt/aead_filt.h @@ -1,5 +1,5 @@ /* -* Filter interface for AEAD modes +* Filter interface for AEAD Modes * (C) 2013 Jack Lloyd * * Distributed under the terms of the Botan license @@ -8,21 +8,18 @@ #ifndef BOTAN_AEAD_FILTER_H__ #define BOTAN_AEAD_FILTER_H__ -#include <botan/key_filt.h> -#include <botan/buf_filt.h> +#include <botan/transform_filter.h> #include <botan/aead.h> -#include <memory> namespace Botan { /** -* Filter interface for AEAD modes like EAX and GCM +* Filter interface for AEAD Modes */ -class BOTAN_DLL AEAD_Filter : public Keyed_Filter, - private Buffered_Filter +class BOTAN_DLL AEAD_Filter : public Transformation_Filter { public: - AEAD_Filter(AEAD_Mode* aead); + AEAD_Filter(AEAD_Mode* aead) : Transformation_Filter(aead) {} /** * Set associated data that is not included in the ciphertext but @@ -32,39 +29,10 @@ class BOTAN_DLL AEAD_Filter : public Keyed_Filter, * @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 + void set_associated_data(const byte ad[], size_t ad_len) { - 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; - + dynamic_cast<AEAD_Mode&>(get_transform()).set_associated_data(ad, ad_len); + } }; } diff --git a/src/filters/filters.h b/src/filters/filters.h index 8fcc2d85d..5973cbf50 100644 --- a/src/filters/filters.h +++ b/src/filters/filters.h @@ -28,7 +28,7 @@ namespace Botan { /** -* Stream Cipher Filter. +* Stream Cipher Filter */ class BOTAN_DLL StreamCipher_Filter : public Keyed_Filter { diff --git a/src/filters/info.txt b/src/filters/info.txt index b5c03aa45..0c56d8269 100644 --- a/src/filters/info.txt +++ b/src/filters/info.txt @@ -13,6 +13,7 @@ pipe_io.cpp pipe_rw.cpp secqueue.cpp threaded_fork.cpp +transform_filter.cpp </source> <header:public> @@ -25,6 +26,7 @@ filters.h key_filt.h pipe.h secqueue.h +transform_filter.h </header:public> <header:internal> diff --git a/src/filters/modes/xts/xts.cpp b/src/filters/modes/xts/xts.cpp deleted file mode 100644 index df38614bb..000000000 --- a/src/filters/modes/xts/xts.cpp +++ /dev/null @@ -1,409 +0,0 @@ -/* -* XTS Mode -* (C) 2009 Jack Lloyd -* -* Distributed under the terms of the Botan license -*/ - -#include <botan/xts.h> -#include <botan/internal/xor_buf.h> -#include <algorithm> -#include <stdexcept> - -namespace Botan { - -namespace { - -void poly_double(byte tweak[], size_t size) - { - const byte polynomial = (size == 16) ? 0x87 : 0x1B; - - byte carry = 0; - for(size_t i = 0; i != size; ++i) - { - byte carry2 = (tweak[i] >> 7); - tweak[i] = (tweak[i] << 1) | carry; - carry = carry2; - } - - if(carry) - tweak[0] ^= polynomial; - } - -/* XTS needs to process at least 2 blocks in parallel - because block_size+1 bytes are needed at the end -*/ -size_t xts_parallelism(BlockCipher* cipher) - { - return std::max<size_t>(cipher->parallel_bytes(), - 2 * cipher->block_size()); - } - -Key_Length_Specification xts_key_spec(const BlockCipher& cipher) - { - const Key_Length_Specification& spec = cipher.key_spec(); - - return Key_Length_Specification(2*spec.minimum_keylength(), - 2*spec.maximum_keylength(), - 2*spec.keylength_multiple()); - } - -} - -/* -* XTS_Encryption constructor -*/ -XTS_Encryption::XTS_Encryption(BlockCipher* ciph) : - Buffered_Filter(xts_parallelism(ciph), ciph->block_size() + 1), - cipher(ciph) - { - if(cipher->block_size() != 8 && cipher->block_size() != 16) - throw std::invalid_argument("Bad cipher for XTS: " + cipher->name()); - - cipher2 = cipher->clone(); - tweak.resize(buffered_block_size()); - } - -/* -* XTS_Encryption constructor -*/ -XTS_Encryption::XTS_Encryption(BlockCipher* ciph, - const SymmetricKey& key, - const InitializationVector& iv) : - Buffered_Filter(xts_parallelism(ciph), ciph->block_size() + 1), - cipher(ciph) - { - if(cipher->block_size() != 8 && cipher->block_size() != 16) - throw std::invalid_argument("Bad cipher for XTS: " + cipher->name()); - - cipher2 = cipher->clone(); - tweak.resize(buffered_block_size()); - - set_key(key); - set_iv(iv); - } - -/* -* Return the name -*/ -std::string XTS_Encryption::name() const - { - return (cipher->name() + "/XTS"); - } - -Key_Length_Specification XTS_Encryption::key_spec() const - { - return xts_key_spec(*cipher); - } - -/* -* Set new tweak -*/ -void XTS_Encryption::set_iv(const InitializationVector& iv) - { - if(!valid_iv_length(iv.length())) - throw Invalid_IV_Length(name(), iv.length()); - - const size_t blocks_in_tweak = tweak.size() / cipher->block_size(); - - tweak.assign(iv.begin(), iv.end()); - cipher2->encrypt(tweak); - - for(size_t i = 1; i < blocks_in_tweak; ++i) - { - buffer_insert(tweak, i*cipher->block_size(), - &tweak[(i-1)*cipher->block_size()], - cipher->block_size()); - - poly_double(&tweak[i*cipher->block_size()], cipher->block_size()); - } - } - -void XTS_Encryption::set_key(const SymmetricKey& key) - { - size_t key_half = key.length() / 2; - - if(key.length() % 2 == 1 || !cipher->valid_keylength(key_half)) - throw Invalid_Key_Length(name(), key.length()); - - cipher->set_key(key.begin(), key_half); - cipher2->set_key(key.begin() + key_half, key_half); - } - -/* -* Encrypt in XTS mode -*/ -void XTS_Encryption::write(const byte input[], size_t length) - { - Buffered_Filter::write(input, length); - } -/* -* Finish encrypting in XTS mode -*/ -void XTS_Encryption::end_msg() - { - Buffered_Filter::end_msg(); - } - -void XTS_Encryption::buffered_block(const byte input[], size_t length) - { - const size_t blocks_in_tweak = tweak.size() / cipher->block_size(); - size_t blocks = length / cipher->block_size(); - - secure_vector<byte> temp(tweak.size()); - - while(blocks) - { - size_t to_proc = std::min(blocks, blocks_in_tweak); - size_t to_proc_bytes = to_proc * cipher->block_size(); - - xor_buf(temp, input, tweak, to_proc_bytes); - - cipher->encrypt_n(&temp[0], &temp[0], to_proc); - - xor_buf(temp, tweak, to_proc_bytes); - - send(temp, to_proc_bytes); - - copy_mem(&tweak[0], - &tweak[(to_proc-1)*cipher->block_size()], - cipher->block_size()); - - poly_double(&tweak[0], cipher->block_size()); - - for(size_t i = 1; i < blocks_in_tweak; ++i) - { - buffer_insert(tweak, i*cipher->block_size(), - &tweak[(i-1)*cipher->block_size()], - cipher->block_size()); - - poly_double(&tweak[i*cipher->block_size()], cipher->block_size()); - } - - input += to_proc * cipher->block_size(); - blocks -= to_proc; - } - } - -/* -* Finish encrypting in XTS mode -*/ -void XTS_Encryption::buffered_final(const byte input[], size_t length) - { - if(length <= cipher->block_size()) - throw Encoding_Error("XTS_Encryption: insufficient data to encrypt"); - - if(length % cipher->block_size() == 0) - { - buffered_block(input, length); - } - else - { // steal ciphertext - - size_t leftover_blocks = - ((length / cipher->block_size()) - 1) * cipher->block_size(); - - buffered_block(input, leftover_blocks); - - input += leftover_blocks; - length -= leftover_blocks; - - secure_vector<byte> temp(input, input + length); - - xor_buf(temp, tweak, cipher->block_size()); - cipher->encrypt(temp); - xor_buf(temp, tweak, cipher->block_size()); - - poly_double(&tweak[0], cipher->block_size()); - - for(size_t i = 0; i != length - cipher->block_size(); ++i) - std::swap(temp[i], temp[i + cipher->block_size()]); - - xor_buf(temp, tweak, cipher->block_size()); - cipher->encrypt(temp); - xor_buf(temp, tweak, cipher->block_size()); - - send(temp, temp.size()); - } - - buffer_reset(); - } - -/* -* XTS_Decryption constructor -*/ -XTS_Decryption::XTS_Decryption(BlockCipher* ciph) : - Buffered_Filter(xts_parallelism(ciph), ciph->block_size() + 1), - cipher(ciph) - { - if(cipher->block_size() != 8 && cipher->block_size() != 16) - throw std::invalid_argument("Bad cipher for XTS: " + cipher->name()); - - cipher2 = ciph->clone(); - tweak.resize(buffered_block_size()); - } - -/* -* XTS_Decryption constructor -*/ -XTS_Decryption::XTS_Decryption(BlockCipher* ciph, - const SymmetricKey& key, - const InitializationVector& iv) : - Buffered_Filter(xts_parallelism(ciph), ciph->block_size() + 1), - cipher(ciph) - { - if(cipher->block_size() != 8 && cipher->block_size() != 16) - throw std::invalid_argument("Bad cipher for XTS: " + cipher->name()); - - cipher2 = ciph->clone(); - tweak.resize(buffered_block_size()); - - set_key(key); - set_iv(iv); - } - -/* -* Return the name -*/ -std::string XTS_Decryption::name() const - { - return (cipher->name() + "/XTS"); - } - -Key_Length_Specification XTS_Decryption::key_spec() const - { - return xts_key_spec(*cipher); - } - -/* -* Set new tweak -*/ -void XTS_Decryption::set_iv(const InitializationVector& iv) - { - if(!valid_iv_length(iv.length())) - throw Invalid_IV_Length(name(), iv.length()); - - const size_t blocks_in_tweak = tweak.size() / cipher->block_size(); - - tweak.assign(iv.begin(), iv.end()); - cipher2->encrypt(tweak); - - for(size_t i = 1; i < blocks_in_tweak; ++i) - { - buffer_insert(tweak, i*cipher->block_size(), - &tweak[(i-1)*cipher->block_size()], - cipher->block_size()); - - poly_double(&tweak[i*cipher->block_size()], cipher->block_size()); - } - } - -void XTS_Decryption::set_key(const SymmetricKey& key) - { - size_t key_half = key.length() / 2; - - if(key.length() % 2 == 1 || !cipher->valid_keylength(key_half)) - throw Invalid_Key_Length(name(), key.length()); - - cipher->set_key(key.begin(), key_half); - cipher2->set_key(key.begin() + key_half, key_half); - } - -/* -* Decrypt in XTS mode -*/ -void XTS_Decryption::write(const byte input[], size_t length) - { - Buffered_Filter::write(input, length); - } - -/* -* Finish decrypting in XTS mode -*/ -void XTS_Decryption::end_msg() - { - Buffered_Filter::end_msg(); - } - -void XTS_Decryption::buffered_block(const byte input[], size_t input_length) - { - const size_t blocks_in_tweak = tweak.size() / cipher->block_size(); - size_t blocks = input_length / cipher->block_size(); - - secure_vector<byte> temp(tweak.size()); - - while(blocks) - { - size_t to_proc = std::min(blocks, blocks_in_tweak); - size_t to_proc_bytes = to_proc * cipher->block_size(); - - xor_buf(temp, input, tweak, to_proc_bytes); - - cipher->decrypt_n(&temp[0], &temp[0], to_proc); - - xor_buf(temp, tweak, to_proc_bytes); - - send(temp, to_proc_bytes); - - copy_mem(&tweak[0], - &tweak[(to_proc-1)*cipher->block_size()], - cipher->block_size()); - - poly_double(&tweak[0], cipher->block_size()); - - for(size_t i = 1; i < blocks_in_tweak; ++i) - { - buffer_insert(tweak, i*cipher->block_size(), - &tweak[(i-1)*cipher->block_size()], - cipher->block_size()); - - poly_double(&tweak[i*cipher->block_size()], cipher->block_size()); - } - - input += to_proc * cipher->block_size(); - blocks -= to_proc; - } - } - -void XTS_Decryption::buffered_final(const byte input[], size_t length) - { - if(length <= cipher->block_size()) - throw Decoding_Error("XTS_Decryption: insufficient data to decrypt"); - - if(length % cipher->block_size() == 0) - { - buffered_block(input, length); - } - else - { - size_t leftover_blocks = - ((length / cipher->block_size()) - 1) * cipher->block_size(); - - buffered_block(input, leftover_blocks); - - input += leftover_blocks; - length -= leftover_blocks; - - secure_vector<byte> temp(input, input + length); - secure_vector<byte> tweak_copy(&tweak[0], &tweak[cipher->block_size()]); - - poly_double(&tweak_copy[0], cipher->block_size()); - - xor_buf(temp, tweak_copy, cipher->block_size()); - cipher->decrypt(temp); - xor_buf(temp, tweak_copy, cipher->block_size()); - - for(size_t i = 0; i != length - cipher->block_size(); ++i) - std::swap(temp[i], temp[i + cipher->block_size()]); - - xor_buf(temp, tweak, cipher->block_size()); - cipher->decrypt(temp); - xor_buf(temp, tweak, cipher->block_size()); - - send(temp, length); - } - - buffer_reset(); - } - -} diff --git a/src/filters/modes/xts/xts.h b/src/filters/modes/xts/xts.h deleted file mode 100644 index 05a779703..000000000 --- a/src/filters/modes/xts/xts.h +++ /dev/null @@ -1,91 +0,0 @@ -/* -* XTS mode, from IEEE P1619 -* (C) 2009 Jack Lloyd -* -* Distributed under the terms of the Botan license -*/ - -#ifndef BOTAN_XTS_H__ -#define BOTAN_XTS_H__ - -#include <botan/block_cipher.h> -#include <botan/key_filt.h> -#include <botan/buf_filt.h> - -namespace Botan { - -/** -* IEEE P1619 XTS Encryption -*/ -class BOTAN_DLL XTS_Encryption : public Keyed_Filter, - private Buffered_Filter - { - public: - void set_key(const SymmetricKey& key); - void set_iv(const InitializationVector& iv); - - Key_Length_Specification key_spec() const override; - - bool valid_iv_length(size_t iv_len) const - { return (iv_len == cipher->block_size()); } - - std::string name() const; - - XTS_Encryption(BlockCipher* ciph); - - XTS_Encryption(BlockCipher* ciph, - const SymmetricKey& key, - const InitializationVector& iv); - - ~XTS_Encryption() { delete cipher; delete cipher2; } - private: - void write(const byte[], size_t); - void end_msg(); - - void buffered_block(const byte input[], size_t input_length); - void buffered_final(const byte input[], size_t input_length); - - BlockCipher* cipher; - BlockCipher* cipher2; - secure_vector<byte> tweak; - }; - -/** -* IEEE P1619 XTS Encryption -*/ -class BOTAN_DLL XTS_Decryption : public Keyed_Filter, - private Buffered_Filter - { - public: - void set_key(const SymmetricKey& key); - void set_iv(const InitializationVector& iv); - - Key_Length_Specification key_spec() const override; - - bool valid_iv_length(size_t iv_len) const - { return (iv_len == cipher->block_size()); } - - std::string name() const; - - XTS_Decryption(BlockCipher* ciph); - - XTS_Decryption(BlockCipher* ciph, - const SymmetricKey& key, - const InitializationVector& iv); - - ~XTS_Decryption() { delete cipher; delete cipher2; } - private: - void write(const byte[], size_t); - void end_msg(); - - void buffered_block(const byte input[], size_t input_length); - void buffered_final(const byte input[], size_t input_length); - - BlockCipher* cipher; - BlockCipher* cipher2; - secure_vector<byte> tweak; - }; - -} - -#endif diff --git a/src/filters/transform_filter.cpp b/src/filters/transform_filter.cpp new file mode 100644 index 000000000..e12328af8 --- /dev/null +++ b/src/filters/transform_filter.cpp @@ -0,0 +1,99 @@ +/* +* Filter interface for Transformations +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/transform_filter.h> + +namespace Botan { + +Transformation_Filter::Transformation_Filter(Transformation* transform) : + Buffered_Filter(transform->update_granularity(), + transform->minimum_final_size()), + m_transform(transform) + { + } + +std::string Transformation_Filter::name() const + { + return m_transform->name(); + } + +void Transformation_Filter::Nonce_State::update(const InitializationVector& iv) + { + m_nonce = unlock(iv.bits_of()); + m_fresh_nonce = true; + } + +std::vector<byte> Transformation_Filter::Nonce_State::get() + { + BOTAN_ASSERT(m_fresh_nonce, "The nonce is fresh for this message"); + + if(!m_nonce.empty()) + m_fresh_nonce = false; + return m_nonce; + } + +void Transformation_Filter::set_iv(const InitializationVector& iv) + { + m_nonce.update(iv); + } + +void Transformation_Filter::set_key(const SymmetricKey& key) + { + m_transform->set_key(key); + } + +Key_Length_Specification Transformation_Filter::key_spec() const + { + return m_transform->key_spec(); + } + +bool Transformation_Filter::valid_iv_length(size_t length) const + { + return m_transform->valid_nonce_length(length); + } + +void Transformation_Filter::write(const byte input[], size_t input_length) + { + Buffered_Filter::write(input, input_length); + } + +void Transformation_Filter::end_msg() + { + Buffered_Filter::end_msg(); + } + +void Transformation_Filter::start_msg() + { + send(m_transform->start_vec(m_nonce.get())); + } + +void Transformation_Filter::buffered_block(const byte input[], size_t input_length) + { + secure_vector<byte> buf; + + while(input_length) + { + const size_t take = std::min(m_transform->update_granularity(), input_length); + + buf.assign(input, input + take); + m_transform->update(buf); + + send(buf); + + input += take; + input_length -= take; + } + } + +void Transformation_Filter::buffered_final(const byte input[], size_t input_length) + { + secure_vector<byte> buf(input, input + input_length); + m_transform->finish(buf); + send(buf); + } + +} diff --git a/src/filters/transform_filter.h b/src/filters/transform_filter.h new file mode 100644 index 000000000..5ad66ba96 --- /dev/null +++ b/src/filters/transform_filter.h @@ -0,0 +1,67 @@ +/* +* Filter interface for Transformations +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_TRANSFORMATION_FILTER_H__ +#define BOTAN_TRANSFORMATION_FILTER_H__ + +#include <botan/transform.h> +#include <botan/key_filt.h> +#include <botan/buf_filt.h> +#include <memory> + +namespace Botan { + +/** +* Filter interface for Transformations +*/ +class BOTAN_DLL Transformation_Filter : public Keyed_Filter, + private Buffered_Filter + { + public: + Transformation_Filter(Transformation* t); + + 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; + + protected: + const Transformation& get_transform() const { return *m_transform; } + + Transformation& get_transform() { return *m_transform; } + + 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<Transformation> m_transform; + + }; + +} + +#endif diff --git a/src/aead/aead.cpp b/src/modes/aead/aead.cpp index 1ec7b4a4a..1ec7b4a4a 100644 --- a/src/aead/aead.cpp +++ b/src/modes/aead/aead.cpp diff --git a/src/modes/aead/aead.h b/src/modes/aead/aead.h new file mode 100644 index 000000000..97f156d60 --- /dev/null +++ b/src/modes/aead/aead.h @@ -0,0 +1,59 @@ +/* +* 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/transform.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 Transformation + { + public: + /** + * Set associated data that is not included in the ciphertext but + * that should be authenticated. Must be called after set_key + * and before finish. + * + * 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; + + template<typename Alloc> + void set_associated_data_vec(const std::vector<byte, Alloc>& ad) + { + set_associated_data(&ad[0], ad.size()); + } + + /** + * Default AEAD nonce size (a commonly supported value among AEAD + * modes, and, large enough that random collisions are unlikely). + */ + size_t default_nonce_size() const override { return 12; } + }; + +/** +* Get an AEAD mode by name (eg "AES-128/GCM" or "Serpent/EAX") +*/ +BOTAN_DLL AEAD_Mode* get_aead(const std::string& name, Cipher_Dir direction); + +} + +#endif diff --git a/src/aead/eax/eax.cpp b/src/modes/aead/eax/eax.cpp index c6aaa9e85..c6aaa9e85 100644 --- a/src/aead/eax/eax.cpp +++ b/src/modes/aead/eax/eax.cpp diff --git a/src/aead/eax/eax.h b/src/modes/aead/eax/eax.h index 6815e3ce0..6815e3ce0 100644 --- a/src/aead/eax/eax.h +++ b/src/modes/aead/eax/eax.h diff --git a/src/aead/eax/info.txt b/src/modes/aead/eax/info.txt index 94924e682..94924e682 100644 --- a/src/aead/eax/info.txt +++ b/src/modes/aead/eax/info.txt diff --git a/src/aead/gcm/gcm.cpp b/src/modes/aead/gcm/gcm.cpp index 7b8e0aa36..7b8e0aa36 100644 --- a/src/aead/gcm/gcm.cpp +++ b/src/modes/aead/gcm/gcm.cpp diff --git a/src/aead/gcm/gcm.h b/src/modes/aead/gcm/gcm.h index e1479c27f..e1479c27f 100644 --- a/src/aead/gcm/gcm.h +++ b/src/modes/aead/gcm/gcm.h diff --git a/src/aead/gcm/info.txt b/src/modes/aead/gcm/info.txt index 698cd0803..698cd0803 100644 --- a/src/aead/gcm/info.txt +++ b/src/modes/aead/gcm/info.txt diff --git a/src/aead/info.txt b/src/modes/aead/info.txt index c2985ea85..c2985ea85 100644 --- a/src/aead/info.txt +++ b/src/modes/aead/info.txt diff --git a/src/aead/ocb/info.txt b/src/modes/aead/ocb/info.txt index 8d6a93ed9..8d6a93ed9 100644 --- a/src/aead/ocb/info.txt +++ b/src/modes/aead/ocb/info.txt diff --git a/src/aead/ocb/ocb.cpp b/src/modes/aead/ocb/ocb.cpp index 4cbd8bde8..4cbd8bde8 100644 --- a/src/aead/ocb/ocb.cpp +++ b/src/modes/aead/ocb/ocb.cpp diff --git a/src/aead/ocb/ocb.h b/src/modes/aead/ocb/ocb.h index ea7729348..ea7729348 100644 --- a/src/aead/ocb/ocb.h +++ b/src/modes/aead/ocb/ocb.h diff --git a/src/filters/modes/xts/info.txt b/src/modes/info.txt index 7327298f9..0dcb0cd59 100644 --- a/src/filters/modes/xts/info.txt +++ b/src/modes/info.txt @@ -1,4 +1,3 @@ -define XTS <requires> block diff --git a/src/modes/xts/info.txt b/src/modes/xts/info.txt new file mode 100644 index 000000000..29b58afe4 --- /dev/null +++ b/src/modes/xts/info.txt @@ -0,0 +1 @@ +define MODE_XTS diff --git a/src/modes/xts/xts.cpp b/src/modes/xts/xts.cpp new file mode 100644 index 000000000..5e10fa8ce --- /dev/null +++ b/src/modes/xts/xts.cpp @@ -0,0 +1,292 @@ +/* +* XTS Mode +* (C) 2009,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/xts.h> +#include <botan/loadstor.h> +#include <botan/internal/xor_buf.h> +#include <botan/internal/rounding.h> + +namespace Botan { + +namespace { + +void poly_double_128(byte out[], const byte in[]) + { + u64bit X0 = load_le<u64bit>(in, 0); + u64bit X1 = load_le<u64bit>(in, 1); + + const bool carry = (X1 >> 63); + + X1 = (X1 << 1) | (X0 >> 63); + X0 = (X0 << 1); + + if(carry) + X0 ^= 0x87; + + store_le(out, X0, X1); + } + +void poly_double_64(byte out[], const byte in[]) + { + u64bit X = load_le<u64bit>(in, 0); + const bool carry = (X >> 63); + X <<= 1; + if(carry) + X ^= 0x1B; + store_le(X, out); + } + +inline void poly_double(byte out[], const byte in[], size_t size) + { + if(size == 8) + poly_double_64(out, in); + else + poly_double_128(out, in); + } + +} + +XTS_Mode::XTS_Mode(BlockCipher* cipher) : m_cipher(cipher) + { + if(m_cipher->block_size() != 8 && m_cipher->block_size() != 16) + throw std::invalid_argument("Bad cipher for XTS: " + cipher->name()); + + m_tweak_cipher.reset(m_cipher->clone()); + m_tweak.resize(update_granularity()); + } + +void XTS_Mode::clear() + { + m_cipher->clear(); + m_tweak_cipher->clear(); + zeroise(m_tweak); + } + +std::string XTS_Mode::name() const + { + return cipher().name() + "/XTS"; + } + +size_t XTS_Mode::update_granularity() const + { + return cipher().parallel_bytes(); + } + +size_t XTS_Mode::minimum_final_size() const + { + return cipher().block_size() + 1; + } + +Key_Length_Specification XTS_Mode::key_spec() const + { + const Key_Length_Specification spec = cipher().key_spec(); + + return Key_Length_Specification(2*spec.minimum_keylength(), + 2*spec.maximum_keylength(), + 2*spec.keylength_multiple()); + } + +size_t XTS_Mode::default_nonce_size() const + { + return cipher().block_size(); + } + +bool XTS_Mode::valid_nonce_length(size_t n) const + { + return cipher().block_size() == n; + } + +void XTS_Mode::key_schedule(const byte key[], size_t length) + { + const size_t key_half = length / 2; + + if(length % 2 == 1 || !m_cipher->valid_keylength(key_half)) + throw Invalid_Key_Length(name(), length); + + m_cipher->set_key(&key[0], key_half); + m_tweak_cipher->set_key(&key[key_half], key_half); + } + +secure_vector<byte> XTS_Mode::start(const byte nonce[], size_t nonce_len) + { + if(!valid_nonce_length(nonce_len)) + throw Invalid_IV_Length(name(), nonce_len); + + const size_t BS = m_tweak_cipher->block_size(); + const size_t blocks_in_tweak = update_granularity() / BS; + + copy_mem(&m_tweak[0], nonce, nonce_len); + m_tweak_cipher->encrypt(&m_tweak[0]); + + update_tweak(0); + + return secure_vector<byte>(); + } + +void XTS_Mode::update_tweak(size_t which) + { + const size_t BS = m_tweak_cipher->block_size(); + + if(which > 0) + poly_double(&m_tweak[0], &m_tweak[(which-1)*BS], BS); + + const size_t blocks_in_tweak = update_granularity() / BS; + + for(size_t i = 1; i < blocks_in_tweak; ++i) + poly_double(&m_tweak[i*BS], &m_tweak[(i-1)*BS], BS); + } + +size_t XTS_Encryption::output_length(size_t input_length) const + { + return round_up(input_length, cipher().block_size()); + } + +void XTS_Encryption::update(secure_vector<byte>& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + byte* buf = &buffer[offset]; + + const size_t BS = cipher().block_size(); + + BOTAN_ASSERT(sz % BS == 0, "Input is full blocks"); + size_t blocks = sz / BS; + + const size_t blocks_in_tweak = update_granularity() / BS; + + while(blocks) + { + const size_t to_proc = std::min(blocks, blocks_in_tweak); + const size_t to_proc_bytes = to_proc * BS; + + xor_buf(buf, tweak(), to_proc_bytes); + cipher().encrypt_n(buf, buf, to_proc); + xor_buf(buf, tweak(), to_proc_bytes); + + buf += to_proc * BS; + blocks -= to_proc; + + update_tweak(to_proc); + } + } + +void XTS_Encryption::finish(secure_vector<byte>& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + byte* buf = &buffer[offset]; + + BOTAN_ASSERT(sz >= minimum_final_size(), "Have sufficient final input"); + + const size_t BS = cipher().block_size(); + + if(sz % BS == 0) + { + update(buffer, offset); + } + else + { + // steal ciphertext + const size_t full_blocks = ((sz / BS) - 1) * BS; + const size_t final_bytes = sz - full_blocks; + BOTAN_ASSERT(final_bytes > BS && final_bytes < 2*BS, "Left over size in expected range"); + + secure_vector<byte> last(buf + full_blocks, buf + full_blocks + final_bytes); + buffer.resize(full_blocks + offset); + update(buffer, offset); + + xor_buf(last, tweak(), BS); + cipher().encrypt(last); + xor_buf(last, tweak(), BS); + + for(size_t i = 0; i != final_bytes - BS; ++i) + std::swap(last[i], last[i + BS]); + + xor_buf(last, tweak() + BS, BS); + cipher().encrypt(last); + xor_buf(last, tweak() + BS, BS); + + buffer += last; + } + } + +size_t XTS_Decryption::output_length(size_t input_length) const + { + // might be less + return input_length; + } + +void XTS_Decryption::update(secure_vector<byte>& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + byte* buf = &buffer[offset]; + + const size_t BS = cipher().block_size(); + + BOTAN_ASSERT(sz % BS == 0, "Input is full blocks"); + size_t blocks = sz / BS; + + const size_t blocks_in_tweak = update_granularity() / BS; + + while(blocks) + { + const size_t to_proc = std::min(blocks, blocks_in_tweak); + const size_t to_proc_bytes = to_proc * BS; + + xor_buf(buf, tweak(), to_proc_bytes); + cipher().decrypt_n(buf, buf, to_proc); + xor_buf(buf, tweak(), to_proc_bytes); + + buf += to_proc * BS; + blocks -= to_proc; + + update_tweak(to_proc); + } + } + +void XTS_Decryption::finish(secure_vector<byte>& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + byte* buf = &buffer[offset]; + + BOTAN_ASSERT(sz >= minimum_final_size(), "Have sufficient final input"); + + const size_t BS = cipher().block_size(); + + if(sz % BS == 0) + { + update(buffer, offset); + } + else + { + // steal ciphertext + const size_t full_blocks = ((sz / BS) - 1) * BS; + const size_t final_bytes = sz - full_blocks; + BOTAN_ASSERT(final_bytes > BS && final_bytes < 2*BS, "Left over size in expected range"); + + secure_vector<byte> last(buf + full_blocks, buf + full_blocks + final_bytes); + buffer.resize(full_blocks + offset); + update(buffer, offset); + + xor_buf(last, tweak() + BS, BS); + cipher().decrypt(last); + xor_buf(last, tweak() + BS, BS); + + for(size_t i = 0; i != final_bytes - BS; ++i) + std::swap(last[i], last[i + BS]); + + xor_buf(last, tweak(), BS); + cipher().decrypt(last); + xor_buf(last, tweak(), BS); + + buffer += last; + } + } + +} diff --git a/src/modes/xts/xts.h b/src/modes/xts/xts.h new file mode 100644 index 000000000..2163bb447 --- /dev/null +++ b/src/modes/xts/xts.h @@ -0,0 +1,86 @@ +/* +* XTS mode, from IEEE P1619 +* (C) 2009,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_MODE_XTS_H__ +#define BOTAN_MODE_XTS_H__ + +#include <botan/transform.h> +#include <botan/block_cipher.h> +#include <memory> + +namespace Botan { + +/** +* IEEE P1619 XTS Mode +*/ +class XTS_Mode : public Transformation + { + public: + std::string name() const override; + + secure_vector<byte> start(const byte nonce[], size_t nonce_len) override; + + size_t update_granularity() const; + + size_t minimum_final_size() const override; + + Key_Length_Specification key_spec() const override; + + size_t default_nonce_size() const override; + + bool valid_nonce_length(size_t n) const override; + + void clear(); + protected: + XTS_Mode(BlockCipher* cipher); + + const byte* tweak() const { return &m_tweak[0]; } + + const BlockCipher& cipher() const { return *m_cipher; } + + void update_tweak(size_t last_used); + + private: + void key_schedule(const byte key[], size_t length) override; + + std::unique_ptr<BlockCipher> m_cipher, m_tweak_cipher; + secure_vector<byte> m_tweak; + }; + +/** +* IEEE P1619 XTS Encryption +*/ +class BOTAN_DLL XTS_Encryption : public XTS_Mode + { + public: + XTS_Encryption(BlockCipher* cipher) : XTS_Mode(cipher) {} + + void update(secure_vector<byte>& blocks, size_t offset) override; + + void finish(secure_vector<byte>& final_block, size_t offset) override; + + size_t output_length(size_t input_length) const override; + }; + +/** +* IEEE P1619 XTS Decryption +*/ +class BOTAN_DLL XTS_Decryption : public XTS_Mode + { + public: + XTS_Decryption(BlockCipher* cipher) : XTS_Mode(cipher) {} + + void update(secure_vector<byte>& blocks, size_t offset) override; + + void finish(secure_vector<byte>& final_block, size_t offset) override; + + size_t output_length(size_t input_length) const override; + }; + +} + +#endif |