diff options
Diffstat (limited to 'src/libs/3rdparty/botan/src/lib/modes')
-rw-r--r-- | src/libs/3rdparty/botan/src/lib/modes/cbc/cbc.cpp | 312 | ||||
-rw-r--r-- | src/libs/3rdparty/botan/src/lib/modes/cbc/cbc.h | 154 | ||||
-rw-r--r-- | src/libs/3rdparty/botan/src/lib/modes/cbc/info.txt | 8 | ||||
-rw-r--r-- | src/libs/3rdparty/botan/src/lib/modes/cipher_mode.cpp | 188 | ||||
-rw-r--r-- | src/libs/3rdparty/botan/src/lib/modes/cipher_mode.h | 257 | ||||
-rw-r--r-- | src/libs/3rdparty/botan/src/lib/modes/info.txt | 9 | ||||
-rw-r--r-- | src/libs/3rdparty/botan/src/lib/modes/mode_pad/info.txt | 3 | ||||
-rw-r--r-- | src/libs/3rdparty/botan/src/lib/modes/mode_pad/mode_pad.cpp | 196 | ||||
-rw-r--r-- | src/libs/3rdparty/botan/src/lib/modes/mode_pad/mode_pad.h | 159 | ||||
-rw-r--r-- | src/libs/3rdparty/botan/src/lib/modes/stream_mode.h | 82 |
10 files changed, 1368 insertions, 0 deletions
diff --git a/src/libs/3rdparty/botan/src/lib/modes/cbc/cbc.cpp b/src/libs/3rdparty/botan/src/lib/modes/cbc/cbc.cpp new file mode 100644 index 0000000000..c67664a6e7 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/modes/cbc/cbc.cpp @@ -0,0 +1,312 @@ +/* +* CBC 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/cbc.h> +#include <botan/mode_pad.h> +#include <botan/internal/rounding.h> + +namespace Botan { + +CBC_Mode::CBC_Mode(BlockCipher* cipher, BlockCipherModePaddingMethod* padding) : + m_cipher(cipher), + m_padding(padding), + m_state(m_cipher->block_size()) + { + if(m_padding && !m_padding->valid_blocksize(cipher->block_size())) + throw Invalid_Argument("Padding " + m_padding->name() + + " cannot be used with " + + cipher->name() + "/CBC"); + } + +void CBC_Mode::clear() + { + m_cipher->clear(); + reset(); + } + +void CBC_Mode::reset() + { + zeroise(m_state); + } + +std::string CBC_Mode::name() const + { + if(m_padding) + return cipher().name() + "/CBC/" + padding().name(); + else + return cipher().name() + "/CBC/CTS"; + } + +size_t CBC_Mode::update_granularity() const + { + return cipher().parallel_bytes(); + } + +Key_Length_Specification CBC_Mode::key_spec() const + { + return cipher().key_spec(); + } + +size_t CBC_Mode::default_nonce_length() const + { + return block_size(); + } + +bool CBC_Mode::valid_nonce_length(size_t n) const + { + return (n == 0 || n == block_size()); + } + +void CBC_Mode::key_schedule(const uint8_t key[], size_t length) + { + m_cipher->set_key(key, length); + } + +void CBC_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) + { + if(!valid_nonce_length(nonce_len)) + throw Invalid_IV_Length(name(), nonce_len); + + /* + * A nonce of zero length means carry the last ciphertext value over + * as the new IV, as unfortunately some protocols require this. If + * this is the first message then we use an IV of all zeros. + */ + if(nonce_len) + m_state.assign(nonce, nonce + nonce_len); + } + +size_t CBC_Encryption::minimum_final_size() const + { + return 0; + } + +size_t CBC_Encryption::output_length(size_t input_length) const + { + if(input_length == 0) + return block_size(); + else + return round_up(input_length, block_size()); + } + +size_t CBC_Encryption::process(uint8_t buf[], size_t sz) + { + const size_t BS = block_size(); + + BOTAN_ASSERT(sz % BS == 0, "CBC input is full blocks"); + const size_t blocks = sz / BS; + + if(blocks > 0) + { + xor_buf(&buf[0], state_ptr(), BS); + cipher().encrypt(&buf[0]); + + for(size_t i = 1; i != blocks; ++i) + { + xor_buf(&buf[BS*i], &buf[BS*(i-1)], BS); + cipher().encrypt(&buf[BS*i]); + } + + state().assign(&buf[BS*(blocks-1)], &buf[BS*blocks]); + } + + return sz; + } + +void CBC_Encryption::finish(secure_vector<uint8_t>& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + + const size_t BS = block_size(); + + const size_t bytes_in_final_block = (buffer.size()-offset) % BS; + + padding().add_padding(buffer, bytes_in_final_block, BS); + + if((buffer.size()-offset) % BS) + throw Exception("Did not pad to full block size in " + name()); + + update(buffer, offset); + } + +bool CTS_Encryption::valid_nonce_length(size_t n) const + { + return (n == block_size()); + } + +size_t CTS_Encryption::minimum_final_size() const + { + return 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<uint8_t>& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + uint8_t* buf = buffer.data() + offset; + const size_t sz = buffer.size() - offset; + + const size_t BS = 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<uint8_t> last(buf + full_blocks, buf + full_blocks + final_bytes); + buffer.resize(full_blocks + offset); + update(buffer, offset); + + xor_buf(last.data(), state_ptr(), BS); + cipher().encrypt(last.data()); + + for(size_t i = 0; i != final_bytes - BS; ++i) + { + last[i] ^= last[i + BS]; + last[i + BS] ^= last[i]; + } + + cipher().encrypt(last.data()); + + buffer += last; + } + } + +size_t CBC_Decryption::output_length(size_t input_length) const + { + return input_length; // precise for CTS, worst case otherwise + } + +size_t CBC_Decryption::minimum_final_size() const + { + return block_size(); + } + +size_t CBC_Decryption::process(uint8_t buf[], size_t sz) + { + const size_t BS = block_size(); + + BOTAN_ASSERT(sz % BS == 0, "Input is full blocks"); + size_t blocks = sz / BS; + + while(blocks) + { + const size_t to_proc = std::min(BS * blocks, m_tempbuf.size()); + + cipher().decrypt_n(buf, m_tempbuf.data(), to_proc / BS); + + xor_buf(m_tempbuf.data(), state_ptr(), BS); + xor_buf(&m_tempbuf[BS], buf, to_proc - BS); + copy_mem(state_ptr(), buf + (to_proc - BS), BS); + + copy_mem(buf, m_tempbuf.data(), to_proc); + + buf += to_proc; + blocks -= to_proc / BS; + } + + return sz; + } + +void CBC_Decryption::finish(secure_vector<uint8_t>& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + + const size_t BS = block_size(); + + if(sz == 0 || sz % BS) + throw Decoding_Error(name() + ": Ciphertext not a multiple of block size"); + + update(buffer, offset); + + const size_t pad_bytes = BS - padding().unpad(&buffer[buffer.size()-BS], BS); + buffer.resize(buffer.size() - pad_bytes); // remove padding + if(pad_bytes == 0 && padding().name() != "NoPadding") + { + throw Decoding_Error(name()); + } + } + +void CBC_Decryption::reset() + { + zeroise(state()); + zeroise(m_tempbuf); + } + +bool CTS_Decryption::valid_nonce_length(size_t n) const + { + return (n == block_size()); + } + +size_t CTS_Decryption::minimum_final_size() const + { + return block_size() + 1; + } + +void CTS_Decryption::finish(secure_vector<uint8_t>& buffer, size_t offset) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + const size_t sz = buffer.size() - offset; + uint8_t* buf = buffer.data() + offset; + + const size_t BS = 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<uint8_t> last(buf + full_blocks, buf + full_blocks + final_bytes); + buffer.resize(full_blocks + offset); + update(buffer, offset); + + cipher().decrypt(last.data()); + + xor_buf(last.data(), &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.data()); + xor_buf(last.data(), state_ptr(), BS); + + buffer += last; + } + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/modes/cbc/cbc.h b/src/libs/3rdparty/botan/src/lib/modes/cbc/cbc.h new file mode 100644 index 0000000000..65b6395115 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/modes/cbc/cbc.h @@ -0,0 +1,154 @@ +/* +* CBC 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_CBC_H_ +#define BOTAN_MODE_CBC_H_ + +#include <botan/cipher_mode.h> +#include <botan/block_cipher.h> +#include <botan/mode_pad.h> + +namespace Botan { + +/** +* CBC Mode +*/ +class BOTAN_PUBLIC_API(2,0) CBC_Mode : public Cipher_Mode + { + public: + std::string name() const override; + + size_t update_granularity() const override; + + Key_Length_Specification key_spec() const override; + + size_t default_nonce_length() const override; + + bool valid_nonce_length(size_t n) const override; + + void clear() override; + + void reset() override; + + protected: + CBC_Mode(BlockCipher* cipher, BlockCipherModePaddingMethod* padding); + + const BlockCipher& cipher() const { return *m_cipher; } + + const BlockCipherModePaddingMethod& padding() const + { + BOTAN_ASSERT_NONNULL(m_padding); + return *m_padding; + } + + secure_vector<uint8_t>& state() { return m_state; } + + size_t block_size() const { return m_state.size(); } + + uint8_t* state_ptr() { return m_state.data(); } + + 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; + std::unique_ptr<BlockCipherModePaddingMethod> m_padding; + secure_vector<uint8_t> m_state; + }; + +/** +* CBC Encryption +*/ +class BOTAN_PUBLIC_API(2,0) CBC_Encryption : public CBC_Mode + { + public: + /** + * @param cipher block cipher to use + * @param padding padding method to use + */ + CBC_Encryption(BlockCipher* cipher, BlockCipherModePaddingMethod* padding) : + CBC_Mode(cipher, padding) {} + + size_t process(uint8_t buf[], size_t size) override; + + void finish(secure_vector<uint8_t>& final_block, size_t offset = 0) override; + + size_t output_length(size_t input_length) const override; + + size_t minimum_final_size() const override; + }; + +/** +* CBC Encryption with ciphertext stealing (CBC-CS3 variant) +*/ +class BOTAN_PUBLIC_API(2,0) CTS_Encryption final : public CBC_Encryption + { + public: + /** + * @param cipher block cipher to use + */ + explicit CTS_Encryption(BlockCipher* cipher) : CBC_Encryption(cipher, nullptr) {} + + size_t output_length(size_t input_length) const override; + + void finish(secure_vector<uint8_t>& final_block, size_t offset = 0) override; + + size_t minimum_final_size() const override; + + bool valid_nonce_length(size_t n) const override; + }; + +/** +* CBC Decryption +*/ +class BOTAN_PUBLIC_API(2,0) CBC_Decryption : public CBC_Mode + { + public: + /** + * @param cipher block cipher to use + * @param padding padding method to use + */ + CBC_Decryption(BlockCipher* cipher, BlockCipherModePaddingMethod* padding) : + CBC_Mode(cipher, padding), m_tempbuf(update_granularity()) {} + + size_t process(uint8_t buf[], size_t size) override; + + void finish(secure_vector<uint8_t>& final_block, size_t offset = 0) override; + + size_t output_length(size_t input_length) const override; + + size_t minimum_final_size() const override; + + void reset() override; + + private: + secure_vector<uint8_t> m_tempbuf; + }; + +/** +* CBC Decryption with ciphertext stealing (CBC-CS3 variant) +*/ +class BOTAN_PUBLIC_API(2,0) CTS_Decryption final : public CBC_Decryption + { + public: + /** + * @param cipher block cipher to use + */ + explicit CTS_Decryption(BlockCipher* cipher) : CBC_Decryption(cipher, nullptr) {} + + void finish(secure_vector<uint8_t>& final_block, size_t offset = 0) override; + + size_t minimum_final_size() const override; + + bool valid_nonce_length(size_t n) const override; + }; + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/modes/cbc/info.txt b/src/libs/3rdparty/botan/src/lib/modes/cbc/info.txt new file mode 100644 index 0000000000..778ba1e252 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/modes/cbc/info.txt @@ -0,0 +1,8 @@ +<defines> +MODE_CBC -> 20131128 +</defines> + +<requires> +block +mode_pad +</requires> diff --git a/src/libs/3rdparty/botan/src/lib/modes/cipher_mode.cpp b/src/libs/3rdparty/botan/src/lib/modes/cipher_mode.cpp new file mode 100644 index 0000000000..00d7a4db08 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/modes/cipher_mode.cpp @@ -0,0 +1,188 @@ +/* +* Cipher Modes +* (C) 2015 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/cipher_mode.h> +#include <botan/stream_mode.h> +#include <botan/scan_name.h> +#include <botan/parsing.h> +#include <sstream> + +#if defined(BOTAN_HAS_BLOCK_CIPHER) + #include <botan/block_cipher.h> +#endif + +#if defined(BOTAN_HAS_AEAD_MODES) + #include <botan/aead.h> +#endif + +#if defined(BOTAN_HAS_MODE_CBC) + #include <botan/cbc.h> +#endif + +#if defined(BOTAN_HAS_MODE_CFB) + #include <botan/cfb.h> +#endif + +#if defined(BOTAN_HAS_MODE_XTS) + #include <botan/xts.h> +#endif + +#if defined(BOTAN_HAS_OPENSSL) + #include <botan/internal/openssl.h> +#endif + +namespace Botan { + +std::unique_ptr<Cipher_Mode> Cipher_Mode::create_or_throw(const std::string& algo, + Cipher_Dir direction, + const std::string& provider) + { + if(auto mode = Cipher_Mode::create(algo, direction, provider)) + return mode; + + throw Lookup_Error("Cipher mode", algo, provider); + } + +std::unique_ptr<Cipher_Mode> Cipher_Mode::create(const std::string& algo, + Cipher_Dir direction, + const std::string& provider) + { +#if defined(BOTAN_HAS_OPENSSL) + if(provider.empty() || provider == "openssl") + { + std::unique_ptr<Cipher_Mode> openssl_cipher(make_openssl_cipher_mode(algo, direction)); + + if(openssl_cipher) + return openssl_cipher; + + if(!provider.empty()) + return std::unique_ptr<Cipher_Mode>(); + } +#endif + +#if defined(BOTAN_HAS_STREAM_CIPHER) + if(auto sc = StreamCipher::create(algo)) + { + return std::unique_ptr<Cipher_Mode>(new Stream_Cipher_Mode(sc.release())); + } +#endif + +#if defined(BOTAN_HAS_AEAD_MODES) + if(auto aead = AEAD_Mode::create(algo, direction)) + { + return std::unique_ptr<Cipher_Mode>(aead.release()); + } +#endif + + if(algo.find('/') != std::string::npos) + { + const std::vector<std::string> algo_parts = split_on(algo, '/'); + const std::string cipher_name = algo_parts[0]; + const std::vector<std::string> mode_info = parse_algorithm_name(algo_parts[1]); + + if(mode_info.empty()) + return std::unique_ptr<Cipher_Mode>(); + + std::ostringstream alg_args; + + alg_args << '(' << cipher_name; + for(size_t i = 1; i < mode_info.size(); ++i) + alg_args << ',' << mode_info[i]; + for(size_t i = 2; i < algo_parts.size(); ++i) + alg_args << ',' << algo_parts[i]; + alg_args << ')'; + + const std::string mode_name = mode_info[0] + alg_args.str(); + return Cipher_Mode::create(mode_name, direction, provider); + } + +#if defined(BOTAN_HAS_BLOCK_CIPHER) + + SCAN_Name spec(algo); + + if(spec.arg_count() == 0) + { + return std::unique_ptr<Cipher_Mode>(); + } + + std::unique_ptr<BlockCipher> bc(BlockCipher::create(spec.arg(0), provider)); + + if(!bc) + { + return std::unique_ptr<Cipher_Mode>(); + } + +#if defined(BOTAN_HAS_MODE_CBC) + if(spec.algo_name() == "CBC") + { + const std::string padding = spec.arg(1, "PKCS7"); + + if(padding == "CTS") + { + if(direction == ENCRYPTION) + return std::unique_ptr<Cipher_Mode>(new CTS_Encryption(bc.release())); + else + return std::unique_ptr<Cipher_Mode>(new CTS_Decryption(bc.release())); + } + else + { + std::unique_ptr<BlockCipherModePaddingMethod> pad(get_bc_pad(padding)); + + if(pad) + { + if(direction == ENCRYPTION) + return std::unique_ptr<Cipher_Mode>(new CBC_Encryption(bc.release(), pad.release())); + else + return std::unique_ptr<Cipher_Mode>(new CBC_Decryption(bc.release(), pad.release())); + } + } + } +#endif + +#if defined(BOTAN_HAS_MODE_XTS) + if(spec.algo_name() == "XTS") + { + if(direction == ENCRYPTION) + return std::unique_ptr<Cipher_Mode>(new XTS_Encryption(bc.release())); + else + return std::unique_ptr<Cipher_Mode>(new XTS_Decryption(bc.release())); + } +#endif + +#if defined(BOTAN_HAS_MODE_CFB) + if(spec.algo_name() == "CFB") + { + const size_t feedback_bits = spec.arg_as_integer(1, 8*bc->block_size()); + if(direction == ENCRYPTION) + return std::unique_ptr<Cipher_Mode>(new CFB_Encryption(bc.release(), feedback_bits)); + else + return std::unique_ptr<Cipher_Mode>(new CFB_Decryption(bc.release(), feedback_bits)); + } +#endif + +#endif + + return std::unique_ptr<Cipher_Mode>(); + } + +//static +std::vector<std::string> Cipher_Mode::providers(const std::string& algo_spec) + { + const std::vector<std::string>& possible = { "base", "openssl" }; + std::vector<std::string> providers; + for(auto&& prov : possible) + { + std::unique_ptr<Cipher_Mode> mode = Cipher_Mode::create(algo_spec, ENCRYPTION, prov); + if(mode) + { + providers.push_back(prov); // available + } + } + return providers; + } + +} diff --git a/src/libs/3rdparty/botan/src/lib/modes/cipher_mode.h b/src/libs/3rdparty/botan/src/lib/modes/cipher_mode.h new file mode 100644 index 0000000000..f67e737a43 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/modes/cipher_mode.h @@ -0,0 +1,257 @@ +/* +* Cipher Modes +* (C) 2013,2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_CIPHER_MODE_H_ +#define BOTAN_CIPHER_MODE_H_ + +#include <botan/secmem.h> +#include <botan/key_spec.h> +#include <botan/exceptn.h> +#include <botan/symkey.h> +#include <string> +#include <vector> + +namespace Botan { + +/** +* The two possible directions for cipher filters, determining whether they +* actually perform encryption or decryption. +*/ +enum Cipher_Dir : int { ENCRYPTION, DECRYPTION }; + +/** +* Interface for cipher modes +*/ +class BOTAN_PUBLIC_API(2,0) Cipher_Mode + { + public: + virtual ~Cipher_Mode() = default; + + /** + * @return list of available providers for this algorithm, empty if not available + * @param algo_spec algorithm name + */ + static std::vector<std::string> providers(const std::string& algo_spec); + + /** + * Create an AEAD mode + * @param algo the algorithm to create + * @param direction specify if this should be an encryption or decryption AEAD + * @param provider optional specification for provider to use + * @return an AEAD mode or a null pointer if not available + */ + static std::unique_ptr<Cipher_Mode> create(const std::string& algo, + Cipher_Dir direction, + const std::string& provider = ""); + + /** + * Create an AEAD mode, or throw + * @param algo the algorithm to create + * @param direction specify if this should be an encryption or decryption AEAD + * @param provider optional specification for provider to use + * @return an AEAD mode, or throw an exception + */ + static std::unique_ptr<Cipher_Mode> create_or_throw(const std::string& algo, + Cipher_Dir direction, + const std::string& provider = ""); + + /* + * Prepare for processing a message under the specified nonce + */ + virtual void start_msg(const uint8_t nonce[], size_t nonce_len) = 0; + + /** + * Begin processing a message. + * @param nonce the per message nonce + */ + template<typename Alloc> + void start(const std::vector<uint8_t, Alloc>& nonce) + { + start_msg(nonce.data(), nonce.size()); + } + + /** + * Begin processing a message. + * @param nonce the per message nonce + * @param nonce_len length of nonce + */ + void start(const uint8_t nonce[], size_t nonce_len) + { + start_msg(nonce, nonce_len); + } + + /** + * Begin processing a message. + */ + void start() + { + return start_msg(nullptr, 0); + } + + /** + * Process message blocks + * + * Input must be a multiple of update_granularity + * + * Processes msg in place and returns bytes written. Normally + * this will be either msg_len (indicating the entire message was + * processed) or for certain AEAD modes zero (indicating that the + * mode requires the entire message be processed in one pass). + * + * @param msg the message to be processed + * @param msg_len length of the message in bytes + */ + virtual size_t process(uint8_t msg[], size_t msg_len) = 0; + + /** + * Process some data. Input must be in size update_granularity() uint8_t blocks. + * @param buffer in/out parameter which will possibly be resized + * @param offset an offset into blocks to begin processing + */ + void update(secure_vector<uint8_t>& buffer, size_t offset = 0) + { + BOTAN_ASSERT(buffer.size() >= offset, "Offset ok"); + uint8_t* buf = buffer.data() + offset; + const size_t buf_size = buffer.size() - offset; + + const size_t written = process(buf, buf_size); + buffer.resize(offset + written); + } + + /** + * Complete processing of a message. + * + * @param final_block in/out parameter which must be at least + * minimum_final_size() bytes, and will be set to any final output + * @param offset an offset into final_block to begin processing + */ + virtual void finish(secure_vector<uint8_t>& final_block, size_t offset = 0) = 0; + + /** + * Returns the size of the output if this transform is used to process a + * message with input_length bytes. Will throw if unable to give a precise + * answer. + */ + virtual size_t output_length(size_t input_length) const = 0; + + /** + * @return size of required blocks to update + */ + virtual size_t update_granularity() const = 0; + + /** + * @return required minimium size to finalize() - may be any + * length larger than this. + */ + virtual size_t minimum_final_size() const = 0; + + /** + * @return the default size for a nonce + */ + virtual size_t default_nonce_length() const = 0; + + /** + * @return true iff nonce_len is a valid length for the nonce + */ + virtual bool valid_nonce_length(size_t nonce_len) const = 0; + + virtual std::string name() const = 0; + + /** + * Zeroise all state + * See also reset_msg() + */ + virtual void clear() = 0; + + /** + * Resets just the message specific state and allows encrypting again under the existing key + */ + virtual void reset() = 0; + + /** + * @return true iff this mode provides authentication as well as + * confidentiality. + */ + virtual bool authenticated() const { return false; } + + /** + * @return the size of the authentication tag used (in bytes) + */ + virtual size_t tag_size() const { return 0; } + + /** + * @return object describing limits on key size + */ + virtual Key_Length_Specification key_spec() const = 0; + + /** + * Check whether a given key length is valid for this algorithm. + * @param length the key length to be checked. + * @return true if the key length is valid. + */ + bool valid_keylength(size_t length) const + { + return key_spec().valid_keylength(length); + } + + /** + * Set the symmetric key of this transform + * @param key contains the key material + */ + template<typename Alloc> + void set_key(const std::vector<uint8_t, Alloc>& key) + { + set_key(key.data(), key.size()); + } + + /** + * Set the symmetric key of this transform + * @param key contains the key material + */ + void set_key(const SymmetricKey& key) + { + set_key(key.begin(), key.length()); + } + + /** + * Set the symmetric key of this transform + * @param key contains the key material + * @param length in bytes of key param + */ + void set_key(const uint8_t key[], size_t length) + { + if(!valid_keylength(length)) + throw Invalid_Key_Length(name(), length); + key_schedule(key, length); + } + + /** + * @return provider information about this implementation. Default is "base", + * might also return "sse2", "avx2", "openssl", or some other arbitrary string. + */ + virtual std::string provider() const { return "base"; } + + private: + virtual void key_schedule(const uint8_t key[], size_t length) = 0; + }; + +/** +* Get a cipher mode by name (eg "AES-128/CBC" or "Serpent/XTS") +* @param algo_spec cipher name +* @param direction ENCRYPTION or DECRYPTION +* @param provider provider implementation to choose +*/ +inline Cipher_Mode* get_cipher_mode(const std::string& algo_spec, + Cipher_Dir direction, + const std::string& provider = "") + { + return Cipher_Mode::create(algo_spec, direction, provider).release(); + } + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/modes/info.txt b/src/libs/3rdparty/botan/src/lib/modes/info.txt new file mode 100644 index 0000000000..4c19db04ca --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/modes/info.txt @@ -0,0 +1,9 @@ +<defines> +MODES -> 20150626 +CIPHER_MODES -> 20180124 +</defines> + +<header:public> +cipher_mode.h +stream_mode.h +</header:public> diff --git a/src/libs/3rdparty/botan/src/lib/modes/mode_pad/info.txt b/src/libs/3rdparty/botan/src/lib/modes/mode_pad/info.txt new file mode 100644 index 0000000000..12b6e5b3a9 --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/modes/mode_pad/info.txt @@ -0,0 +1,3 @@ +<defines> +CIPHER_MODE_PADDING -> 20131128 +</defines> diff --git a/src/libs/3rdparty/botan/src/lib/modes/mode_pad/mode_pad.cpp b/src/libs/3rdparty/botan/src/lib/modes/mode_pad/mode_pad.cpp new file mode 100644 index 0000000000..f93b2dcccc --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/modes/mode_pad/mode_pad.cpp @@ -0,0 +1,196 @@ +/* +* CBC Padding Methods +* (C) 1999-2007,2013 Jack Lloyd +* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/mode_pad.h> +#include <botan/exceptn.h> +#include <botan/internal/ct_utils.h> + +namespace Botan { + +/** +* Get a block cipher padding method by name +*/ +BlockCipherModePaddingMethod* get_bc_pad(const std::string& algo_spec) + { + if(algo_spec == "NoPadding") + return new Null_Padding; + + if(algo_spec == "PKCS7") + return new PKCS7_Padding; + + if(algo_spec == "OneAndZeros") + return new OneAndZeros_Padding; + + if(algo_spec == "X9.23") + return new ANSI_X923_Padding; + + if(algo_spec == "ESP") + return new ESP_Padding; + + return nullptr; + } + +/* +* Pad with PKCS #7 Method +*/ +void PKCS7_Padding::add_padding(secure_vector<uint8_t>& buffer, + size_t last_byte_pos, + size_t block_size) const + { + const uint8_t pad_value = static_cast<uint8_t>(block_size - last_byte_pos); + + for(size_t i = 0; i != pad_value; ++i) + buffer.push_back(pad_value); + } + +/* +* Unpad with PKCS #7 Method +*/ +size_t PKCS7_Padding::unpad(const uint8_t block[], size_t size) const + { + CT::poison(block,size); + size_t bad_input = 0; + const uint8_t last_byte = block[size-1]; + + bad_input |= CT::expand_mask<size_t>(last_byte > size); + + size_t pad_pos = size - last_byte; + size_t i = size - 2; + while(i) + { + bad_input |= (~CT::is_equal(block[i],last_byte)) & CT::expand_mask<uint8_t>(i >= pad_pos); + --i; + } + + CT::conditional_copy_mem(bad_input,&pad_pos,&size,&pad_pos,1); + CT::unpoison(block,size); + CT::unpoison(pad_pos); + return pad_pos; + } + +/* +* Pad with ANSI X9.23 Method +*/ +void ANSI_X923_Padding::add_padding(secure_vector<uint8_t>& buffer, + size_t last_byte_pos, + size_t block_size) const + { + const uint8_t pad_value = static_cast<uint8_t>(block_size - last_byte_pos); + + for(size_t i = last_byte_pos; i < block_size-1; ++i) + { + buffer.push_back(0); + } + buffer.push_back(pad_value); + } + +/* +* Unpad with ANSI X9.23 Method +*/ +size_t ANSI_X923_Padding::unpad(const uint8_t block[], size_t size) const + { + CT::poison(block,size); + size_t bad_input = 0; + const size_t last_byte = block[size-1]; + + bad_input |= CT::expand_mask<size_t>(last_byte > size); + + size_t pad_pos = size - last_byte; + size_t i = size - 2; + while(i) + { + bad_input |= (~CT::is_zero(block[i])) & CT::expand_mask<uint8_t>(i >= pad_pos); + --i; + } + CT::conditional_copy_mem(bad_input,&pad_pos,&size,&pad_pos,1); + CT::unpoison(block,size); + CT::unpoison(pad_pos); + return pad_pos; + } + +/* +* Pad with One and Zeros Method +*/ +void OneAndZeros_Padding::add_padding(secure_vector<uint8_t>& buffer, + size_t last_byte_pos, + size_t block_size) const + { + buffer.push_back(0x80); + + for(size_t i = last_byte_pos + 1; i % block_size; ++i) + buffer.push_back(0x00); + } + +/* +* Unpad with One and Zeros Method +*/ +size_t OneAndZeros_Padding::unpad(const uint8_t block[], size_t size) const + { + CT::poison(block, size); + uint8_t bad_input = 0; + uint8_t seen_one = 0; + size_t pad_pos = size - 1; + size_t i = size; + + while(i) + { + seen_one |= CT::is_equal<uint8_t>(block[i-1],0x80); + pad_pos -= CT::select<uint8_t>(~seen_one, 1, 0); + bad_input |= ~CT::is_zero<uint8_t>(block[i-1]) & ~seen_one; + i--; + } + bad_input |= ~seen_one; + + CT::conditional_copy_mem(size_t(bad_input),&pad_pos,&size,&pad_pos,1); + CT::unpoison(block, size); + CT::unpoison(pad_pos); + + return pad_pos; + } + +/* +* Pad with ESP Padding Method +*/ +void ESP_Padding::add_padding(secure_vector<uint8_t>& buffer, + size_t last_byte_pos, + size_t block_size) const + { + uint8_t pad_value = 0x01; + + for(size_t i = last_byte_pos; i < block_size; ++i) + { + buffer.push_back(pad_value++); + } + } + +/* +* Unpad with ESP Padding Method +*/ +size_t ESP_Padding::unpad(const uint8_t block[], size_t size) const + { + CT::poison(block,size); + + const size_t last_byte = block[size-1]; + size_t bad_input = 0; + bad_input |= CT::expand_mask<size_t>(last_byte > size); + + size_t pad_pos = size - last_byte; + size_t i = size - 1; + while(i) + { + bad_input |= ~CT::is_equal<uint8_t>(size_t(block[i-1]),size_t(block[i])-1) & CT::expand_mask<uint8_t>(i > pad_pos); + --i; + } + CT::conditional_copy_mem(bad_input,&pad_pos,&size,&pad_pos,1); + CT::unpoison(block, size); + CT::unpoison(pad_pos); + return pad_pos; + } + + +} diff --git a/src/libs/3rdparty/botan/src/lib/modes/mode_pad/mode_pad.h b/src/libs/3rdparty/botan/src/lib/modes/mode_pad/mode_pad.h new file mode 100644 index 0000000000..cc196d251b --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/modes/mode_pad/mode_pad.h @@ -0,0 +1,159 @@ +/* +* CBC Padding Methods +* (C) 1999-2008,2013 Jack Lloyd +* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_MODE_PADDING_H_ +#define BOTAN_MODE_PADDING_H_ + +#include <botan/secmem.h> +#include <string> + +namespace Botan { + +/** +* Block Cipher Mode Padding Method +* This class is pretty limited, it cannot deal well with +* randomized padding methods, or any padding method that +* wants to add more than one block. For instance, it should +* be possible to define cipher text stealing mode as simply +* a padding mode for CBC, which happens to consume the last +* two block (and requires use of the block cipher). +*/ +class BOTAN_PUBLIC_API(2,0) BlockCipherModePaddingMethod + { + public: + /** + * Add padding bytes to buffer. + * @param buffer data to pad + * @param final_block_bytes size of the final block in bytes + * @param block_size size of each block in bytes + */ + virtual void add_padding(secure_vector<uint8_t>& buffer, + size_t final_block_bytes, + size_t block_size) const = 0; + + /** + * Remove padding bytes from block + * @param block the last block + * @param size the size of the block in bytes + * @return number of padding bytes + */ + virtual size_t unpad(const uint8_t block[], + size_t size) const = 0; + + /** + * @param block_size of the cipher + * @return valid block size for this padding mode + */ + virtual bool valid_blocksize(size_t block_size) const = 0; + + /** + * @return name of the mode + */ + virtual std::string name() const = 0; + + /** + * virtual destructor + */ + virtual ~BlockCipherModePaddingMethod() = default; + }; + +/** +* PKCS#7 Padding +*/ +class BOTAN_PUBLIC_API(2,0) PKCS7_Padding final : public BlockCipherModePaddingMethod + { + public: + void add_padding(secure_vector<uint8_t>& buffer, + size_t final_block_bytes, + size_t block_size) const override; + + size_t unpad(const uint8_t[], size_t) const override; + + bool valid_blocksize(size_t bs) const override { return (bs > 0 && bs < 256); } + + std::string name() const override { return "PKCS7"; } + }; + +/** +* ANSI X9.23 Padding +*/ +class BOTAN_PUBLIC_API(2,0) ANSI_X923_Padding final : public BlockCipherModePaddingMethod + { + public: + void add_padding(secure_vector<uint8_t>& buffer, + size_t final_block_bytes, + size_t block_size) const override; + + size_t unpad(const uint8_t[], size_t) const override; + + bool valid_blocksize(size_t bs) const override { return (bs > 0 && bs < 256); } + + std::string name() const override { return "X9.23"; } + }; + +/** +* One And Zeros Padding (ISO/IEC 9797-1, padding method 2) +*/ +class BOTAN_PUBLIC_API(2,0) OneAndZeros_Padding final : public BlockCipherModePaddingMethod + { + public: + void add_padding(secure_vector<uint8_t>& buffer, + size_t final_block_bytes, + size_t block_size) const override; + + size_t unpad(const uint8_t[], size_t) const override; + + bool valid_blocksize(size_t bs) const override { return (bs > 0); } + + std::string name() const override { return "OneAndZeros"; } + }; + +/** +* ESP Padding (RFC 4304) +*/ +class BOTAN_PUBLIC_API(2,0) ESP_Padding final : public BlockCipherModePaddingMethod + { + public: + void add_padding(secure_vector<uint8_t>& buffer, + size_t final_block_bytes, + size_t block_size) const override; + + size_t unpad(const uint8_t[], size_t) const override; + + bool valid_blocksize(size_t bs) const override { return (bs > 0); } + + std::string name() const override { return "ESP"; } + }; + +/** +* Null Padding +*/ +class BOTAN_PUBLIC_API(2,0) Null_Padding final : public BlockCipherModePaddingMethod + { + public: + void add_padding(secure_vector<uint8_t>&, size_t, size_t) const override + { + /* no padding */ + } + + size_t unpad(const uint8_t[], size_t size) const override { return size; } + + bool valid_blocksize(size_t) const override { return true; } + + std::string name() const override { return "NoPadding"; } + }; + +/** +* Get a block cipher padding mode by name (eg "NoPadding" or "PKCS7") +* @param algo_spec block cipher padding mode name +*/ +BOTAN_PUBLIC_API(2,0) BlockCipherModePaddingMethod* get_bc_pad(const std::string& algo_spec); + +} + +#endif diff --git a/src/libs/3rdparty/botan/src/lib/modes/stream_mode.h b/src/libs/3rdparty/botan/src/lib/modes/stream_mode.h new file mode 100644 index 0000000000..3bce01731a --- /dev/null +++ b/src/libs/3rdparty/botan/src/lib/modes/stream_mode.h @@ -0,0 +1,82 @@ +/* +* (C) 2015 Jack Lloyd +* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_STREAM_MODE_H_ +#define BOTAN_STREAM_MODE_H_ + +#include <botan/cipher_mode.h> + +#if defined(BOTAN_HAS_STREAM_CIPHER) + #include <botan/stream_cipher.h> +#endif + +namespace Botan { + +#if defined(BOTAN_HAS_STREAM_CIPHER) + +class BOTAN_PUBLIC_API(2,0) Stream_Cipher_Mode final : public Cipher_Mode + { + public: + /** + * @param cipher underyling stream cipher + */ + explicit Stream_Cipher_Mode(StreamCipher* cipher) : m_cipher(cipher) {} + + size_t process(uint8_t buf[], size_t sz) override + { + m_cipher->cipher1(buf, sz); + return sz; + } + + void finish(secure_vector<uint8_t>& buf, size_t offset) override + { return update(buf, offset); } + + size_t output_length(size_t input_length) const override { return input_length; } + + size_t update_granularity() const override { return 1; } + + size_t minimum_final_size() const override { return 0; } + + size_t default_nonce_length() const override { return 0; } + + bool valid_nonce_length(size_t nonce_len) const override + { return m_cipher->valid_iv_length(nonce_len); } + + Key_Length_Specification key_spec() const override { return m_cipher->key_spec(); } + + std::string name() const override { return m_cipher->name(); } + + void clear() override + { + m_cipher->clear(); + reset(); + } + + void reset() override { /* no msg state */ } + + private: + void start_msg(const uint8_t nonce[], size_t nonce_len) override + { + if(nonce_len > 0) + { + m_cipher->set_iv(nonce, nonce_len); + } + } + + void key_schedule(const uint8_t key[], size_t length) override + { + m_cipher->set_key(key, length); + } + + std::unique_ptr<StreamCipher> m_cipher; + }; + +#endif + +} + +#endif |