diff options
author | lloyd <[email protected]> | 2013-08-15 20:46:15 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2013-08-15 20:46:15 +0000 |
commit | 7328d76b78c3c923c11cc01aa5cf8e5498ea02ff (patch) | |
tree | b62a69987d18d0b8d010329f11f4a72cf0b3ecce | |
parent | 10bab015381aceecdf37bc7c7c325e014f2da676 (diff) |
Convert CTS mode to Transformation API
-rw-r--r-- | src/engine/core_engine/core_modes.cpp | 14 | ||||
-rw-r--r-- | src/filters/modes/cts/cts.cpp | 223 | ||||
-rw-r--r-- | src/filters/modes/cts/cts.h | 86 | ||||
-rw-r--r-- | src/filters/modes/cts/info.txt | 5 | ||||
-rw-r--r-- | src/modes/cbc/cbc.cpp | 129 | ||||
-rw-r--r-- | src/modes/cbc/cbc.h | 38 |
6 files changed, 163 insertions, 332 deletions
diff --git a/src/engine/core_engine/core_modes.cpp b/src/engine/core_engine/core_modes.cpp index e949d5f9b..aa9080c2d 100644 --- a/src/engine/core_engine/core_modes.cpp +++ b/src/engine/core_engine/core_modes.cpp @@ -12,10 +12,6 @@ #include <botan/mode_pad.h> #include <memory> -#if defined(BOTAN_HAS_CTS) - #include <botan/cts.h> -#endif - #if defined(BOTAN_HAS_MODE_CFB) #include <botan/cfb.h> #endif @@ -117,19 +113,15 @@ Keyed_Filter* get_cipher_mode(const BlockCipher* block_cipher, if(mode == "CBC") { +#if defined(BOTAN_HAS_MODE_CBC) if(padding == "CTS") { -#if defined(BOTAN_HAS_CTS) if(direction == ENCRYPTION) - return new CTS_Encryption(block_cipher->clone()); + return new Transformation_Filter(new CTS_Encryption(block_cipher->clone())); else - return new CTS_Decryption(block_cipher->clone()); -#else - return nullptr; -#endif + return new Transformation_Filter(new CTS_Decryption(block_cipher->clone())); } -#if defined(BOTAN_HAS_MODE_CBC) if(direction == ENCRYPTION) return new Transformation_Filter( new CBC_Encryption(block_cipher->clone(), get_bc_pad(padding, "PKCS7"))); diff --git a/src/filters/modes/cts/cts.cpp b/src/filters/modes/cts/cts.cpp deleted file mode 100644 index 0e3c521c3..000000000 --- a/src/filters/modes/cts/cts.cpp +++ /dev/null @@ -1,223 +0,0 @@ -/* -* CTS Mode -* (C) 1999-2007 Jack Lloyd -* -* Distributed under the terms of the Botan license -*/ - -#include <botan/cts.h> -#include <botan/internal/xor_buf.h> -#include <algorithm> - -namespace Botan { - -/* -* CTS Encryption Constructor -*/ -CTS_Encryption::CTS_Encryption(BlockCipher* ciph) : - cipher(ciph) - { - buffer.resize(2 * cipher->block_size()); - state.resize(cipher->block_size()); - position = 0; - } - -/* -* CTS Encryption Constructor -*/ -CTS_Encryption::CTS_Encryption(BlockCipher* ciph, - const SymmetricKey& key, - const InitializationVector& iv) : - cipher(ciph) - { - buffer.resize(2 * cipher->block_size()); - state.resize(cipher->block_size()); - position = 0; - - set_key(key); - set_iv(iv); - } - -/* -* Set the IV -*/ -void CTS_Encryption::set_iv(const InitializationVector& iv) - { - if(!valid_iv_length(iv.length())) - throw Invalid_IV_Length(name(), iv.length()); - - state = iv.bits_of(); - zeroise(buffer); - position = 0; - } - -/* -* Encrypt a block -*/ -void CTS_Encryption::encrypt(const byte block[]) - { - xor_buf(&state[0], &block[0], cipher->block_size()); - cipher->encrypt(state); - send(state, cipher->block_size()); - } - -/* -* Encrypt in CTS mode -*/ -void CTS_Encryption::write(const byte input[], size_t length) - { - size_t copied = std::min<size_t>(buffer.size() - position, length); - buffer_insert(buffer, position, input, copied); - length -= copied; - input += copied; - position += copied; - - if(length == 0) return; - - encrypt(&buffer[0]); - if(length > cipher->block_size()) - { - encrypt(&buffer[cipher->block_size()]); - while(length > 2*cipher->block_size()) - { - encrypt(input); - length -= cipher->block_size(); - input += cipher->block_size(); - } - position = 0; - } - else - { - copy_mem(&buffer[0], &buffer[cipher->block_size()], cipher->block_size()); - position = cipher->block_size(); - } - buffer_insert(buffer, position, input, length); - position += length; - } - -/* -* Finish encrypting in CTS mode -*/ -void CTS_Encryption::end_msg() - { - if(position < cipher->block_size() + 1) - throw Encoding_Error(name() + ": insufficient data to encrypt"); - - xor_buf(state, buffer, cipher->block_size()); - cipher->encrypt(state); - secure_vector<byte> cn = state; - clear_mem(&buffer[position], buffer.size() - position); - encrypt(&buffer[cipher->block_size()]); - send(cn, position - cipher->block_size()); - position = 0; - } - -/* -* CTS Decryption Constructor -*/ -CTS_Decryption::CTS_Decryption(BlockCipher* ciph) : - cipher(ciph) - { - buffer.resize(2 * cipher->block_size()); - state.resize(cipher->block_size()); - temp.resize(cipher->block_size()); - position = 0; - } - -/* -* CTS Decryption Constructor -*/ -CTS_Decryption::CTS_Decryption(BlockCipher* ciph, - const SymmetricKey& key, - const InitializationVector& iv) : - cipher(ciph) - { - buffer.resize(2 * cipher->block_size()); - state.resize(cipher->block_size()); - temp.resize(cipher->block_size()); - position = 0; - - set_key(key); - set_iv(iv); - } - -/* -* Set the IV -*/ -void CTS_Decryption::set_iv(const InitializationVector& iv) - { - if(!valid_iv_length(iv.length())) - throw Invalid_IV_Length(name(), iv.length()); - - state = iv.bits_of(); - zeroise(buffer); - position = 0; - } - -/* -* Decrypt a block -*/ -void CTS_Decryption::decrypt(const byte block[]) - { - cipher->decrypt(block, &temp[0]); - xor_buf(temp, state, cipher->block_size()); - send(temp, cipher->block_size()); - copy_mem(&state[0], block, cipher->block_size()); - } - -/* -* Decrypt in CTS mode -*/ -void CTS_Decryption::write(const byte input[], size_t length) - { - size_t copied = std::min<size_t>(buffer.size() - position, length); - buffer_insert(buffer, position, input, copied); - length -= copied; - input += copied; - position += copied; - - if(length == 0) return; - - decrypt(&buffer[0]); - if(length > cipher->block_size()) - { - decrypt(&buffer[cipher->block_size()]); - while(length > 2*cipher->block_size()) - { - decrypt(input); - length -= cipher->block_size(); - input += cipher->block_size(); - } - position = 0; - } - else - { - copy_mem(&buffer[0], &buffer[cipher->block_size()], cipher->block_size()); - position = cipher->block_size(); - } - buffer_insert(buffer, position, input, length); - position += length; - } - -/* -* Finish decrypting in CTS mode -*/ -void CTS_Decryption::end_msg() - { - cipher->decrypt(&buffer[0], &temp[0]); - xor_buf(&temp[0], &buffer[cipher->block_size()], position - cipher->block_size()); - - secure_vector<byte> xn = temp; - - copy_mem(&buffer[position], - &xn[position - cipher->block_size()], - buffer.size() - position); - - cipher->decrypt(&buffer[cipher->block_size()], &temp[0]); - xor_buf(&temp[0], &state[0], cipher->block_size()); - send(temp, cipher->block_size()); - send(xn, position - cipher->block_size()); - position = 0; - } - -} diff --git a/src/filters/modes/cts/cts.h b/src/filters/modes/cts/cts.h deleted file mode 100644 index b0efb6944..000000000 --- a/src/filters/modes/cts/cts.h +++ /dev/null @@ -1,86 +0,0 @@ -/* -* CTS Mode -* (C) 1999-2007 Jack Lloyd -* -* Distributed under the terms of the Botan license -*/ - -#ifndef BOTAN_CTS_H__ -#define BOTAN_CTS_H__ - -#include <botan/block_cipher.h> -#include <botan/key_filt.h> - -namespace Botan { - -/** -* CBC encryption with ciphertext stealing -*/ -class BOTAN_DLL CTS_Encryption : public Keyed_Filter - { - public: - std::string name() const { return cipher->name() + "/CTS"; } - - void set_iv(const InitializationVector&); - - void set_key(const SymmetricKey& key) { cipher->set_key(key); } - - Key_Length_Specification key_spec() const override { return cipher->key_spec(); } - - bool valid_iv_length(size_t iv_len) const - { return (iv_len == cipher->block_size()); } - - CTS_Encryption(BlockCipher* cipher); - - CTS_Encryption(BlockCipher* cipher, - const SymmetricKey& key, - const InitializationVector& iv); - - ~CTS_Encryption() { delete cipher; } - private: - void write(const byte[], size_t); - void end_msg(); - void encrypt(const byte[]); - - BlockCipher* cipher; - secure_vector<byte> buffer, state; - size_t position; - }; - -/** -* CBC decryption with ciphertext stealing -*/ -class BOTAN_DLL CTS_Decryption : public Keyed_Filter - { - public: - std::string name() const { return cipher->name() + "/CTS"; } - - void set_iv(const InitializationVector&); - - void set_key(const SymmetricKey& key) { cipher->set_key(key); } - - Key_Length_Specification key_spec() const override { return cipher->key_spec(); } - - bool valid_iv_length(size_t iv_len) const - { return (iv_len == cipher->block_size()); } - - CTS_Decryption(BlockCipher* cipher); - - CTS_Decryption(BlockCipher* cipher, - const SymmetricKey& key, - const InitializationVector& iv); - - ~CTS_Decryption() { delete cipher; } - private: - void write(const byte[], size_t); - void end_msg(); - void decrypt(const byte[]); - - BlockCipher* cipher; - secure_vector<byte> buffer, state, temp; - size_t position; - }; - -} - -#endif diff --git a/src/filters/modes/cts/info.txt b/src/filters/modes/cts/info.txt deleted file mode 100644 index 7b590c5cb..000000000 --- a/src/filters/modes/cts/info.txt +++ /dev/null @@ -1,5 +0,0 @@ -define CTS - -<requires> -block -</requires> diff --git a/src/modes/cbc/cbc.cpp b/src/modes/cbc/cbc.cpp index bb7c56858..96e5be6e2 100644 --- a/src/modes/cbc/cbc.cpp +++ b/src/modes/cbc/cbc.cpp @@ -10,6 +10,9 @@ #include <botan/internal/xor_buf.h> #include <botan/internal/rounding.h> +#include <iostream> +#include <botan/hex.h> + namespace Botan { CBC_Mode::CBC_Mode(BlockCipher* cipher, BlockCipherModePaddingMethod* padding) : @@ -17,7 +20,7 @@ CBC_Mode::CBC_Mode(BlockCipher* cipher, BlockCipherModePaddingMethod* padding) : m_padding(padding), m_state(m_cipher->block_size()) { - if(!m_padding->valid_blocksize(cipher->block_size())) + if(m_padding && !m_padding->valid_blocksize(cipher->block_size())) throw std::invalid_argument("Padding " + m_padding->name() + " cannot be used with " + cipher->name() + "/CBC"); @@ -31,7 +34,10 @@ void CBC_Mode::clear() std::string CBC_Mode::name() const { - return cipher().name() + "/CBC/" + padding().name(); + if(m_padding) + return cipher().name() + "/CBC/" + padding().name(); + else + return cipher().name() + "/CBC/CTS"; } size_t CBC_Mode::update_granularity() const @@ -98,7 +104,7 @@ void CBC_Encryption::update(secure_vector<byte>& buffer, size_t offset) if(blocks) { - xor_buf(&buf[0], &state()[0], BS); + xor_buf(&buf[0], state_ptr(), BS); cipher().encrypt(&buf[0]); for(size_t i = 1; i != blocks; ++i) @@ -115,7 +121,6 @@ void CBC_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]; const size_t BS = cipher().block_size(); @@ -142,9 +147,68 @@ void CBC_Encryption::finish(secure_vector<byte>& buffer, size_t offset) update(buffer, offset); } +bool CTS_Encryption::valid_nonce_length(size_t n) const + { + return (n == cipher().block_size()); + } + +size_t CTS_Encryption::minimum_final_size() const + { + return cipher().block_size() + 1; + } + +size_t CTS_Encryption::output_length(size_t input_length) const + { + return input_length; // no ciphertext expansion in CTS + } + +void CTS_Encryption::finish(secure_vector<byte>& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + byte* buf = &buffer[offset]; + const size_t sz = buffer.size() - offset; + + const size_t BS = cipher().block_size(); + + if(sz < BS + 1) + throw Encoding_Error(name() + ": insufficient data to encrypt"); + + if(sz % BS == 0) + { + update(buffer, offset); + + // swap last two blocks + for(size_t i = 0; i != BS; ++i) + std::swap(buffer[buffer.size()-BS+i], buffer[buffer.size()-2*BS+i]); + } + else + { + 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[0], state_ptr(), BS); + cipher().encrypt(&last[0]); + + for(size_t i = 0; i != final_bytes - BS; ++i) + { + std::swap(last[i], last[i + BS]); + last[i] ^= last[i + BS]; + } + + cipher().encrypt(&last[0]); + + buffer += last; + } + } + size_t CBC_Decryption::output_length(size_t input_length) const { - return input_length; + return input_length; // precise for CTS, worst case otherwise } size_t CBC_Decryption::minimum_final_size() const @@ -165,7 +229,7 @@ void CBC_Decryption::update(secure_vector<byte>& buffer, size_t offset) while(blocks) { - const size_t to_proc = std::min(sz, m_tempbuf.size()); + const size_t to_proc = std::min(BS * blocks, m_tempbuf.size()); cipher().decrypt_n(buf, &m_tempbuf[0], to_proc / BS); @@ -196,4 +260,57 @@ void CBC_Decryption::finish(secure_vector<byte>& buffer, size_t offset) buffer.resize(buffer.size() - pad_bytes); // remove padding } +bool CTS_Decryption::valid_nonce_length(size_t n) const + { + return (n == cipher().block_size()); + } + +size_t CTS_Decryption::minimum_final_size() const + { + return cipher().block_size() + 1; + } + +void CTS_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]; + + const size_t BS = cipher().block_size(); + + if(sz < BS + 1) + throw Encoding_Error(name() + ": insufficient data to decrypt"); + + if(sz % BS == 0) + { + // swap last two blocks + for(size_t i = 0; i != BS; ++i) + std::swap(buffer[buffer.size()-BS+i], buffer[buffer.size()-2*BS+i]); + + update(buffer, offset); + } + else + { + 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); + + cipher().decrypt(&last[0]); + xor_buf(&last[0], &last[BS], final_bytes - BS); + + for(size_t i = 0; i != final_bytes - BS; ++i) + std::swap(last[i], last[i + BS]); + + cipher().decrypt(&last[0]); + xor_buf(&last[0], state_ptr(), BS); + + buffer += last; + } + + } + } diff --git a/src/modes/cbc/cbc.h b/src/modes/cbc/cbc.h index add6a206f..68a1f7bcd 100644 --- a/src/modes/cbc/cbc.h +++ b/src/modes/cbc/cbc.h @@ -39,7 +39,11 @@ class CBC_Mode : public Transformation const BlockCipher& cipher() const { return *m_cipher; } - const BlockCipherModePaddingMethod& padding() const { return *m_padding; } + const BlockCipherModePaddingMethod& padding() const + { + BOTAN_ASSERT_NONNULL(m_padding); + return *m_padding; + } secure_vector<byte>& state() { return m_state; } @@ -72,6 +76,23 @@ class BOTAN_DLL CBC_Encryption : public CBC_Mode }; /** +* CBC Encryption with ciphertext stealing (CBC-CS3 variant) +*/ +class BOTAN_DLL CTS_Encryption : public CBC_Encryption + { + public: + CTS_Encryption(BlockCipher* cipher) : CBC_Encryption(cipher, nullptr) {} + + size_t output_length(size_t input_length) const override; + + void finish(secure_vector<byte>& final_block, size_t offset) override; + + size_t minimum_final_size() const override; + + bool valid_nonce_length(size_t n) const; + }; + +/** * CBC Decryption */ class BOTAN_DLL CBC_Decryption : public CBC_Mode @@ -91,6 +112,21 @@ class BOTAN_DLL CBC_Decryption : public CBC_Mode secure_vector<byte> m_tempbuf; }; +/** +* CBC Decryption with ciphertext stealing (CBC-CS3 variant) +*/ +class BOTAN_DLL CTS_Decryption : public CBC_Decryption + { + public: + CTS_Decryption(BlockCipher* cipher) : CBC_Decryption(cipher, nullptr) {} + + void finish(secure_vector<byte>& final_block, size_t offset) override; + + size_t minimum_final_size() const override; + + bool valid_nonce_length(size_t n) const; + }; + } #endif |