diff options
-rw-r--r-- | checks/bench.cpp | 4 | ||||
-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 | 100 | ||||
-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 (renamed from src/aead/aead.h) | 0 | ||||
-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 | 321 | ||||
-rw-r--r-- | src/modes/xts/xts.h | 86 |
26 files changed, 591 insertions, 654 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/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..e5820585f --- /dev/null +++ b/src/filters/transform_filter.cpp @@ -0,0 +1,100 @@ +/* +* 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) + { + printf("set_iv\n"); + 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/aead/aead.h b/src/modes/aead/aead.h index 97f156d60..97f156d60 100644 --- a/src/aead/aead.h +++ b/src/modes/aead/aead.h 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..b4e266c21 --- /dev/null +++ b/src/modes/xts/xts.cpp @@ -0,0 +1,321 @@ +/* +* XTS Mode +* (C) 2009,2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/xts.h> +#include <botan/internal/xor_buf.h> +#include <botan/internal/rounding.h> + +namespace Botan { + +namespace { + +void poly_double(byte tweak[], size_t size) + { + // Use u64bits here? + 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_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 + { + /* XTS needs to process at least 2 blocks in parallel + because block_size+1 bytes are needed at the end + */ + return std::max<size_t>(cipher().parallel_bytes(), 2 * cipher().block_size()); + } + +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); + + for(size_t i = 1; i < blocks_in_tweak; ++i) + { + copy_mem(&m_tweak[i*BS], &m_tweak[(i-1)*BS], BS); + poly_double(&m_tweak[i*BS], BS); + } + + return secure_vector<byte>(); + } + +void XTS_Mode::update_tweak(size_t which) + { + const size_t BS = m_tweak_cipher->block_size(); + + //if(which > 0) + copy_mem(&m_tweak[0], &m_tweak[(which-1)*BS], BS); + poly_double(&m_tweak[0], BS); + + const size_t blocks_in_tweak = update_granularity() / BS; + + for(size_t i = 1; i < blocks_in_tweak; ++i) + { + copy_mem(&m_tweak[i*BS], &m_tweak[(i-1)*BS], BS); + poly_double(&m_tweak[i*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; + } + } + +/* +void XTS_Decryption::buffered_final(const byte input[], size_t length) + { + size_t leftover_blocks = + ((length / BS) - 1) * BS; + + 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[BS]); + + poly_double(&tweak_copy[0], BS); + + xor_buf(temp, tweak_copy, BS); + cipher->decrypt(temp); + xor_buf(temp, tweak_copy, BS); + + for(size_t i = 0; i != length - BS; ++i) + std::swap(temp[i], temp[i + BS]); + + xor_buf(temp, tweak, BS); + cipher->decrypt(temp); + xor_buf(temp, tweak, BS); + + send(temp, length); + } + + buffer_reset(); + } +*/ + +} 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 |