diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /comm/third_party/botan/src/lib/modes/cfb | |
parent | Initial commit. (diff) | |
download | thunderbird-upstream.tar.xz thunderbird-upstream.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'comm/third_party/botan/src/lib/modes/cfb')
-rw-r--r-- | comm/third_party/botan/src/lib/modes/cfb/cfb.cpp | 229 | ||||
-rw-r--r-- | comm/third_party/botan/src/lib/modes/cfb/cfb.h | 106 | ||||
-rw-r--r-- | comm/third_party/botan/src/lib/modes/cfb/info.txt | 7 |
3 files changed, 342 insertions, 0 deletions
diff --git a/comm/third_party/botan/src/lib/modes/cfb/cfb.cpp b/comm/third_party/botan/src/lib/modes/cfb/cfb.cpp new file mode 100644 index 0000000000..0c619e322c --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/cfb/cfb.cpp @@ -0,0 +1,229 @@ +/* +* CFB Mode +* (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) +*/ + +#include <botan/cfb.h> + +namespace Botan { + +CFB_Mode::CFB_Mode(BlockCipher* cipher, size_t feedback_bits) : + m_cipher(cipher), + m_block_size(m_cipher->block_size()), + m_feedback_bytes(feedback_bits ? feedback_bits / 8 : m_block_size) + { + if(feedback_bits % 8 || feedback() > cipher->block_size()) + throw Invalid_Argument(name() + ": feedback bits " + + std::to_string(feedback_bits) + " not supported"); + } + +void CFB_Mode::clear() + { + m_cipher->clear(); + m_keystream.clear(); + reset(); + } + +void CFB_Mode::reset() + { + m_state.clear(); + zeroise(m_keystream); + } + +std::string CFB_Mode::name() const + { + if(feedback() == cipher().block_size()) + return cipher().name() + "/CFB"; + else + return cipher().name() + "/CFB(" + std::to_string(feedback()*8) + ")"; + } + +size_t CFB_Mode::output_length(size_t input_length) const + { + return input_length; + } + +size_t CFB_Mode::update_granularity() const + { + return feedback(); + } + +size_t CFB_Mode::minimum_final_size() const + { + return 0; + } + +Key_Length_Specification CFB_Mode::key_spec() const + { + return cipher().key_spec(); + } + +size_t CFB_Mode::default_nonce_length() const + { + return block_size(); + } + +bool CFB_Mode::valid_nonce_length(size_t n) const + { + return (n == 0 || n == block_size()); + } + +void CFB_Mode::key_schedule(const uint8_t key[], size_t length) + { + m_cipher->set_key(key, length); + m_keystream.resize(m_cipher->block_size()); + } + +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); + + verify_key_set(!m_keystream.empty()); + + if(nonce_len == 0) + { + if(m_state.empty()) + { + throw Invalid_State("CFB requires a non-empty initial nonce"); + } + // No reason to encrypt state->keystream_buf, because no change + } + else + { + m_state.assign(nonce, nonce + nonce_len); + cipher().encrypt(m_state, m_keystream); + m_keystream_pos = 0; + } + } + +void CFB_Mode::shift_register() + { + const size_t shift = feedback(); + const size_t carryover = block_size() - shift; + + if(carryover > 0) + { + copy_mem(m_state.data(), &m_state[shift], carryover); + } + copy_mem(&m_state[carryover], m_keystream.data(), shift); + cipher().encrypt(m_state, m_keystream); + m_keystream_pos = 0; + } + +size_t CFB_Encryption::process(uint8_t buf[], size_t sz) + { + verify_key_set(!m_keystream.empty()); + BOTAN_STATE_CHECK(m_state.empty() == false); + + const size_t shift = feedback(); + + size_t left = sz; + + if(m_keystream_pos != 0) + { + const size_t take = std::min<size_t>(left, shift - m_keystream_pos); + + xor_buf(m_keystream.data() + m_keystream_pos, buf, take); + copy_mem(buf, m_keystream.data() + m_keystream_pos, take); + + m_keystream_pos += take; + left -= take; + buf += take; + + if(m_keystream_pos == shift) + { + shift_register(); + } + } + + while(left >= shift) + { + xor_buf(m_keystream.data(), buf, shift); + copy_mem(buf, m_keystream.data(), shift); + + left -= shift; + buf += shift; + shift_register(); + } + + if(left > 0) + { + xor_buf(m_keystream.data(), buf, left); + copy_mem(buf, m_keystream.data(), left); + m_keystream_pos += left; + } + + return sz; + } + +void CFB_Encryption::finish(secure_vector<uint8_t>& buffer, size_t offset) + { + update(buffer, offset); + } + +namespace { + +inline void xor_copy(uint8_t buf[], uint8_t key_buf[], size_t len) + { + for(size_t i = 0; i != len; ++i) + { + uint8_t k = key_buf[i]; + key_buf[i] = buf[i]; + buf[i] ^= k; + } + } + +} + +size_t CFB_Decryption::process(uint8_t buf[], size_t sz) + { + verify_key_set(!m_keystream.empty()); + BOTAN_STATE_CHECK(m_state.empty() == false); + + const size_t shift = feedback(); + + size_t left = sz; + + if(m_keystream_pos != 0) + { + const size_t take = std::min<size_t>(left, shift - m_keystream_pos); + + xor_copy(buf, m_keystream.data() + m_keystream_pos, take); + + m_keystream_pos += take; + left -= take; + buf += take; + + if(m_keystream_pos == shift) + { + shift_register(); + } + } + + while(left >= shift) + { + xor_copy(buf, m_keystream.data(), shift); + left -= shift; + buf += shift; + shift_register(); + } + + if(left > 0) + { + xor_copy(buf, m_keystream.data(), left); + m_keystream_pos += left; + } + + return sz; + } + +void CFB_Decryption::finish(secure_vector<uint8_t>& buffer, size_t offset) + { + update(buffer, offset); + } + +} diff --git a/comm/third_party/botan/src/lib/modes/cfb/cfb.h b/comm/third_party/botan/src/lib/modes/cfb/cfb.h new file mode 100644 index 0000000000..1f9e554872 --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/cfb/cfb.h @@ -0,0 +1,106 @@ +/* +* CFB mode +* (C) 1999-2007,2013 Jack Lloyd +* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MODE_CFB_H_ +#define BOTAN_MODE_CFB_H_ + +#include <botan/cipher_mode.h> +#include <botan/block_cipher.h> + +BOTAN_FUTURE_INTERNAL_HEADER(cfb.h) + +namespace Botan { + +/** +* CFB Mode +*/ +class BOTAN_PUBLIC_API(2,0) CFB_Mode : public Cipher_Mode + { + public: + std::string name() const override final; + + size_t update_granularity() const override final; + + size_t minimum_final_size() const override final; + + Key_Length_Specification key_spec() const override final; + + size_t output_length(size_t input_length) const override final; + + size_t default_nonce_length() const override final; + + bool valid_nonce_length(size_t n) const override final; + + void clear() override final; + + void reset() override final; + protected: + CFB_Mode(BlockCipher* cipher, size_t feedback_bits); + + void shift_register(); + + size_t feedback() const { return m_feedback_bytes; } + const BlockCipher& cipher() const { return *m_cipher; } + size_t block_size() const { return m_block_size; } + + secure_vector<uint8_t> m_state; + secure_vector<uint8_t> m_keystream; + size_t m_keystream_pos = 0; + + private: + void start_msg(const uint8_t nonce[], size_t nonce_len) override; + void key_schedule(const uint8_t key[], size_t length) override; + + std::unique_ptr<BlockCipher> m_cipher; + const size_t m_block_size; + const size_t m_feedback_bytes; + }; + +/** +* CFB Encryption +*/ +class BOTAN_PUBLIC_API(2,0) CFB_Encryption final : public CFB_Mode + { + public: + /** + * If feedback_bits is zero, cipher->block_size() bytes will be used. + * @param cipher block cipher to use + * @param feedback_bits number of bits fed back into the shift register, + * must be a multiple of 8 + */ + CFB_Encryption(BlockCipher* cipher, size_t feedback_bits) : + CFB_Mode(cipher, feedback_bits) {} + + size_t process(uint8_t buf[], size_t size) override; + + void finish(secure_vector<uint8_t>& final_block, size_t offset = 0) override; + }; + +/** +* CFB Decryption +*/ +class BOTAN_PUBLIC_API(2,0) CFB_Decryption final : public CFB_Mode + { + public: + /** + * If feedback_bits is zero, cipher->block_size() bytes will be used. + * @param cipher block cipher to use + * @param feedback_bits number of bits fed back into the shift register, + * must be a multiple of 8 + */ + CFB_Decryption(BlockCipher* cipher, size_t feedback_bits) : + CFB_Mode(cipher, feedback_bits) {} + + size_t process(uint8_t buf[], size_t size) override; + + void finish(secure_vector<uint8_t>& final_block, size_t offset = 0) override; + }; + +} + +#endif diff --git a/comm/third_party/botan/src/lib/modes/cfb/info.txt b/comm/third_party/botan/src/lib/modes/cfb/info.txt new file mode 100644 index 0000000000..77a6af448e --- /dev/null +++ b/comm/third_party/botan/src/lib/modes/cfb/info.txt @@ -0,0 +1,7 @@ +<defines> +MODE_CFB -> 20131128 +</defines> + +<requires> +block +</requires> |