aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorlloyd <[email protected]>2013-08-15 20:46:15 +0000
committerlloyd <[email protected]>2013-08-15 20:46:15 +0000
commit7328d76b78c3c923c11cc01aa5cf8e5498ea02ff (patch)
treeb62a69987d18d0b8d010329f11f4a72cf0b3ecce
parent10bab015381aceecdf37bc7c7c325e014f2da676 (diff)
Convert CTS mode to Transformation API
-rw-r--r--src/engine/core_engine/core_modes.cpp14
-rw-r--r--src/filters/modes/cts/cts.cpp223
-rw-r--r--src/filters/modes/cts/cts.h86
-rw-r--r--src/filters/modes/cts/info.txt5
-rw-r--r--src/modes/cbc/cbc.cpp129
-rw-r--r--src/modes/cbc/cbc.h38
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