diff options
author | Jack Lloyd <[email protected]> | 2017-05-13 10:54:51 -0400 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2017-05-13 10:54:51 -0400 |
commit | 2914fcfb736b0a156ee14e4775a587ad92171ca3 (patch) | |
tree | 272492e1e76cb68d8d08ae425f6a36a5e003c2b7 /src/lib | |
parent | 2c5919cd5aa3d7723919f729cab9938df1cc4f94 (diff) |
Handle IV carryover in CBC, CFB, and stream ciphers
Allow an empty nonce to mean "continue using the current cipher state".
GH #864
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/block/aes/aes_ni/aes_ni.cpp | 12 | ||||
-rw-r--r-- | src/lib/filters/cipher_filter.cpp | 25 | ||||
-rw-r--r-- | src/lib/filters/cipher_filter.h | 14 | ||||
-rw-r--r-- | src/lib/modes/cbc/cbc.cpp | 2 | ||||
-rw-r--r-- | src/lib/modes/cfb/cfb.cpp | 15 | ||||
-rw-r--r-- | src/lib/modes/stream_mode.h | 5 |
6 files changed, 38 insertions, 35 deletions
diff --git a/src/lib/block/aes/aes_ni/aes_ni.cpp b/src/lib/block/aes/aes_ni/aes_ni.cpp index 52f4e44a2..65c1dc300 100644 --- a/src/lib/block/aes/aes_ni/aes_ni.cpp +++ b/src/lib/block/aes/aes_ni/aes_ni.cpp @@ -109,6 +109,8 @@ __m128i aes_256_key_expansion(__m128i key, __m128i key2) BOTAN_FUNC_ISA("ssse3,aes") void AES_128::aesni_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + BOTAN_ASSERT(m_EK.empty() == false, "Key was set"); + const __m128i* in_mm = reinterpret_cast<const __m128i*>(in); __m128i* out_mm = reinterpret_cast<__m128i*>(out); @@ -186,6 +188,8 @@ void AES_128::aesni_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) BOTAN_FUNC_ISA("ssse3,aes") void AES_128::aesni_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + BOTAN_ASSERT(m_DK.empty() == false, "Key was set"); + const __m128i* in_mm = reinterpret_cast<const __m128i*>(in); __m128i* out_mm = reinterpret_cast<__m128i*>(out); @@ -316,6 +320,8 @@ void AES_128::aesni_key_schedule(const uint8_t key[], size_t) BOTAN_FUNC_ISA("ssse3,aes") void AES_192::aesni_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + BOTAN_ASSERT(m_EK.empty() == false, "Key was set"); + const __m128i* in_mm = reinterpret_cast<const __m128i*>(in); __m128i* out_mm = reinterpret_cast<__m128i*>(out); @@ -399,6 +405,8 @@ void AES_192::aesni_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) BOTAN_FUNC_ISA("ssse3,aes") void AES_192::aesni_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + BOTAN_ASSERT(m_DK.empty() == false, "Key was set"); + const __m128i* in_mm = reinterpret_cast<const __m128i*>(in); __m128i* out_mm = reinterpret_cast<__m128i*>(out); @@ -532,6 +540,8 @@ void AES_192::aesni_key_schedule(const uint8_t key[], size_t) BOTAN_FUNC_ISA("ssse3,aes") void AES_256::aesni_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + BOTAN_ASSERT(m_EK.empty() == false, "Key was set"); + const __m128i* in_mm = reinterpret_cast<const __m128i*>(in); __m128i* out_mm = reinterpret_cast<__m128i*>(out); @@ -621,6 +631,8 @@ void AES_256::aesni_encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) BOTAN_FUNC_ISA("ssse3,aes") void AES_256::aesni_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const { + BOTAN_ASSERT(m_DK.empty() == false, "Key was set"); + const __m128i* in_mm = reinterpret_cast<const __m128i*>(in); __m128i* out_mm = reinterpret_cast<__m128i*>(out); diff --git a/src/lib/filters/cipher_filter.cpp b/src/lib/filters/cipher_filter.cpp index 1f3476694..646e596d8 100644 --- a/src/lib/filters/cipher_filter.cpp +++ b/src/lib/filters/cipher_filter.cpp @@ -1,6 +1,6 @@ /* * Filter interface for Cipher_Modes -* (C) 2013,2014 Jack Lloyd +* (C) 2013,2014,2017 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ @@ -38,24 +38,9 @@ std::string Cipher_Mode_Filter::name() const return m_mode->name(); } -void Cipher_Mode_Filter::Nonce_State::update(const InitializationVector& iv) - { - m_nonce = unlock(iv.bits_of()); - m_fresh_nonce = true; - } - -std::vector<uint8_t> Cipher_Mode_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 Cipher_Mode_Filter::set_iv(const InitializationVector& iv) { - m_nonce.update(iv); + m_nonce = unlock(iv.bits_of()); } void Cipher_Mode_Filter::set_key(const SymmetricKey& key) @@ -85,7 +70,11 @@ void Cipher_Mode_Filter::end_msg() void Cipher_Mode_Filter::start_msg() { - m_mode->start(m_nonce.get()); + if(m_nonce.empty() && !m_mode->valid_nonce_length(0)) + throw Invalid_State("Cipher " + m_mode->name() + " requires a fresh nonce for each message"); + + m_mode->start(m_nonce); + m_nonce.clear(); } void Cipher_Mode_Filter::buffered_block(const uint8_t input[], size_t input_length) diff --git a/src/lib/filters/cipher_filter.h b/src/lib/filters/cipher_filter.h index 1675a15d7..eae70d9c0 100644 --- a/src/lib/filters/cipher_filter.h +++ b/src/lib/filters/cipher_filter.h @@ -46,20 +46,8 @@ class BOTAN_DLL Cipher_Mode_Filter : public Keyed_Filter, void buffered_block(const uint8_t input[], size_t input_length) override; void buffered_final(const uint8_t input[], size_t input_length) override; - class Nonce_State - { - public: - explicit Nonce_State(bool allow_null_nonce) : m_fresh_nonce(allow_null_nonce) {} - - void update(const InitializationVector& iv); - std::vector<uint8_t> get(); - private: - bool m_fresh_nonce; - std::vector<uint8_t> m_nonce; - }; - - Nonce_State m_nonce; std::unique_ptr<Cipher_Mode> m_mode; + std::vector<uint8_t> m_nonce; secure_vector<uint8_t> m_buffer; }; diff --git a/src/lib/modes/cbc/cbc.cpp b/src/lib/modes/cbc/cbc.cpp index 188b4a0aa..fbe56da82 100644 --- a/src/lib/modes/cbc/cbc.cpp +++ b/src/lib/modes/cbc/cbc.cpp @@ -1,6 +1,6 @@ /* * CBC Mode -* (C) 1999-2007,2013 Jack Lloyd +* (C) 1999-2007,2013,2017 Jack Lloyd * (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) diff --git a/src/lib/modes/cfb/cfb.cpp b/src/lib/modes/cfb/cfb.cpp index 148e16c6c..56d234090 100644 --- a/src/lib/modes/cfb/cfb.cpp +++ b/src/lib/modes/cfb/cfb.cpp @@ -67,7 +67,7 @@ size_t CFB_Mode::default_nonce_length() const bool CFB_Mode::valid_nonce_length(size_t n) const { - return (n == cipher().block_size()); + return (n == 0 || n == cipher().block_size()); } void CFB_Mode::key_schedule(const uint8_t key[], size_t length) @@ -80,7 +80,18 @@ void CFB_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) if(!valid_nonce_length(nonce_len)) throw Invalid_IV_Length(name(), nonce_len); - m_shift_register.assign(nonce, nonce + nonce_len); + if(nonce_len == 0) + { + if(m_shift_register.empty()) + { + throw Invalid_State("CFB requires a non-empty initial nonce"); + } + } + else + { + m_shift_register.assign(nonce, nonce + nonce_len); + } + m_keystream_buf.resize(m_shift_register.size()); cipher().encrypt(m_shift_register, m_keystream_buf); } diff --git a/src/lib/modes/stream_mode.h b/src/lib/modes/stream_mode.h index e32044a4b..27a94a7c7 100644 --- a/src/lib/modes/stream_mode.h +++ b/src/lib/modes/stream_mode.h @@ -56,7 +56,10 @@ class BOTAN_DLL Stream_Cipher_Mode : public Cipher_Mode private: void start_msg(const uint8_t nonce[], size_t nonce_len) override { - m_cipher->set_iv(nonce, nonce_len); + if(nonce_len > 0) + { + m_cipher->set_iv(nonce, nonce_len); + } } void key_schedule(const uint8_t key[], size_t length) override |