diff options
Diffstat (limited to 'src/lib')
55 files changed, 1297 insertions, 618 deletions
diff --git a/src/lib/asn1/oid_lookup/default.cpp b/src/lib/asn1/oid_lookup/default.cpp index fe7a42748..9e16cfc0b 100644 --- a/src/lib/asn1/oid_lookup/default.cpp +++ b/src/lib/asn1/oid_lookup/default.cpp @@ -30,6 +30,9 @@ const char* default_oid_list() "1.2.840.10045.2.1 = ECDSA" "\n" "1.3.132.1.12 = ECDH" "\n" + // ecgPublicKey (see https://www.teletrust.de/projekte/oid/) + "1.3.36.3.3.2.5.2.1 = ECGDSA" "\n" + "1.2.643.2.2.19 = GOST-34.10" "\n" // Block ciphers @@ -112,6 +115,13 @@ const char* default_oid_list() "1.2.840.10045.4.3.3 = ECDSA/EMSA1(SHA-384)" "\n" "1.2.840.10045.4.3.4 = ECDSA/EMSA1(SHA-512)" "\n" + "1.3.36.3.3.2.5.4.1 = ECGDSA/EMSA1(RIPEMD-160)" "\n" + "1.3.36.3.3.2.5.4.2 = ECGDSA/EMSA1(SHA-160)" "\n" + "1.3.36.3.3.2.5.4.3 = ECGDSA/EMSA1(SHA-224)" "\n" + "1.3.36.3.3.2.5.4.4 = ECGDSA/EMSA1(SHA-256)" "\n" + "1.3.36.3.3.2.5.4.5 = ECGDSA/EMSA1(SHA-384)" "\n" + "1.3.36.3.3.2.5.4.6 = ECGDSA/EMSA1(SHA-512)" "\n" + "1.2.643.2.2.3 = GOST-34.10/EMSA1(GOST-R-34.11-94)" "\n" "1.3.6.1.4.1.25258.2.1.1.1 = RW/EMSA2(RIPEMD-160)" "\n" diff --git a/src/lib/base/algo_registry.h b/src/lib/base/algo_registry.h index ebc23bfca..f7e66b3e2 100644 --- a/src/lib/base/algo_registry.h +++ b/src/lib/base/algo_registry.h @@ -294,10 +294,6 @@ make_new_T_1X(const typename Algo_Registry<T>::Spec& spec) #define BOTAN_REGISTER_NAMED_T_2LEN(T, type, name, provider, len1, len2) \ BOTAN_REGISTER_TYPE(T, type, name, (make_new_T_2len<type,len1,len2>), provider, BOTAN_DEFAULT_ALGORITHM_PRIO) -// TODO move elsewhere: -#define BOTAN_REGISTER_TRANSFORM(name, maker) BOTAN_REGISTER_T(Transform, name, maker) -#define BOTAN_REGISTER_TRANSFORM_NOARGS(name) BOTAN_REGISTER_T_NOARGS(Transform, name) - } #endif diff --git a/src/lib/base/info.txt b/src/lib/base/info.txt index 33d22a279..7553007e5 100644 --- a/src/lib/base/info.txt +++ b/src/lib/base/info.txt @@ -8,15 +8,12 @@ secmem.h scan_name.h sym_algo.h symkey.h -transform.h </header:public> <header:internal> algo_registry.h </header:internal> -define TRANSFORM 20131209 - <requires> block hash diff --git a/src/lib/base/transform.cpp b/src/lib/base/transform.cpp deleted file mode 100644 index 8f05a33ad..000000000 --- a/src/lib/base/transform.cpp +++ /dev/null @@ -1,20 +0,0 @@ -/* -* (C) 2015 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ - -#include <botan/internal/algo_registry.h> -#include <botan/transform.h> - -namespace Botan { - -Transform* get_transform(const std::string& specstr, - const std::string& provider, - const std::string& dirstr) - { - Algo_Registry<Transform>::Spec spec(specstr, dirstr); - return Algo_Registry<Transform>::global_registry().make(spec, provider); - } - -} diff --git a/src/lib/base/transform.h b/src/lib/base/transform.h deleted file mode 100644 index cd4ee9880..000000000 --- a/src/lib/base/transform.h +++ /dev/null @@ -1,182 +0,0 @@ -/* -* Transforms of data -* (C) 2013 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ - -#ifndef BOTAN_TRANSFORM_H__ -#define BOTAN_TRANSFORM_H__ - -#include <botan/secmem.h> -#include <botan/key_spec.h> -#include <botan/exceptn.h> -#include <botan/symkey.h> -#include <botan/scan_name.h> -#include <string> -#include <vector> - -namespace Botan { - -/** -* Interface for general transformations on data -*/ -class BOTAN_DLL Transform - { - public: - typedef SCAN_Name Spec; - - /** - * Begin processing a message. - * @param nonce the per message nonce - */ - template<typename Alloc> - secure_vector<byte> start(const std::vector<byte, Alloc>& nonce) - { - return start(nonce.data(), nonce.size()); - } - - /** - * Begin processing a message. - * @param nonce the per message nonce - */ - template<typename Alloc> - BOTAN_DEPRECATED("Use Transform::start") - secure_vector<byte> start_vec(const std::vector<byte, Alloc>& nonce) - { - return start(nonce.data(), nonce.size()); - } - - /** - * Begin processing a message. - * @param nonce the per message nonce - * @param nonce_len length of nonce - */ - secure_vector<byte> start(const byte nonce[], size_t nonce_len) - { - return start_raw(nonce, nonce_len); - } - - /** - * Begin processing a message. - */ - secure_vector<byte> start() - { - return start_raw(nullptr, 0); - } - - virtual secure_vector<byte> start_raw(const byte nonce[], size_t nonce_len) = 0; - - /** - * Process some data. Input must be in size update_granularity() byte blocks. - * @param blocks in/out parameter which will possibly be resized - * @param offset an offset into blocks to begin processing - */ - virtual void update(secure_vector<byte>& blocks, size_t offset = 0) = 0; - - /** - * 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<byte>& 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; - - /** - * Return some short name describing the provider of this tranformation. - * Useful in cases where multiple implementations are available (eg, - * different implementations of AES). Default "core" is used for the - * 'standard' implementation included in the library. - */ - virtual std::string provider() const { return "core"; } - - virtual std::string name() const = 0; - - virtual void clear() = 0; - - virtual ~Transform() {} - }; - -class BOTAN_DLL Keyed_Transform : public Transform - { - public: - /** - * @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); - } - - template<typename Alloc> - void set_key(const std::vector<byte, Alloc>& key) - { - set_key(key.data(), key.size()); - } - - 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 byte key[], size_t length) - { - if(!valid_keylength(length)) - throw Invalid_Key_Length(name(), length); - key_schedule(key, length); - } - - private: - virtual void key_schedule(const byte key[], size_t length) = 0; - }; - -typedef Transform Transformation; - -BOTAN_DLL Transform* get_transform(const std::string& specstr, - const std::string& provider = "", - const std::string& dirstr = ""); - -} - -#endif diff --git a/src/lib/block/threefish/threefish.cpp b/src/lib/block/threefish/threefish.cpp index 958175bb8..c8e2aff85 100644 --- a/src/lib/block/threefish/threefish.cpp +++ b/src/lib/block/threefish/threefish.cpp @@ -221,7 +221,7 @@ void Threefish_512::decrypt_n(const byte in[], byte out[], size_t blocks) const void Threefish_512::set_tweak(const byte tweak[], size_t len) { if(len != 16) - throw Exception("Unsupported twofish tweak length"); + throw Exception("Threefish-512 requires 128 bit tweak"); m_T.resize(3); m_T[0] = load_le<u64bit>(tweak, 0); m_T[1] = load_le<u64bit>(tweak, 1); @@ -246,8 +246,8 @@ void Threefish_512::key_schedule(const byte key[], size_t) void Threefish_512::clear() { - zeroise(m_K); - zeroise(m_T); + zap(m_K); + zap(m_T); } } diff --git a/src/lib/compression/bzip2/bzip2.cpp b/src/lib/compression/bzip2/bzip2.cpp index d9ada84f6..565eb09fc 100644 --- a/src/lib/compression/bzip2/bzip2.cpp +++ b/src/lib/compression/bzip2/bzip2.cpp @@ -39,6 +39,14 @@ class Bzip2_Compression_Stream : public Bzip2_Stream public: explicit Bzip2_Compression_Stream(size_t block_size) { + /* + * Defaults to 900k blocks as the computation cost of + * compression is not overly affected by the size, though + * more memory is required. + */ + if(block_size == 0 || block_size >= 9) + block_size = 9; + int rc = BZ2_bzCompressInit(streamp(), block_size, 0, 0); if(rc == BZ_MEM_ERROR) @@ -98,9 +106,9 @@ class Bzip2_Decompression_Stream : public Bzip2_Stream } -Compression_Stream* Bzip2_Compression::make_stream() const +Compression_Stream* Bzip2_Compression::make_stream(size_t comp_level) const { - return new Bzip2_Compression_Stream(m_block_size); + return new Bzip2_Compression_Stream(comp_level); } Compression_Stream* Bzip2_Decompression::make_stream() const diff --git a/src/lib/compression/bzip2/bzip2.h b/src/lib/compression/bzip2/bzip2.h index 06c80cb8e..18216f7eb 100644 --- a/src/lib/compression/bzip2/bzip2.h +++ b/src/lib/compression/bzip2/bzip2.h @@ -19,21 +19,9 @@ namespace Botan { class BOTAN_DLL Bzip2_Compression final : public Stream_Compression { public: - /** - * @param block_size in 1024 KiB increments, in range from 1 to 9. - * - * Lowering this does not noticably modify the compression or - * decompression speed, though less memory is required for both - * compression and decompression. - */ - Bzip2_Compression(size_t block_size = 9) : m_block_size(block_size) {} - std::string name() const override { return "Bzip2_Compression"; } - private: - Compression_Stream* make_stream() const override; - - const size_t m_block_size; + Compression_Stream* make_stream(size_t comp_level) const override; }; /** diff --git a/src/lib/compression/bzip2/info.txt b/src/lib/compression/bzip2/info.txt index ea2efa6f1..bc8d780be 100644 --- a/src/lib/compression/bzip2/info.txt +++ b/src/lib/compression/bzip2/info.txt @@ -1,4 +1,4 @@ -define BZIP2_TRANSFORM 20141118 +define BZIP2 20160412 load_on vendor diff --git a/src/lib/compression/compress_utils.h b/src/lib/compression/compress_utils.h index 2a830ac4e..a60ae3c22 100644 --- a/src/lib/compression/compress_utils.h +++ b/src/lib/compression/compress_utils.h @@ -86,8 +86,8 @@ class Zlib_Style_Stream : public Compression_Stream }; #define BOTAN_REGISTER_COMPRESSION(C, D) \ - BOTAN_REGISTER_T_1LEN(Transform, C, 9); \ - BOTAN_REGISTER_T_NOARGS(Transform, D) + BOTAN_REGISTER_T_NOARGS(Compression_Algorithm, C); \ + BOTAN_REGISTER_T_NOARGS(Decompression_Algorithm, D) } diff --git a/src/lib/compression/compression.cpp b/src/lib/compression/compression.cpp index 54faec7b8..f289aa79f 100644 --- a/src/lib/compression/compression.cpp +++ b/src/lib/compression/compression.cpp @@ -54,9 +54,7 @@ void Compression_Alloc_Info::do_free(void* ptr) } } -namespace { - -Compressor_Transform* do_make_compressor(const std::string& type, const std::string& suffix) +Compression_Algorithm* make_compressor(const std::string& type) { const std::map<std::string, std::string> trans{ {"zlib", "Zlib"}, @@ -73,31 +71,29 @@ Compressor_Transform* do_make_compressor(const std::string& type, const std::str if(i == trans.end()) return nullptr; - const std::string t_name = i->second + suffix; - - std::unique_ptr<Transform> t(get_transform(t_name)); - - if(!t) - return nullptr; - - Compressor_Transform* r = dynamic_cast<Compressor_Transform*>(t.get()); - if(!r) - throw Exception("Bad cast of compression object " + t_name); - - t.release(); - return r; + const SCAN_Name t_name(i->second + "_Compression"); + return Algo_Registry<Compression_Algorithm>::global_registry().make(t_name); } -} - -Compressor_Transform* make_compressor(const std::string& type, size_t level) +Decompression_Algorithm* make_decompressor(const std::string& type) { - return do_make_compressor(type, "_Compression(" + std::to_string(level) + ")"); - } + const std::map<std::string, std::string> trans{ + {"zlib", "Zlib"}, + {"deflate", "Deflate"}, + {"gzip", "Gzip"}, + {"gz", "Gzip"}, + {"bzip2", "Bzip2"}, + {"bz2", "Bzip2"}, + {"lzma", "LZMA"}, + {"xz", "LZMA"}}; -Compressor_Transform* make_decompressor(const std::string& type) - { - return do_make_compressor(type, "_Decompression"); + auto i = trans.find(type); + + if(i == trans.end()) + return nullptr; + + const SCAN_Name t_name(i->second + "_Decompression"); + return Algo_Registry<Decompression_Algorithm>::global_registry().make(t_name); } void Stream_Compression::clear() @@ -105,13 +101,9 @@ void Stream_Compression::clear() m_stream.reset(); } -secure_vector<byte> Stream_Compression::start_raw(const byte[], size_t nonce_len) +void Stream_Compression::start(size_t level) { - if(!valid_nonce_length(nonce_len)) - throw Invalid_IV_Length(name(), nonce_len); - - m_stream.reset(make_stream()); - return secure_vector<byte>(); + m_stream.reset(make_stream(level)); } void Stream_Compression::process(secure_vector<byte>& buf, size_t offset, u32bit flags) @@ -154,16 +146,10 @@ void Stream_Compression::process(secure_vector<byte>& buf, size_t offset, u32bit buf.swap(m_buffer); } -void Stream_Compression::update(secure_vector<byte>& buf, size_t offset) - { - BOTAN_ASSERT(m_stream, "Initialized"); - process(buf, offset, m_stream->run_flag()); - } - -void Stream_Compression::flush(secure_vector<byte>& buf, size_t offset) +void Stream_Compression::update(secure_vector<byte>& buf, size_t offset, bool flush) { BOTAN_ASSERT(m_stream, "Initialized"); - process(buf, offset, m_stream->flush_flag()); + process(buf, offset, flush ? m_stream->flush_flag() : m_stream->run_flag()); } void Stream_Compression::finish(secure_vector<byte>& buf, size_t offset) @@ -178,14 +164,9 @@ void Stream_Decompression::clear() m_stream.reset(); } -secure_vector<byte> Stream_Decompression::start_raw(const byte[], size_t nonce_len) +void Stream_Decompression::start() { - if(!valid_nonce_length(nonce_len)) - throw Invalid_IV_Length(name(), nonce_len); - m_stream.reset(make_stream()); - - return secure_vector<byte>(); } void Stream_Decompression::process(secure_vector<byte>& buf, size_t offset, u32bit flags) diff --git a/src/lib/compression/compression.h b/src/lib/compression/compression.h index 66aaacdc4..81b863dcf 100644 --- a/src/lib/compression/compression.h +++ b/src/lib/compression/compression.h @@ -8,32 +8,76 @@ #ifndef BOTAN_COMPRESSION_TRANSFORM_H__ #define BOTAN_COMPRESSION_TRANSFORM_H__ -#include <botan/transform.h> +#include <botan/secmem.h> +#include <botan/scan_name.h> namespace Botan { -class BOTAN_DLL Compressor_Transform : public Transform +class BOTAN_DLL Compression_Algorithm { public: - size_t update_granularity() const override final { return 1; } + typedef SCAN_Name Spec; + + /** + * Begin compressing. Most compression algorithms offer a tunable + * time/compression tradeoff parameter generally represented by + * an integer in the range of 1 to 9. + * + * If 0 or a value out of range is provided, a compression algorithm + * specific default is used. + */ + virtual void start(size_t comp_level = 0) = 0; + + /** + * Process some data. Input must be in size update_granularity() byte blocks. + * @param blocks in/out parameter which will possibly be resized or swapped + * @param offset an offset into blocks to begin processing + * @param flush if true the compressor will be told to flush state + */ + virtual void update(secure_vector<byte>& buf, size_t offset = 0, bool flush = false) = 0; + + /** + * Finish compressing + * + * @param final_block in/out parameter + * @param offset an offset into final_block to begin processing + */ + virtual void finish(secure_vector<byte>& final_block, size_t offset = 0) = 0; + + virtual std::string name() const = 0; + + /** + * Reset the state and abort the current message; start can be + * called again to process a new message. + */ + virtual void clear() = 0; + + virtual ~Compression_Algorithm() {} + }; + +class BOTAN_DLL Decompression_Algorithm + { + public: + typedef SCAN_Name Spec; - size_t minimum_final_size() const override final { return 0; } + /** + * Decompression does not support levels + */ + virtual void start() = 0; - size_t default_nonce_length() const override final { return 0; } + virtual void update(secure_vector<byte>& buf, size_t offset = 0) = 0; - bool valid_nonce_length(size_t nonce_len) const override final - { return nonce_len == 0; } + virtual void finish(secure_vector<byte>& final_block, size_t offset = 0) = 0; - virtual void flush(secure_vector<byte>& buf, size_t offset = 0) { update(buf, offset); } + virtual std::string name() const = 0; - size_t output_length(size_t) const override final - { - throw Exception(name() + " output length indeterminate"); - } + virtual void clear() = 0; + + virtual ~Decompression_Algorithm() {} }; -BOTAN_DLL Compressor_Transform* make_compressor(const std::string& type, size_t level); -BOTAN_DLL Compressor_Transform* make_decompressor(const std::string& type); +BOTAN_DLL Compression_Algorithm* make_compressor(const std::string& type); +BOTAN_DLL Decompression_Algorithm* make_decompressor(const std::string& type); class Compression_Stream { @@ -55,39 +99,37 @@ class Compression_Stream virtual bool run(u32bit flags) = 0; }; -class BOTAN_DLL Stream_Compression : public Compressor_Transform +class Stream_Compression : public Compression_Algorithm { public: - void update(secure_vector<byte>& buf, size_t offset = 0) final override; - - void flush(secure_vector<byte>& buf, size_t offset = 0) final override; + void update(secure_vector<byte>& buf, size_t offset, bool flush) final override; - void finish(secure_vector<byte>& buf, size_t offset = 0) final override; + void finish(secure_vector<byte>& buf, size_t offset) final override; void clear() final override; private: - secure_vector<byte> start_raw(const byte[], size_t) final override; + void start(size_t level) final override; void process(secure_vector<byte>& buf, size_t offset, u32bit flags); - virtual Compression_Stream* make_stream() const = 0; + virtual Compression_Stream* make_stream(size_t level) const = 0; secure_vector<byte> m_buffer; std::unique_ptr<Compression_Stream> m_stream; }; -class BOTAN_DLL Stream_Decompression : public Compressor_Transform +class Stream_Decompression : public Decompression_Algorithm { public: - void update(secure_vector<byte>& buf, size_t offset = 0) final override; + void update(secure_vector<byte>& buf, size_t offset) final override; - void finish(secure_vector<byte>& buf, size_t offset = 0) final override; + void finish(secure_vector<byte>& buf, size_t offset) final override; void clear() final override; private: - secure_vector<byte> start_raw(const byte[], size_t) final override; + void start() final override; void process(secure_vector<byte>& buf, size_t offset, u32bit flags); diff --git a/src/lib/compression/lzma/info.txt b/src/lib/compression/lzma/info.txt index 443a96919..7a712338e 100644 --- a/src/lib/compression/lzma/info.txt +++ b/src/lib/compression/lzma/info.txt @@ -1,4 +1,4 @@ -define LZMA_TRANSFORM 20141118 +define LZMA 20160412 load_on vendor diff --git a/src/lib/compression/lzma/lzma.cpp b/src/lib/compression/lzma/lzma.cpp index 3cc03a098..18701278d 100644 --- a/src/lib/compression/lzma/lzma.cpp +++ b/src/lib/compression/lzma/lzma.cpp @@ -58,6 +58,11 @@ class LZMA_Compression_Stream : public LZMA_Stream public: explicit LZMA_Compression_Stream(size_t level) { + if(level == 0) + level = 6; // default + else if(level > 9) + level = 9; // clamp to maximum allowed value + lzma_ret rc = ::lzma_easy_encoder(streamp(), level, LZMA_CHECK_CRC64); if(rc == LZMA_MEM_ERROR) @@ -84,9 +89,9 @@ class LZMA_Decompression_Stream : public LZMA_Stream } -Compression_Stream* LZMA_Compression::make_stream() const +Compression_Stream* LZMA_Compression::make_stream(size_t level) const { - return new LZMA_Compression_Stream(m_level); + return new LZMA_Compression_Stream(level); } Compression_Stream* LZMA_Decompression::make_stream() const diff --git a/src/lib/compression/lzma/lzma.h b/src/lib/compression/lzma/lzma.h index d9ea10091..63722b064 100644 --- a/src/lib/compression/lzma/lzma.h +++ b/src/lib/compression/lzma/lzma.h @@ -20,19 +20,10 @@ namespace Botan { class BOTAN_DLL LZMA_Compression final : public Stream_Compression { public: - /** - * @param level how much effort to use on compressing (0 to 9); - * higher levels are slower but tend to give better - * compression - */ - LZMA_Compression(size_t level = 6) : m_level(level) {} - std::string name() const override { return "LZMA_Compression"; } private: - Compression_Stream* make_stream() const override; - - const size_t m_level; + Compression_Stream* make_stream(size_t level) const override; }; /** diff --git a/src/lib/compression/zlib/info.txt b/src/lib/compression/zlib/info.txt index 8b722350f..6c82c49a3 100644 --- a/src/lib/compression/zlib/info.txt +++ b/src/lib/compression/zlib/info.txt @@ -1,4 +1,4 @@ -define ZLIB_TRANSFORM 20141118 +define ZLIB 20160412 load_on vendor diff --git a/src/lib/compression/zlib/zlib.cpp b/src/lib/compression/zlib/zlib.cpp index 6df5ee931..836925a68 100644 --- a/src/lib/compression/zlib/zlib.cpp +++ b/src/lib/compression/zlib/zlib.cpp @@ -50,20 +50,25 @@ class Zlib_Compression_Stream : public Zlib_Stream { wbits = compute_window_bits(wbits, wbits_offset); - int rc = deflateInit2(streamp(), level, Z_DEFLATED, wbits, - 8, Z_DEFAULT_STRATEGY); + if(level >= 9) + level = 9; + else if(level == 0) + level = 6; + + int rc = ::deflateInit2(streamp(), level, Z_DEFLATED, wbits, 8, Z_DEFAULT_STRATEGY); + if(rc != Z_OK) throw Exception("zlib deflate initialization failed"); } ~Zlib_Compression_Stream() { - deflateEnd(streamp()); + ::deflateEnd(streamp()); } bool run(u32bit flags) override { - int rc = deflate(streamp(), flags); + int rc = ::deflate(streamp(), flags); if(rc == Z_MEM_ERROR) throw Exception("zlib memory allocation failure"); @@ -79,7 +84,7 @@ class Zlib_Decompression_Stream : public Zlib_Stream public: Zlib_Decompression_Stream(int wbits, int wbits_offset = 0) { - int rc = inflateInit2(streamp(), compute_window_bits(wbits, wbits_offset)); + int rc = ::inflateInit2(streamp(), compute_window_bits(wbits, wbits_offset)); if(rc == Z_MEM_ERROR) throw Exception("zlib memory allocation failure"); @@ -89,12 +94,12 @@ class Zlib_Decompression_Stream : public Zlib_Stream ~Zlib_Decompression_Stream() { - inflateEnd(streamp()); + ::inflateEnd(streamp()); } bool run(u32bit flags) override { - int rc = inflate(streamp(), flags); + int rc = ::inflate(streamp(), flags); if(rc == Z_MEM_ERROR) throw Exception("zlib memory allocation failure"); @@ -145,9 +150,9 @@ class Gzip_Decompression_Stream : public Zlib_Decompression_Stream } -Compression_Stream* Zlib_Compression::make_stream() const +Compression_Stream* Zlib_Compression::make_stream(size_t level) const { - return new Zlib_Compression_Stream(m_level, 15); + return new Zlib_Compression_Stream(level, 15); } Compression_Stream* Zlib_Decompression::make_stream() const @@ -155,9 +160,9 @@ Compression_Stream* Zlib_Decompression::make_stream() const return new Zlib_Decompression_Stream(15); } -Compression_Stream* Deflate_Compression::make_stream() const +Compression_Stream* Deflate_Compression::make_stream(size_t level) const { - return new Deflate_Compression_Stream(m_level, 15); + return new Deflate_Compression_Stream(level, 15); } Compression_Stream* Deflate_Decompression::make_stream() const @@ -165,9 +170,9 @@ Compression_Stream* Deflate_Decompression::make_stream() const return new Deflate_Decompression_Stream(15); } -Compression_Stream* Gzip_Compression::make_stream() const +Compression_Stream* Gzip_Compression::make_stream(size_t level) const { - return new Gzip_Compression_Stream(m_level, 15, m_os_code); + return new Gzip_Compression_Stream(level, 15, m_os_code); } Compression_Stream* Gzip_Decompression::make_stream() const diff --git a/src/lib/compression/zlib/zlib.h b/src/lib/compression/zlib/zlib.h index 6a8cead14..0cedb1eab 100644 --- a/src/lib/compression/zlib/zlib.h +++ b/src/lib/compression/zlib/zlib.h @@ -19,20 +19,9 @@ namespace Botan { class BOTAN_DLL Zlib_Compression final : public Stream_Compression { public: - /** - * @param level how much effort to use on compressing (0 to 9); - * higher levels are slower but tend to give better - * compression - */ - - Zlib_Compression(size_t level = 6) : m_level(level) {} - std::string name() const override { return "Zlib_Compression"; } - private: - Compression_Stream* make_stream() const override; - - const size_t m_level; + Compression_Stream* make_stream(size_t level) const override; }; /** @@ -42,7 +31,6 @@ class BOTAN_DLL Zlib_Decompression final : public Stream_Decompression { public: std::string name() const override { return "Zlib_Decompression"; } - private: Compression_Stream* make_stream() const override; }; @@ -53,19 +41,9 @@ class BOTAN_DLL Zlib_Decompression final : public Stream_Decompression class BOTAN_DLL Deflate_Compression final : public Stream_Compression { public: - /** - * @param level how much effort to use on compressing (0 to 9); - * higher levels are slower but tend to give better - * compression - */ - Deflate_Compression(size_t level = 6) : m_level(level) {} - std::string name() const override { return "Deflate_Compression"; } - private: - Compression_Stream* make_stream() const override; - - const size_t m_level; + Compression_Stream* make_stream(size_t level) const override; }; /** @@ -75,7 +53,6 @@ class BOTAN_DLL Deflate_Decompression final : public Stream_Decompression { public: std::string name() const override { return "Deflate_Decompression"; } - private: Compression_Stream* make_stream() const override; }; @@ -86,20 +63,11 @@ class BOTAN_DLL Deflate_Decompression final : public Stream_Decompression class BOTAN_DLL Gzip_Compression final : public Stream_Compression { public: - /** - * @param level how much effort to use on compressing (0 to 9); - * higher levels are slower but tend to give better - * compression - */ - Gzip_Compression(size_t level = 6, byte os_code = 255) : - m_level(level), m_os_code(os_code) {} + Gzip_Compression(byte os_code = 255) : m_os_code(os_code) {} std::string name() const override { return "Gzip_Compression"; } - private: - Compression_Stream* make_stream() const override; - - const size_t m_level; + Compression_Stream* make_stream(size_t level) const override; const byte m_os_code; }; @@ -110,7 +78,6 @@ class BOTAN_DLL Gzip_Decompression final : public Stream_Decompression { public: std::string name() const override { return "Gzip_Decompression"; } - private: Compression_Stream* make_stream() const override; }; diff --git a/src/lib/filters/aead_filt.h b/src/lib/filters/aead_filt.h index a97b580bd..c86739fc8 100644 --- a/src/lib/filters/aead_filt.h +++ b/src/lib/filters/aead_filt.h @@ -8,7 +8,7 @@ #ifndef BOTAN_AEAD_FILTER_H__ #define BOTAN_AEAD_FILTER_H__ -#include <botan/transform_filter.h> +#include <botan/cipher_filter.h> #include <botan/aead.h> namespace Botan { @@ -16,10 +16,10 @@ namespace Botan { /** * Filter interface for AEAD Modes */ -class BOTAN_DLL AEAD_Filter : public Transform_Filter +class AEAD_Filter : public Cipher_Mode_Filter { public: - AEAD_Filter(AEAD_Mode* aead) : Transform_Filter(aead) {} + AEAD_Filter(AEAD_Mode* aead) : Cipher_Mode_Filter(aead) {} /** * Set associated data that is not included in the ciphertext but diff --git a/src/lib/filters/cipher_filter.cpp b/src/lib/filters/cipher_filter.cpp new file mode 100644 index 000000000..f91cf3aa2 --- /dev/null +++ b/src/lib/filters/cipher_filter.cpp @@ -0,0 +1,114 @@ +/* +* Filter interface for Cipher_Modes +* (C) 2013,2014 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/cipher_filter.h> +#include <botan/internal/rounding.h> + +namespace Botan { + +namespace { + +size_t choose_update_size(size_t update_granularity) + { + const size_t target_size = 1024; + + if(update_granularity >= target_size) + return update_granularity; + + return round_up(target_size, update_granularity); + } + +} + +Cipher_Mode_Filter::Cipher_Mode_Filter(Cipher_Mode* mode) : + Buffered_Filter(choose_update_size(mode->update_granularity()), + mode->minimum_final_size()), + m_nonce(mode->default_nonce_length() == 0), + m_mode(mode), + m_buffer(m_mode->update_granularity()) + { + } + +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<byte> 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); + } + +void Cipher_Mode_Filter::set_key(const SymmetricKey& key) + { + m_mode->set_key(key); + } + +Key_Length_Specification Cipher_Mode_Filter::key_spec() const + { + return m_mode->key_spec(); + } + +bool Cipher_Mode_Filter::valid_iv_length(size_t length) const + { + return m_mode->valid_nonce_length(length); + } + +void Cipher_Mode_Filter::write(const byte input[], size_t input_length) + { + Buffered_Filter::write(input, input_length); + } + +void Cipher_Mode_Filter::end_msg() + { + Buffered_Filter::end_msg(); + } + +void Cipher_Mode_Filter::start_msg() + { + send(m_mode->start(m_nonce.get())); + } + +void Cipher_Mode_Filter::buffered_block(const byte input[], size_t input_length) + { + while(input_length) + { + const size_t take = std::min(m_mode->update_granularity(), input_length); + + m_buffer.assign(input, input + take); + m_mode->update(m_buffer); + + send(m_buffer); + + input += take; + input_length -= take; + } + } + +void Cipher_Mode_Filter::buffered_final(const byte input[], size_t input_length) + { + secure_vector<byte> buf(input, input + input_length); + m_mode->finish(buf); + send(buf); + } + +} diff --git a/src/lib/filters/transform_filter.h b/src/lib/filters/cipher_filter.h index 2ecc5cecb..e0681f82a 100644 --- a/src/lib/filters/transform_filter.h +++ b/src/lib/filters/cipher_filter.h @@ -1,6 +1,6 @@ /* -* Filter interface for Transforms -* (C) 2013 Jack Lloyd +* Filter interface for ciphers +* (C) 2013,2016 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ @@ -8,20 +8,20 @@ #ifndef BOTAN_TRANSFORM_FILTER_H__ #define BOTAN_TRANSFORM_FILTER_H__ -#include <botan/transform.h> +#include <botan/cipher_mode.h> #include <botan/key_filt.h> #include <botan/buf_filt.h> namespace Botan { /** -* Filter interface for Transforms +* Filter interface for cipher modes */ -class BOTAN_DLL Transform_Filter : public Keyed_Filter, - private Buffered_Filter +class BOTAN_DLL Cipher_Mode_Filter : public Keyed_Filter, + private Buffered_Filter { public: - explicit Transform_Filter(Transform* t); + explicit Cipher_Mode_Filter(Cipher_Mode* t); void set_iv(const InitializationVector& iv) override; @@ -34,9 +34,9 @@ class BOTAN_DLL Transform_Filter : public Keyed_Filter, std::string name() const override; protected: - const Transform& get_transform() const { return *m_transform; } + const Cipher_Mode& get_mode() const { return *m_mode; } - Transform& get_transform() { return *m_transform; } + Cipher_Mode& get_mode() { return *m_mode; } private: void write(const byte input[], size_t input_length) override; @@ -59,10 +59,12 @@ class BOTAN_DLL Transform_Filter : public Keyed_Filter, }; Nonce_State m_nonce; - std::unique_ptr<Transform> m_transform; + std::unique_ptr<Cipher_Mode> m_mode; secure_vector<byte> m_buffer; }; +// deprecated aliases, will be removed before 2.0 +typedef Cipher_Mode_Filter Transform_Filter; typedef Transform_Filter Transformation_Filter; } diff --git a/src/lib/filters/comp_filter.cpp b/src/lib/filters/comp_filter.cpp index ab11526dd..a89fd68ae 100644 --- a/src/lib/filters/comp_filter.cpp +++ b/src/lib/filters/comp_filter.cpp @@ -1,6 +1,6 @@ /* * Filter interface for compression -* (C) 2014,2015 Jack Lloyd +* (C) 2014,2015,2016 Jack Lloyd * (C) 2015 Matej Kenda * * Botan is released under the Simplified BSD License (see license.txt) @@ -8,44 +8,83 @@ #include <botan/comp_filter.h> #include <botan/compression.h> +#include <botan/exceptn.h> namespace Botan { Compression_Filter::Compression_Filter(const std::string& type, size_t level, size_t bs) : - Compression_Decompression_Filter(make_compressor(type, level), bs) + m_comp(make_compressor(type)), + m_buffersize(std::max<size_t>(bs, 256)), + m_level(level) { + if(!m_comp) + { + throw Invalid_Argument("Compression type '" + type + "' not found"); + } } -Decompression_Filter::Decompression_Filter(const std::string& type, size_t bs) : - Compression_Decompression_Filter(make_decompressor(type), bs) +std::string Compression_Filter::name() const { + return m_comp->name(); } -Compression_Decompression_Filter::Compression_Decompression_Filter(Transform* transform, size_t bs) : - m_buffersize(std::max<size_t>(256, bs)), m_buffer(m_buffersize) +void Compression_Filter::start_msg() { - if (!transform) + m_comp->start(m_level); + } + +void Compression_Filter::write(const byte input[], size_t input_length) + { + while(input_length) { - throw Invalid_Argument("Transform is null"); + const size_t take = std::min(m_buffersize, input_length); + BOTAN_ASSERT(take > 0, "Consumed something"); + + m_buffer.assign(input, input + take); + m_comp->update(m_buffer); + + send(m_buffer); + + input += take; + input_length -= take; } - m_transform.reset(dynamic_cast<Compressor_Transform*>(transform)); - if(!m_transform) + } + +void Compression_Filter::flush() + { + m_buffer.clear(); + m_comp->update(m_buffer, 0, true); + send(m_buffer); + } + +void Compression_Filter::end_msg() + { + m_buffer.clear(); + m_comp->finish(m_buffer); + send(m_buffer); + } + +Decompression_Filter::Decompression_Filter(const std::string& type, size_t bs) : + m_comp(make_decompressor(type)), + m_buffersize(std::max<size_t>(bs, 256)) + { + if(!m_comp) { - throw Invalid_Argument("Transform " + transform->name() + " is not a compressor"); + throw Invalid_Argument("Compression type '" + type + "' not found"); } } -std::string Compression_Decompression_Filter::name() const +std::string Decompression_Filter::name() const { - return m_transform->name(); + return m_comp->name(); } -void Compression_Decompression_Filter::start_msg() +void Decompression_Filter::start_msg() { - send(m_transform->start()); + m_comp->start(); } -void Compression_Decompression_Filter::write(const byte input[], size_t input_length) +void Decompression_Filter::write(const byte input[], size_t input_length) { while(input_length) { @@ -53,7 +92,7 @@ void Compression_Decompression_Filter::write(const byte input[], size_t input_le BOTAN_ASSERT(take > 0, "Consumed something"); m_buffer.assign(input, input + take); - m_transform->update(m_buffer); + m_comp->update(m_buffer); send(m_buffer); @@ -62,17 +101,10 @@ void Compression_Decompression_Filter::write(const byte input[], size_t input_le } } -void Compression_Decompression_Filter::flush() - { - m_buffer.clear(); - m_transform->flush(m_buffer); - send(m_buffer); - } - -void Compression_Decompression_Filter::end_msg() +void Decompression_Filter::end_msg() { m_buffer.clear(); - m_transform->finish(m_buffer); + m_comp->finish(m_buffer); send(m_buffer); } diff --git a/src/lib/filters/comp_filter.h b/src/lib/filters/comp_filter.h index bb928b640..4d347c42d 100644 --- a/src/lib/filters/comp_filter.h +++ b/src/lib/filters/comp_filter.h @@ -1,6 +1,6 @@ /* * Filter interface for compression -* (C) 2014,2015 Jack Lloyd +* (C) 2014,2015,2016 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ @@ -12,46 +12,50 @@ namespace Botan { -class Transform; -class Compressor_Transform; +class Compression_Algorithm; +class Decompression_Algorithm; /** -* Filter interface for compression/decompression +* Filter interface for compression */ -class BOTAN_DLL Compression_Decompression_Filter : public Filter +class BOTAN_DLL Compression_Filter : public Filter { public: void start_msg() override; void write(const byte input[], size_t input_length) override; void end_msg() override; - std::string name() const override; + void flush(); - protected: - Compression_Decompression_Filter(Transform* t, size_t bs); + std::string name() const override; - void flush(); + Compression_Filter(const std::string& type, + size_t compression_level, + size_t buffer_size = 4096); private: - std::unique_ptr<Compressor_Transform> m_transform; - std::size_t m_buffersize; + std::unique_ptr<Compression_Algorithm> m_comp; + size_t m_buffersize, m_level; secure_vector<byte> m_buffer; }; -class BOTAN_DLL Compression_Filter : public Compression_Decompression_Filter +/** +* Filter interface for decompression +*/ +class BOTAN_DLL Decompression_Filter : public Filter { public: - Compression_Filter(const std::string& type, - size_t compression_level, - size_t buffer_size = 4096); + void start_msg() override; + void write(const byte input[], size_t input_length) override; + void end_msg() override; - using Compression_Decompression_Filter::flush; - }; + std::string name() const override; -class BOTAN_DLL Decompression_Filter : public Compression_Decompression_Filter - { - public: Decompression_Filter(const std::string& type, size_t buffer_size = 4096); + private: + std::unique_ptr<Decompression_Algorithm> m_comp; + std::size_t m_buffersize; + secure_vector<byte> m_buffer; }; } diff --git a/src/lib/filters/info.txt b/src/lib/filters/info.txt index fbecd9c87..217baea1d 100644 --- a/src/lib/filters/info.txt +++ b/src/lib/filters/info.txt @@ -1,4 +1,4 @@ -define FILTERS 20131128 +define FILTERS 20160415 <source> algo_filt.cpp @@ -14,7 +14,7 @@ pipe_io.cpp pipe_rw.cpp secqueue.cpp threaded_fork.cpp -transform_filter.cpp +cipher_filter.cpp </source> <header:public> @@ -27,7 +27,7 @@ filters.h key_filt.h pipe.h secqueue.h -transform_filter.h +cipher_filter.h </header:public> <header:internal> diff --git a/src/lib/filters/key_filt.cpp b/src/lib/filters/key_filt.cpp index 2cc350268..0f6a67da9 100644 --- a/src/lib/filters/key_filt.cpp +++ b/src/lib/filters/key_filt.cpp @@ -5,7 +5,7 @@ */ #include <botan/key_filt.h> -#include <botan/transform_filter.h> +#include <botan/cipher_filter.h> namespace Botan { @@ -14,7 +14,7 @@ Keyed_Filter* get_cipher(const std::string& algo_spec, { std::unique_ptr<Cipher_Mode> c(get_cipher_mode(algo_spec, direction)); if(c) - return new Transform_Filter(c.release()); + return new Cipher_Mode_Filter(c.release()); throw Algorithm_Not_Found(algo_spec); } diff --git a/src/lib/filters/transform_filter.cpp b/src/lib/filters/transform_filter.cpp deleted file mode 100644 index 27a22f9bd..000000000 --- a/src/lib/filters/transform_filter.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/* -* Filter interface for Transforms -* (C) 2013,2014 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ - -#include <botan/transform_filter.h> -#include <botan/internal/rounding.h> - -namespace Botan { - -namespace { - -size_t choose_update_size(size_t update_granularity) - { - const size_t target_size = 1024; - - if(update_granularity >= target_size) - return update_granularity; - - return round_up(target_size, update_granularity); - } - -} - -Transform_Filter::Transform_Filter(Transform* transform) : - Buffered_Filter(choose_update_size(transform->update_granularity()), - transform->minimum_final_size()), - m_nonce(transform->default_nonce_length() == 0), - m_transform(transform), - m_buffer(m_transform->update_granularity()) - { - } - -std::string Transform_Filter::name() const - { - return m_transform->name(); - } - -void Transform_Filter::Nonce_State::update(const InitializationVector& iv) - { - m_nonce = unlock(iv.bits_of()); - m_fresh_nonce = true; - } - -std::vector<byte> Transform_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 Transform_Filter::set_iv(const InitializationVector& iv) - { - m_nonce.update(iv); - } - -void Transform_Filter::set_key(const SymmetricKey& key) - { - if(Keyed_Transform* keyed = dynamic_cast<Keyed_Transform*>(m_transform.get())) - keyed->set_key(key); - else if(key.length() != 0) - throw Exception("Transform " + name() + " does not accept keys"); - } - -Key_Length_Specification Transform_Filter::key_spec() const - { - if(Keyed_Transform* keyed = dynamic_cast<Keyed_Transform*>(m_transform.get())) - return keyed->key_spec(); - return Key_Length_Specification(0); - } - -bool Transform_Filter::valid_iv_length(size_t length) const - { - return m_transform->valid_nonce_length(length); - } - -void Transform_Filter::write(const byte input[], size_t input_length) - { - Buffered_Filter::write(input, input_length); - } - -void Transform_Filter::end_msg() - { - Buffered_Filter::end_msg(); - } - -void Transform_Filter::start_msg() - { - send(m_transform->start(m_nonce.get())); - } - -void Transform_Filter::buffered_block(const byte input[], size_t input_length) - { - while(input_length) - { - const size_t take = std::min(m_transform->update_granularity(), input_length); - - m_buffer.assign(input, input + take); - m_transform->update(m_buffer); - - send(m_buffer); - - input += take; - input_length -= take; - } - } - -void Transform_Filter::buffered_final(const byte input[], size_t input_length) - { - secure_vector<byte> buf(input, input + input_length); - m_transform->finish(buf); - send(buf); - } - -} diff --git a/src/lib/kdf/kdf.cpp b/src/lib/kdf/kdf.cpp index 45ee165e0..7f4488d32 100644 --- a/src/lib/kdf/kdf.cpp +++ b/src/lib/kdf/kdf.cpp @@ -33,6 +33,14 @@ #include <botan/prf_x942.h> #endif +#if defined(BOTAN_HAS_SP800_108) +#include <botan/sp800_108.h> +#endif + +#if defined(BOTAN_HAS_SP800_56C) +#include <botan/sp800_56c.h> +#endif + #define BOTAN_REGISTER_KDF_NOARGS(type, name) \ BOTAN_REGISTER_NAMED_T(KDF, name, type, (make_new_T<type>)) #define BOTAN_REGISTER_KDF_1HASH(type, name) \ @@ -93,4 +101,13 @@ BOTAN_REGISTER_NAMED_T(KDF, "TLS-12-PRF", TLS_12_PRF, TLS_12_PRF::make); BOTAN_REGISTER_KDF_NAMED_1STR(X942_PRF, "X9.42-PRF"); #endif +#if defined(BOTAN_HAS_SP800_108) +BOTAN_REGISTER_NAMED_T(KDF, "SP800-108-Counter", SP800_108_Counter, SP800_108_Counter::make); +BOTAN_REGISTER_NAMED_T(KDF, "SP800-108-Feedback", SP800_108_Feedback, SP800_108_Feedback::make); +BOTAN_REGISTER_NAMED_T(KDF, "SP800-108-Pipeline", SP800_108_Pipeline, SP800_108_Pipeline::make); +#endif + +#if defined(BOTAN_HAS_SP800_56C) +BOTAN_REGISTER_NAMED_T(KDF, "SP800-56C", SP800_56C, SP800_56C::make); +#endif } diff --git a/src/lib/kdf/sp800_108/info.txt b/src/lib/kdf/sp800_108/info.txt new file mode 100644 index 000000000..a78531fe7 --- /dev/null +++ b/src/lib/kdf/sp800_108/info.txt @@ -0,0 +1,6 @@ +define SP800_108 20160128 + +<requires> +mac +hmac +</requires> diff --git a/src/lib/kdf/sp800_108/sp800_108.cpp b/src/lib/kdf/sp800_108/sp800_108.cpp new file mode 100644 index 000000000..873db814c --- /dev/null +++ b/src/lib/kdf/sp800_108/sp800_108.cpp @@ -0,0 +1,157 @@ +/* +* KDFs defined in NIST SP 800-108 +* (C) 2016 Kai Michaelis +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/sp800_108.h> +#include <botan/hmac.h> + +namespace Botan { + +SP800_108_Counter* SP800_108_Counter::make(const Spec& spec) + { + if(auto mac = MessageAuthenticationCode::create(spec.arg(0))) + return new SP800_108_Counter(mac.release()); + + if(auto mac = MessageAuthenticationCode::create("HMAC(" + spec.arg(0) + ")")) + return new SP800_108_Counter(mac.release()); + + return nullptr; + } + +size_t SP800_108_Counter::kdf(byte key[], size_t key_len, + const byte secret[], size_t secret_len, + const byte salt[], size_t salt_len) const + { + const std::size_t prf_len = m_prf->output_length(); + byte *p = key; + uint32_t counter = 1; + secure_vector<byte> tmp; + + m_prf->set_key(secret, secret_len); + + while(p < key + key_len && counter != 0) + { + const std::size_t to_copy = std::min< std::size_t >(key + key_len - p, prf_len); + byte be_cnt[4] = { 0 }; + + store_be(counter, be_cnt); + + m_prf->update(be_cnt,4); + m_prf->update(salt, salt_len); + m_prf->final(tmp); + + std::move(tmp.begin(), tmp.begin() + to_copy, p); + ++counter; + + if (counter == 0) + throw Invalid_Argument("Can't process more than 4GB"); + + p += to_copy; + } + + return key_len; + } + +SP800_108_Feedback* SP800_108_Feedback::make(const Spec& spec) + { + if(auto mac = MessageAuthenticationCode::create(spec.arg(0))) + return new SP800_108_Feedback(mac.release()); + + if(auto mac = MessageAuthenticationCode::create("HMAC(" + spec.arg(0) + ")")) + return new SP800_108_Feedback(mac.release()); + + return nullptr; + } + +size_t SP800_108_Feedback::kdf(byte key[], size_t key_len, + const byte secret[], size_t secret_len, + const byte salt[], size_t salt_len) const + { + const std::size_t prf_len = m_prf->output_length(); + const std::size_t iv_len = (salt_len >= prf_len ? prf_len : 0); + + byte *p = key; + uint32_t counter = 1; + secure_vector< byte > prev(salt, salt + iv_len); + secure_vector< byte > ctx(salt + iv_len, salt + salt_len); + + m_prf->set_key(secret, secret_len); + + while(p < key + key_len && counter != 0) + { + const std::size_t to_copy = std::min< std::size_t >(key + key_len - p, prf_len); + byte be_cnt[4] = { 0 }; + + store_be(counter, be_cnt); + + m_prf->update(prev); + m_prf->update(be_cnt,4); + m_prf->update(ctx); + m_prf->final(prev); + + std::copy(prev.begin(), prev.begin() + to_copy, p); + ++counter; + + if (counter == 0) + throw Invalid_Argument("Can't process more than 4GB"); + + p += to_copy; + } + + return key_len; + } + +SP800_108_Pipeline* SP800_108_Pipeline::make(const Spec& spec) + { + if(auto mac = MessageAuthenticationCode::create(spec.arg(0))) + return new SP800_108_Pipeline(mac.release()); + + if(auto mac = MessageAuthenticationCode::create("HMAC(" + spec.arg(0) + ")")) + return new SP800_108_Pipeline(mac.release()); + + return nullptr; + } + +size_t SP800_108_Pipeline::kdf(byte key[], size_t key_len, + const byte secret[], size_t secret_len, + const byte salt[], size_t salt_len) const + { + const std::size_t prf_len = m_prf->output_length(); + byte *p = key; + uint32_t counter = 1; + secure_vector<byte> ai(salt, salt + salt_len), ki; + + m_prf->set_key(secret,secret_len); + + while(p < key + key_len && counter != 0) + { + // A(i) + m_prf->update(ai); + m_prf->final(ai); + + // K(i) + const std::size_t to_copy = std::min< std::size_t >(key + key_len - p, prf_len); + byte be_cnt[4] = { 0 }; + + store_be(counter, be_cnt); + + m_prf->update(ai); + m_prf->update(be_cnt,4); + m_prf->update(salt, salt_len); + m_prf->final(ki); + + std::copy(ki.begin(), ki.begin() + to_copy, p); + ++counter; + + if (counter == 0) + throw Invalid_Argument("Can't process more than 4GB"); + + p += to_copy; + } + + return key_len; + } +} diff --git a/src/lib/kdf/sp800_108/sp800_108.h b/src/lib/kdf/sp800_108/sp800_108.h new file mode 100644 index 000000000..0acdfacf9 --- /dev/null +++ b/src/lib/kdf/sp800_108/sp800_108.h @@ -0,0 +1,81 @@ +/* +* KDFs defined in NIST SP 800-108 +* (C) 2016 Kai Michaelis +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SP800_108_H__ +#define BOTAN_SP800_108_H__ + +#include <botan/kdf.h> +#include <botan/mac.h> + +namespace Botan { + +/** + * NIST SP 800-108 KDF in Counter Mode (5.1) + */ +class BOTAN_DLL SP800_108_Counter : public KDF + { + public: + std::string name() const override { return "SP800-108-Counter(" + m_prf->name() + ")"; } + + KDF* clone() const override { return new SP800_108_Counter(m_prf->clone()); } + + size_t kdf(byte key[], size_t key_len, + const byte secret[], size_t secret_len, + const byte salt[], size_t salt_len) const override; + + SP800_108_Counter(MessageAuthenticationCode* mac) : m_prf(mac) {} + + static SP800_108_Counter* make(const Spec& spec); + private: + std::unique_ptr<MessageAuthenticationCode> m_prf; + }; + +/** + * NIST SP 800-108 KDF in Feedback Mode (5.2) + */ +class BOTAN_DLL SP800_108_Feedback : public KDF + { + public: + std::string name() const override { return "SP800-108-Feedback(" + m_prf->name() + ")"; } + + KDF* clone() const override { return new SP800_108_Feedback(m_prf->clone()); } + + size_t kdf(byte key[], size_t key_len, + const byte secret[], size_t secret_len, + const byte salt[], size_t salt_len) const override; + + SP800_108_Feedback(MessageAuthenticationCode* mac) : m_prf(mac) {} + + static SP800_108_Feedback* make(const Spec& spec); + private: + std::unique_ptr<MessageAuthenticationCode> m_prf; + }; + +/** + * NIST SP 800-108 KDF in Double Pipeline Mode (5.3) + */ +class BOTAN_DLL SP800_108_Pipeline : public KDF + { + public: + std::string name() const override { return "SP800-108-Pipeline(" + m_prf->name() + ")"; } + + KDF* clone() const override { return new SP800_108_Pipeline(m_prf->clone()); } + + size_t kdf(byte key[], size_t key_len, + const byte secret[], size_t secret_len, + const byte salt[], size_t salt_len) const override; + + SP800_108_Pipeline(MessageAuthenticationCode* mac) : m_prf(mac) {} + + static SP800_108_Pipeline* make(const Spec& spec); + private: + std::unique_ptr<MessageAuthenticationCode> m_prf; + }; + +} + +#endif diff --git a/src/lib/kdf/sp800_56c/info.txt b/src/lib/kdf/sp800_56c/info.txt new file mode 100644 index 000000000..203c05a83 --- /dev/null +++ b/src/lib/kdf/sp800_56c/info.txt @@ -0,0 +1,6 @@ +define SP800_56C 20160211 + +<requires> +sp800_108 +hmac +</requires> diff --git a/src/lib/kdf/sp800_56c/sp800_56c.cpp b/src/lib/kdf/sp800_56c/sp800_56c.cpp new file mode 100644 index 000000000..664d32b30 --- /dev/null +++ b/src/lib/kdf/sp800_56c/sp800_56c.cpp @@ -0,0 +1,45 @@ +/* +* KDF defined in NIST SP 800-56c +* (C) 2016 Kai Michaelis +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/sp800_108.h> +#include <botan/sp800_56c.h> +#include <botan/hmac.h> + +namespace Botan { + +SP800_56C* SP800_56C::make(const Spec& spec) + { + if(auto exp = SP800_108_Feedback::make(spec)) + { + if(auto mac = MessageAuthenticationCode::create(spec.arg(0))) + return new SP800_56C(mac.release(), exp); + + if(auto mac = MessageAuthenticationCode::create("HMAC(" + spec.arg(0) + ")")) + return new SP800_56C(mac.release(), exp); + } + + return nullptr; + } + +size_t SP800_56C::kdf(byte key[], size_t key_len, + const byte secret[], size_t secret_len, + const byte salt[], size_t salt_len) const + { + // Randomness Extraction + secure_vector< byte > k_dk, context; + + m_prf->set_key(salt, salt_len); + m_prf->update(secret, secret_len); + m_prf->final(k_dk); + + // Key Expansion + m_exp->kdf(key, key_len, k_dk.data(), k_dk.size(), context.data(), context.size()); + + return key_len; + } + +} diff --git a/src/lib/kdf/sp800_56c/sp800_56c.h b/src/lib/kdf/sp800_56c/sp800_56c.h new file mode 100644 index 000000000..d1b6f39b5 --- /dev/null +++ b/src/lib/kdf/sp800_56c/sp800_56c.h @@ -0,0 +1,39 @@ +/* +* KDF defined in NIST SP 800-56c +* (C) 2016 Kai Michaelis +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SP800_56C_H__ +#define BOTAN_SP800_56C_H__ + +#include <botan/kdf.h> +#include <botan/mac.h> + +namespace Botan { + +/** + * NIST SP 800-56C KDF + */ +class BOTAN_DLL SP800_56C : public KDF + { + public: + std::string name() const override { return "SP800-56C(" + m_prf->name() + ")"; } + + KDF* clone() const override { return new SP800_56C(m_prf->clone(), m_exp->clone()); } + + size_t kdf(byte key[], size_t key_len, + const byte secret[], size_t secret_len, + const byte salt[], size_t salt_len) const override; + + SP800_56C(MessageAuthenticationCode* mac, KDF* exp) : m_prf(mac), m_exp(exp) {} + + static SP800_56C* make(const Spec& spec); + private: + std::unique_ptr<MessageAuthenticationCode> m_prf; + std::unique_ptr<KDF> m_exp; + }; +} + +#endif diff --git a/src/lib/math/numbertheory/mp_numth.cpp b/src/lib/math/numbertheory/mp_numth.cpp index 6eb938286..3373b9ee7 100644 --- a/src/lib/math/numbertheory/mp_numth.cpp +++ b/src/lib/math/numbertheory/mp_numth.cpp @@ -71,4 +71,18 @@ BigInt sub_mul(const BigInt& a, const BigInt& b, const BigInt& c) return r; } +/* +* Multiply-Subtract Operation +*/ +BigInt mul_sub(const BigInt& a, const BigInt& b, const BigInt& c) + { + if(c.is_negative() || c.is_zero()) + throw Invalid_Argument("mul_sub: Third argument must be > 0"); + + BigInt r = a; + r *= b; + r -= c; + return r; + } + } diff --git a/src/lib/math/numbertheory/numthry.h b/src/lib/math/numbertheory/numthry.h index e1e6c65f6..591b61f6a 100644 --- a/src/lib/math/numbertheory/numthry.h +++ b/src/lib/math/numbertheory/numthry.h @@ -37,6 +37,17 @@ BigInt BOTAN_DLL sub_mul(const BigInt& a, const BigInt& c); /** +* Fused multiply-subtract +* @param a an integer +* @param b an integer +* @param c an integer +* @return (a*b)-c +*/ +BigInt BOTAN_DLL mul_sub(const BigInt& a, + const BigInt& b, + const BigInt& c); + +/** * Return the absolute value * @param n an integer * @return absolute value of n diff --git a/src/lib/misc/pbes2/pbes2.h b/src/lib/misc/pbes2/pbes2.h index 90aa4f84b..ea2f9aa1d 100644 --- a/src/lib/misc/pbes2/pbes2.h +++ b/src/lib/misc/pbes2/pbes2.h @@ -8,8 +8,7 @@ #ifndef BOTAN_PBE_PKCS_v20_H__ #define BOTAN_PBE_PKCS_v20_H__ -#include <botan/secmem.h> -#include <botan/transform.h> +#include <botan/rng.h> #include <botan/alg_id.h> #include <chrono> diff --git a/src/lib/modes/aead/aead.cpp b/src/lib/modes/aead/aead.cpp index 3d04887d0..88e6cbeaa 100644 --- a/src/lib/modes/aead/aead.cpp +++ b/src/lib/modes/aead/aead.cpp @@ -41,8 +41,8 @@ BOTAN_REGISTER_BLOCK_CIPHER_MODE_LEN2(CCM_Encryption, CCM_Decryption, 16, 3); #endif #if defined(BOTAN_HAS_AEAD_CHACHA20_POLY1305) -BOTAN_REGISTER_TRANSFORM_NOARGS(ChaCha20Poly1305_Encryption); -BOTAN_REGISTER_TRANSFORM_NOARGS(ChaCha20Poly1305_Decryption); +BOTAN_REGISTER_T_NOARGS(Cipher_Mode, ChaCha20Poly1305_Encryption); +BOTAN_REGISTER_T_NOARGS(Cipher_Mode, ChaCha20Poly1305_Decryption); #endif #if defined(BOTAN_HAS_AEAD_EAX) diff --git a/src/lib/modes/cipher_mode.cpp b/src/lib/modes/cipher_mode.cpp index acd5e23e2..e7040772c 100644 --- a/src/lib/modes/cipher_mode.cpp +++ b/src/lib/modes/cipher_mode.cpp @@ -29,10 +29,13 @@ namespace Botan { +#define BOTAN_REGISTER_CIPHER_MODE(name, maker) BOTAN_REGISTER_T(Cipher_Mode, name, maker) +#define BOTAN_REGISTER_CIPHER_MODE_NOARGS(name) BOTAN_REGISTER_T_NOARGS(Cipher_Mode, name) + #if defined(BOTAN_HAS_MODE_ECB) template<typename T> -Transform* make_ecb_mode(const Transform::Spec& spec) +Cipher_Mode* make_ecb_mode(const Cipher_Mode::Spec& spec) { std::unique_ptr<BlockCipher> bc(BlockCipher::create(spec.arg(0))); std::unique_ptr<BlockCipherModePaddingMethod> pad(get_bc_pad(spec.arg(1, "NoPadding"))); @@ -41,14 +44,14 @@ Transform* make_ecb_mode(const Transform::Spec& spec) return nullptr; } -BOTAN_REGISTER_TRANSFORM(ECB_Encryption, make_ecb_mode<ECB_Encryption>); -BOTAN_REGISTER_TRANSFORM(ECB_Decryption, make_ecb_mode<ECB_Decryption>); +BOTAN_REGISTER_CIPHER_MODE(ECB_Encryption, make_ecb_mode<ECB_Encryption>); +BOTAN_REGISTER_CIPHER_MODE(ECB_Decryption, make_ecb_mode<ECB_Decryption>); #endif #if defined(BOTAN_HAS_MODE_CBC) template<typename CBC_T, typename CTS_T> -Transform* make_cbc_mode(const Transform::Spec& spec) +Cipher_Mode* make_cbc_mode(const Cipher_Mode::Spec& spec) { std::unique_ptr<BlockCipher> bc(BlockCipher::create(spec.arg(0))); @@ -65,8 +68,8 @@ Transform* make_cbc_mode(const Transform::Spec& spec) return nullptr; } -BOTAN_REGISTER_TRANSFORM(CBC_Encryption, (make_cbc_mode<CBC_Encryption,CTS_Encryption>)); -BOTAN_REGISTER_TRANSFORM(CBC_Decryption, (make_cbc_mode<CBC_Decryption,CTS_Decryption>)); +BOTAN_REGISTER_CIPHER_MODE(CBC_Encryption, (make_cbc_mode<CBC_Encryption,CTS_Encryption>)); +BOTAN_REGISTER_CIPHER_MODE(CBC_Decryption, (make_cbc_mode<CBC_Decryption,CTS_Decryption>)); #endif #if defined(BOTAN_HAS_MODE_CFB) @@ -83,14 +86,17 @@ Cipher_Mode* get_cipher_mode(const std::string& algo_spec, Cipher_Dir direction) const char* dir_string = (direction == ENCRYPTION) ? "_Encryption" : "_Decryption"; - std::unique_ptr<Transform> t; + Cipher_Mode::Spec spec(algo_spec, dir_string); - t.reset(get_transform(algo_spec, provider, dir_string)); + std::unique_ptr<Cipher_Mode> cipher_mode( + Algo_Registry<Cipher_Mode>::global_registry().make( + Cipher_Mode::Spec(algo_spec, dir_string), + provider) + ); - if(Cipher_Mode* cipher = dynamic_cast<Cipher_Mode*>(t.get())) + if(cipher_mode) { - t.release(); - return cipher; + return cipher_mode.release(); } const std::vector<std::string> algo_parts = split_on(algo_spec, '/'); @@ -115,24 +121,32 @@ Cipher_Mode* get_cipher_mode(const std::string& algo_spec, Cipher_Dir direction) const std::string mode_name = mode_info[0] + alg_args.str(); const std::string mode_name_directional = mode_info[0] + dir_string + alg_args.str(); - t.reset(get_transform(mode_name_directional, provider)); + cipher_mode.reset( + Algo_Registry<Cipher_Mode>::global_registry().make( + Cipher_Mode::Spec(mode_name_directional), + provider) + ); - if(Cipher_Mode* cipher = dynamic_cast<Cipher_Mode*>(t.get())) + if(cipher_mode) { - t.release(); - return cipher; + return cipher_mode.release(); } - t.reset(get_transform(mode_name, provider)); + cipher_mode.reset( + Algo_Registry<Cipher_Mode>::global_registry().make( + Cipher_Mode::Spec(mode_name), + provider) + ); - if(Cipher_Mode* cipher = dynamic_cast<Cipher_Mode*>(t.get())) + if(cipher_mode) { - t.release(); - return cipher; + return cipher_mode.release(); } if(auto sc = StreamCipher::create(mode_name, provider)) + { return new Stream_Cipher_Mode(sc.release()); + } return nullptr; } diff --git a/src/lib/modes/cipher_mode.h b/src/lib/modes/cipher_mode.h index 63821005d..73a5f7d96 100644 --- a/src/lib/modes/cipher_mode.h +++ b/src/lib/modes/cipher_mode.h @@ -8,17 +8,123 @@ #ifndef BOTAN_CIPHER_MODE_H__ #define BOTAN_CIPHER_MODE_H__ -#include <botan/transform.h> -#include <botan/stream_cipher.h> +#include <botan/secmem.h> +#include <botan/key_spec.h> +#include <botan/exceptn.h> +#include <botan/symkey.h> +#include <botan/scan_name.h> +#include <string> +#include <vector> namespace Botan { /** * Interface for cipher modes */ -class BOTAN_DLL Cipher_Mode : public Keyed_Transform +class BOTAN_DLL Cipher_Mode { public: + typedef SCAN_Name Spec; + + virtual ~Cipher_Mode() {} + + /** + * Begin processing a message. + * @param nonce the per message nonce + */ + template<typename Alloc> + secure_vector<byte> start(const std::vector<byte, Alloc>& nonce) + { + return start(nonce.data(), nonce.size()); + } + + /** + * Begin processing a message. + * @param nonce the per message nonce + */ + template<typename Alloc> + BOTAN_DEPRECATED("Use Transform::start") + secure_vector<byte> start_vec(const std::vector<byte, Alloc>& nonce) + { + return start(nonce.data(), nonce.size()); + } + + /** + * Begin processing a message. + * @param nonce the per message nonce + * @param nonce_len length of nonce + */ + secure_vector<byte> start(const byte nonce[], size_t nonce_len) + { + return start_raw(nonce, nonce_len); + } + + /** + * Begin processing a message. + */ + secure_vector<byte> start() + { + return start_raw(nullptr, 0); + } + + virtual secure_vector<byte> start_raw(const byte nonce[], size_t nonce_len) = 0; + + /** + * Process some data. Input must be in size update_granularity() byte blocks. + * @param blocks in/out parameter which will possibly be resized + * @param offset an offset into blocks to begin processing + */ + virtual void update(secure_vector<byte>& blocks, size_t offset = 0) = 0; + + /** + * 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<byte>& 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; + + /** + * Return some short name describing the provider of this tranformation. + * Useful in cases where multiple implementations are available (eg, + * different implementations of AES). Default "core" is used for the + * 'standard' implementation included in the library. + */ + virtual std::string provider() const { return "core"; } + + virtual std::string name() const = 0; + + virtual void clear() = 0; + /** * Returns true iff this mode provides authentication as well as * confidentiality. @@ -29,6 +135,47 @@ class BOTAN_DLL Cipher_Mode : public Keyed_Transform * 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); + } + + template<typename Alloc> + void set_key(const std::vector<byte, Alloc>& key) + { + set_key(key.data(), key.size()); + } + + 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 byte key[], size_t length) + { + if(!valid_keylength(length)) + throw Invalid_Key_Length(name(), length); + key_schedule(key, length); + } + + private: + virtual void key_schedule(const byte key[], size_t length) = 0; }; /** diff --git a/src/lib/modes/mode_utils.h b/src/lib/modes/mode_utils.h index 44524c4f6..3e4b7370b 100644 --- a/src/lib/modes/mode_utils.h +++ b/src/lib/modes/mode_utils.h @@ -18,7 +18,7 @@ namespace Botan { template<typename T> -T* make_block_cipher_mode(const Transform::Spec& spec) +T* make_block_cipher_mode(const Cipher_Mode::Spec& spec) { if(std::unique_ptr<BlockCipher> bc = BlockCipher::create(spec.arg(0))) return new T(bc.release()); @@ -26,7 +26,7 @@ T* make_block_cipher_mode(const Transform::Spec& spec) } template<typename T, size_t LEN1> -T* make_block_cipher_mode_len(const Transform::Spec& spec) +T* make_block_cipher_mode_len(const Cipher_Mode::Spec& spec) { if(std::unique_ptr<BlockCipher> bc = BlockCipher::create(spec.arg(0))) { @@ -38,7 +38,7 @@ T* make_block_cipher_mode_len(const Transform::Spec& spec) } template<typename T, size_t LEN1, size_t LEN2> -T* make_block_cipher_mode_len2(const Transform::Spec& spec) +T* make_block_cipher_mode_len2(const Cipher_Mode::Spec& spec) { if(std::unique_ptr<BlockCipher> bc = BlockCipher::create(spec.arg(0))) { @@ -51,16 +51,16 @@ T* make_block_cipher_mode_len2(const Transform::Spec& spec) } #define BOTAN_REGISTER_BLOCK_CIPHER_MODE(E, D) \ - BOTAN_REGISTER_NAMED_T(Transform, #E, E, make_block_cipher_mode<E>); \ - BOTAN_REGISTER_NAMED_T(Transform, #D, D, make_block_cipher_mode<D>) + BOTAN_REGISTER_NAMED_T(Cipher_Mode, #E, E, make_block_cipher_mode<E>); \ + BOTAN_REGISTER_NAMED_T(Cipher_Mode, #D, D, make_block_cipher_mode<D>) #define BOTAN_REGISTER_BLOCK_CIPHER_MODE_LEN(E, D, LEN) \ - BOTAN_REGISTER_NAMED_T(Transform, #E, E, (make_block_cipher_mode_len<E, LEN>)); \ - BOTAN_REGISTER_NAMED_T(Transform, #D, D, (make_block_cipher_mode_len<D, LEN>)) + BOTAN_REGISTER_NAMED_T(Cipher_Mode, #E, E, (make_block_cipher_mode_len<E, LEN>)); \ + BOTAN_REGISTER_NAMED_T(Cipher_Mode, #D, D, (make_block_cipher_mode_len<D, LEN>)) #define BOTAN_REGISTER_BLOCK_CIPHER_MODE_LEN2(E, D, LEN1, LEN2) \ - BOTAN_REGISTER_NAMED_T(Transform, #E, E, (make_block_cipher_mode_len2<E, LEN1, LEN2>)); \ - BOTAN_REGISTER_NAMED_T(Transform, #D, D, (make_block_cipher_mode_len2<D, LEN1, LEN2>)) + BOTAN_REGISTER_NAMED_T(Cipher_Mode, #E, E, (make_block_cipher_mode_len2<E, LEN1, LEN2>)); \ + BOTAN_REGISTER_NAMED_T(Cipher_Mode, #D, D, (make_block_cipher_mode_len2<D, LEN1, LEN2>)) } diff --git a/src/lib/pubkey/ecc_key/ecc_key.cpp b/src/lib/pubkey/ecc_key/ecc_key.cpp index 2dca20725..befc2cc4c 100644 --- a/src/lib/pubkey/ecc_key/ecc_key.cpp +++ b/src/lib/pubkey/ecc_key/ecc_key.cpp @@ -33,7 +33,10 @@ EC_PublicKey::EC_PublicKey(const EC_Group& dom_par, } EC_PublicKey::EC_PublicKey(const AlgorithmIdentifier& alg_id, - const secure_vector<byte>& key_bits) : m_domain_params{EC_Group(alg_id.parameters)}, m_public_key{OS2ECP(key_bits, domain().get_curve())}, m_domain_encoding{EC_DOMPAR_ENC_EXPLICIT} + const secure_vector<byte>& key_bits) : + m_domain_params{EC_Group(alg_id.parameters)}, + m_public_key{OS2ECP(key_bits, domain().get_curve())}, + m_domain_encoding{EC_DOMPAR_ENC_EXPLICIT} {} bool EC_PublicKey::check_key(RandomNumberGenerator&, @@ -80,17 +83,23 @@ const BigInt& EC_PrivateKey::private_value() const */ EC_PrivateKey::EC_PrivateKey(RandomNumberGenerator& rng, const EC_Group& ec_group, - const BigInt& x) + const BigInt& x, + bool with_modular_inverse) { m_domain_params = ec_group; m_domain_encoding = EC_DOMPAR_ENC_EXPLICIT; if(x == 0) + { m_private_key = BigInt::random_integer(rng, 1, domain().get_order()); + } else + { m_private_key = x; + } - m_public_key = domain().get_base_point() * m_private_key; + m_public_key = domain().get_base_point() * + ((with_modular_inverse) ? inverse_mod(m_private_key, m_domain_params.get_order()) : m_private_key); BOTAN_ASSERT(m_public_key.on_the_curve(), "Generated public key point was on the curve"); @@ -108,7 +117,8 @@ secure_vector<byte> EC_PrivateKey::pkcs8_private_key() const } EC_PrivateKey::EC_PrivateKey(const AlgorithmIdentifier& alg_id, - const secure_vector<byte>& key_bits) + const secure_vector<byte>& key_bits, + bool with_modular_inverse) { m_domain_params = EC_Group(alg_id.parameters); m_domain_encoding = EC_DOMPAR_ENC_EXPLICIT; @@ -129,7 +139,8 @@ EC_PrivateKey::EC_PrivateKey(const AlgorithmIdentifier& alg_id, if(public_key_bits.empty()) { - m_public_key = domain().get_base_point() * m_private_key; + m_public_key = domain().get_base_point() * + ((with_modular_inverse) ? inverse_mod(m_private_key, m_domain_params.get_order()) : m_private_key); BOTAN_ASSERT(m_public_key.on_the_curve(), "Public point derived from loaded key was on the curve"); diff --git a/src/lib/pubkey/ecc_key/ecc_key.h b/src/lib/pubkey/ecc_key/ecc_key.h index 3f93a908c..a8e77b895 100644 --- a/src/lib/pubkey/ecc_key/ecc_key.h +++ b/src/lib/pubkey/ecc_key/ecc_key.h @@ -96,12 +96,30 @@ class BOTAN_DLL EC_PrivateKey : public virtual EC_PublicKey, public virtual Private_Key { public: - EC_PrivateKey(RandomNumberGenerator& rng, - const EC_Group& domain, - const BigInt& private_key); - + /* + * If x=0, creates a new private key in the domain + * using the given rng. If with_modular_inverse is set, + * the public key will be calculated by multiplying + * the base point with the modular inverse of + * x (as in ECGDSA and ECKCDSA), otherwise by + * multiplying directly with x (as in ECDSA). + */ + EC_PrivateKey(RandomNumberGenerator& rng, + const EC_Group& domain, + const BigInt& x, + bool with_modular_inverse=false); + + /* + * Creates a new private key object from the given + * key_bits. If with_modular_inverse is set, + * the public key will be calculated by multiplying + * the base point with the modular inverse of + * x (as in ECGDSA and ECKCDSA), otherwise by + * multiplying directly with x (as in ECDSA). + */ EC_PrivateKey(const AlgorithmIdentifier& alg_id, - const secure_vector<byte>& key_bits); + const secure_vector<byte>& key_bits, + bool with_modular_inverse=false); secure_vector<byte> pkcs8_private_key() const override; diff --git a/src/lib/pubkey/ecdsa/ecdsa.h b/src/lib/pubkey/ecdsa/ecdsa.h index 1eb41a4b9..eed09afe6 100644 --- a/src/lib/pubkey/ecdsa/ecdsa.h +++ b/src/lib/pubkey/ecdsa/ecdsa.h @@ -78,7 +78,7 @@ class BOTAN_DLL ECDSA_PrivateKey : public ECDSA_PublicKey, * Generate a new private key * @param rng a random number generator * @param domain parameters to used for this key - * @param x the private key (if zero, generate a ney random key) + * @param x the private key (if zero, generate a new random key) */ ECDSA_PrivateKey(RandomNumberGenerator& rng, const EC_Group& domain, diff --git a/src/lib/pubkey/ecgdsa/ecgdsa.cpp b/src/lib/pubkey/ecgdsa/ecgdsa.cpp new file mode 100644 index 000000000..b28e3fe96 --- /dev/null +++ b/src/lib/pubkey/ecgdsa/ecgdsa.cpp @@ -0,0 +1,148 @@ +/* +* ECGDSA (BSI-TR-03111, version 2.0) +* (C) 2016 René Korthaus +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/internal/pk_utils.h> +#include <botan/ecgdsa.h> +#include <botan/keypair.h> + +namespace Botan { + +bool ECGDSA_PrivateKey::check_key(RandomNumberGenerator& rng, + bool strong) const + { + if(!public_point().on_the_curve()) + return false; + + if(!strong) + return true; + + return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-1)"); + } + +namespace { + +/** +* ECGDSA signature operation +*/ +class ECGDSA_Signature_Operation : public PK_Ops::Signature_with_EMSA + { + public: + typedef ECGDSA_PrivateKey Key_Type; + + ECGDSA_Signature_Operation(const ECGDSA_PrivateKey& ecgdsa, + const std::string& emsa) : + PK_Ops::Signature_with_EMSA(emsa), + m_order(ecgdsa.domain().get_order()), + m_base_point(ecgdsa.domain().get_base_point(), m_order), + m_x(ecgdsa.private_value()), + m_mod_order(m_order) + { + } + + secure_vector<byte> raw_sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng) override; + + size_t message_parts() const override { return 2; } + size_t message_part_size() const override { return m_order.bytes(); } + size_t max_input_bits() const override { return m_order.bits(); } + + private: + const BigInt& m_order; + Blinded_Point_Multiply m_base_point; + const BigInt& m_x; + Modular_Reducer m_mod_order; + }; + +secure_vector<byte> +ECGDSA_Signature_Operation::raw_sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng) + { + const BigInt m(msg, msg_len); + + BigInt k = BigInt::random_integer(rng, 1, m_order); + + const PointGFp k_times_P = m_base_point.blinded_multiply(k, rng); + const BigInt r = m_mod_order.reduce(k_times_P.get_affine_x()); + const BigInt s = m_mod_order.multiply(m_x, mul_sub(k, r, m)); + + // With overwhelming probability, a bug rather than actual zero r/s + BOTAN_ASSERT(s != 0, "invalid s"); + BOTAN_ASSERT(r != 0, "invalid r"); + + secure_vector<byte> output(2*m_order.bytes()); + r.binary_encode(&output[output.size() / 2 - r.bytes()]); + s.binary_encode(&output[output.size() - s.bytes()]); + return output; + } + +/** +* ECGDSA verification operation +*/ +class ECGDSA_Verification_Operation : public PK_Ops::Verification_with_EMSA + { + public: + typedef ECGDSA_PublicKey Key_Type; + + ECGDSA_Verification_Operation(const ECGDSA_PublicKey& ecgdsa, + const std::string& emsa) : + PK_Ops::Verification_with_EMSA(emsa), + m_base_point(ecgdsa.domain().get_base_point()), + m_public_point(ecgdsa.public_point()), + m_order(ecgdsa.domain().get_order()), + m_mod_order(m_order) + { + } + + size_t message_parts() const override { return 2; } + size_t message_part_size() const override { return m_order.bytes(); } + size_t max_input_bits() const override { return m_order.bits(); } + + bool with_recovery() const override { return false; } + + bool verify(const byte msg[], size_t msg_len, + const byte sig[], size_t sig_len) override; + private: + const PointGFp& m_base_point; + const PointGFp& m_public_point; + const BigInt& m_order; + // FIXME: should be offered by curve + Modular_Reducer m_mod_order; + }; + +bool ECGDSA_Verification_Operation::verify(const byte msg[], size_t msg_len, + const byte sig[], size_t sig_len) + { + if(sig_len != m_order.bytes()*2) + return false; + + BigInt e(msg, msg_len); + + BigInt r(sig, sig_len / 2); + BigInt s(sig + sig_len / 2, sig_len / 2); + + if(r <= 0 || r >= m_order || s <= 0 || s >= m_order) + return false; + + BigInt w = inverse_mod(r, m_order); + + const BigInt u1 = m_mod_order.reduce(e * w); + const BigInt u2 = m_mod_order.reduce(s * w); + const PointGFp R = multi_exponentiate(m_base_point, u1, m_public_point, u2); + + if(R.is_zero()) + return false; + + const BigInt v = m_mod_order.reduce(R.get_affine_x()); + return (v == r); + } + +BOTAN_REGISTER_PK_SIGNATURE_OP("ECGDSA", ECGDSA_Signature_Operation); +BOTAN_REGISTER_PK_VERIFY_OP("ECGDSA", ECGDSA_Verification_Operation); + +} + +} diff --git a/src/lib/pubkey/ecgdsa/ecgdsa.h b/src/lib/pubkey/ecgdsa/ecgdsa.h new file mode 100644 index 000000000..518adeeab --- /dev/null +++ b/src/lib/pubkey/ecgdsa/ecgdsa.h @@ -0,0 +1,91 @@ +/* +* ECGDSA (BSI-TR-03111, version 2.0) +* (C) 2016 René Korthaus +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ECGDSA_KEY_H__ +#define BOTAN_ECGDSA_KEY_H__ + +#include <botan/ecc_key.h> + +namespace Botan { + +/** +* This class represents ECGDSA public keys. +*/ +class BOTAN_DLL ECGDSA_PublicKey : public virtual EC_PublicKey + { + public: + + /** + * Construct a public key from a given public point. + * @param dom_par the domain parameters associated with this key + * @param public_point the public point defining this key + */ + ECGDSA_PublicKey(const EC_Group& dom_par, + const PointGFp& public_point) : + EC_PublicKey(dom_par, public_point) {} + + ECGDSA_PublicKey(const AlgorithmIdentifier& alg_id, + const secure_vector<byte>& key_bits) : + EC_PublicKey(alg_id, key_bits) {} + + /** + * Get this keys algorithm name. + * @result this keys algorithm name ("ECGDSA") + */ + std::string algo_name() const override { return "ECGDSA"; } + + /** + * Get the maximum number of bits allowed to be fed to this key. + * This is the bitlength of the order of the base point. + * @result the maximum number of input bits + */ + size_t max_input_bits() const override + { return domain().get_order().bits(); } + + size_t message_parts() const override { return 2; } + + size_t message_part_size() const override + { return domain().get_order().bytes(); } + + protected: + ECGDSA_PublicKey() {} + }; + +/** +* This class represents ECGDSA private keys. +*/ +class BOTAN_DLL ECGDSA_PrivateKey : public ECGDSA_PublicKey, + public EC_PrivateKey + { + public: + + /** + * Load a private key + * @param alg_id the X.509 algorithm identifier + * @param key_bits PKCS #8 structure + */ + ECGDSA_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector<byte>& key_bits) : + EC_PrivateKey(alg_id, key_bits, true) {} + + /** + * Generate a new private key + * @param rng a random number generator + * @param domain parameters to used for this key + * @param x the private key (if zero, generate a new random key) + */ + ECGDSA_PrivateKey(RandomNumberGenerator& rng, + const EC_Group& domain, + const BigInt& x = 0) : + EC_PrivateKey(rng, domain, x, true) {} + + bool check_key(RandomNumberGenerator& rng, bool) const override; + }; + +} + +#endif diff --git a/src/lib/pubkey/ecgdsa/info.txt b/src/lib/pubkey/ecgdsa/info.txt new file mode 100644 index 000000000..6c18a1440 --- /dev/null +++ b/src/lib/pubkey/ecgdsa/info.txt @@ -0,0 +1,11 @@ +define ECGDSA 20160301 + +<requires> +asn1 +bigint +ec_group +ecc_key +keypair +numbertheory +rng +</requires> diff --git a/src/lib/pubkey/pk_algs.cpp b/src/lib/pubkey/pk_algs.cpp index 689237a84..d2947b0c0 100644 --- a/src/lib/pubkey/pk_algs.cpp +++ b/src/lib/pubkey/pk_algs.cpp @@ -24,6 +24,10 @@ #include <botan/ecdsa.h> #endif +#if defined(BOTAN_HAS_ECGDSA) + #include <botan/ecgdsa.h> +#endif + #if defined(BOTAN_HAS_GOST_34_10_2001) #include <botan/gost_3410.h> #endif @@ -96,6 +100,11 @@ Public_Key* make_public_key(const AlgorithmIdentifier& alg_id, return new ECDSA_PublicKey(alg_id, key_bits); #endif +#if defined(BOTAN_HAS_ECGDSA) + if(alg_name == "ECGDSA") + return new ECGDSA_PublicKey(alg_id, key_bits); +#endif + #if defined(BOTAN_HAS_GOST_34_10_2001) if(alg_name == "GOST-34.10") return new GOST_3410_PublicKey(alg_id, key_bits); @@ -162,6 +171,11 @@ Private_Key* make_private_key(const AlgorithmIdentifier& alg_id, return new ECDSA_PrivateKey(alg_id, key_bits); #endif +#if defined(BOTAN_HAS_ECGDSA) + if(alg_name == "ECGDSA") + return new ECGDSA_PrivateKey(alg_id, key_bits); +#endif + #if defined(BOTAN_HAS_GOST_34_10_2001) if(alg_name == "GOST-34.10") return new GOST_3410_PrivateKey(alg_id, key_bits); diff --git a/src/lib/rng/auto_rng/auto_rng.h b/src/lib/rng/auto_rng/auto_rng.h index ce0c5a7d2..72ea88d3e 100644 --- a/src/lib/rng/auto_rng/auto_rng.h +++ b/src/lib/rng/auto_rng/auto_rng.h @@ -13,7 +13,7 @@ namespace Botan { -class BOTAN_DLL AutoSeeded_RNG : public RandomNumberGenerator +class AutoSeeded_RNG : public RandomNumberGenerator { public: void randomize(byte out[], size_t len) override diff --git a/src/lib/stream/chacha/chacha.cpp b/src/lib/stream/chacha/chacha.cpp index 0a32c720b..ac81fd70d 100644 --- a/src/lib/stream/chacha/chacha.cpp +++ b/src/lib/stream/chacha/chacha.cpp @@ -10,8 +10,18 @@ namespace Botan { -void ChaCha::chacha(byte output[64], const u32bit input[16]) +ChaCha::ChaCha(size_t rounds) : m_rounds(rounds) { + if(m_rounds != 12 && m_rounds != 20) + throw Invalid_Argument("ChaCha only supports 12 or 20 rounds"); + } + +namespace { + +void chacha(byte output[64], const u32bit input[16], size_t rounds) + { + BOTAN_ASSERT(rounds % 2 == 0, "Valid rounds"); + u32bit x00 = input[ 0], x01 = input[ 1], x02 = input[ 2], x03 = input[ 3], x04 = input[ 4], x05 = input[ 5], x06 = input[ 6], x07 = input[ 7], x08 = input[ 8], x09 = input[ 9], x10 = input[10], x11 = input[11], @@ -25,7 +35,7 @@ void ChaCha::chacha(byte output[64], const u32bit input[16]) c += d; b ^= c; b = rotate_left(b, 7); \ } while(0) - for(size_t i = 0; i != 10; ++i) + for(size_t i = 0; i != rounds / 2; ++i) { CHACHA_QUARTER_ROUND(x00, x04, x08, x12); CHACHA_QUARTER_ROUND(x01, x05, x09, x13); @@ -58,6 +68,8 @@ void ChaCha::chacha(byte output[64], const u32bit input[16]) store_le(x15 + input[15], output + 4 * 15); } +} + /* * Combine cipher stream with message */ @@ -69,7 +81,7 @@ void ChaCha::cipher(const byte in[], byte out[], size_t length) length -= (m_buffer.size() - m_position); in += (m_buffer.size() - m_position); out += (m_buffer.size() - m_position); - chacha(m_buffer.data(), m_state.data()); + chacha(m_buffer.data(), m_state.data(), m_rounds); ++m_state[12]; m_state[13] += (m_state[12] == 0); @@ -142,7 +154,7 @@ void ChaCha::set_iv(const byte iv[], size_t length) m_state[15] = load_le<u32bit>(iv, 2); } - chacha(m_buffer.data(), m_state.data()); + chacha(m_buffer.data(), m_state.data(), m_rounds); ++m_state[12]; m_state[13] += (m_state[12] == 0); @@ -156,4 +168,9 @@ void ChaCha::clear() m_position = 0; } +std::string ChaCha::name() const + { + return "ChaCha(" + std::to_string(m_rounds) + ")"; + } + } diff --git a/src/lib/stream/chacha/chacha.h b/src/lib/stream/chacha/chacha.h index 92f8ef035..ba93d6260 100644 --- a/src/lib/stream/chacha/chacha.h +++ b/src/lib/stream/chacha/chacha.h @@ -18,6 +18,14 @@ namespace Botan { class BOTAN_DLL ChaCha final : public StreamCipher { public: + StreamCipher* clone() const override { return new ChaCha(m_rounds); } + + /** + * Currently only 12 or 20 rounds are supported, all others + * will throw an exception + */ + ChaCha(size_t rounds); + void cipher(const byte in[], byte out[], size_t length) override; void set_iv(const byte iv[], size_t iv_len) override; @@ -31,14 +39,13 @@ class BOTAN_DLL ChaCha final : public StreamCipher } void clear() override; - std::string name() const override { return "ChaCha"; } - StreamCipher* clone() const override { return new ChaCha; } - protected: - virtual void chacha(byte output[64], const u32bit input[16]); + std::string name() const override; + private: void key_schedule(const byte key[], size_t key_len) override; + size_t m_rounds; secure_vector<u32bit> m_state; secure_vector<byte> m_buffer; size_t m_position = 0; diff --git a/src/lib/stream/stream_cipher.cpp b/src/lib/stream/stream_cipher.cpp index 03ef5e329..6f98df1fb 100644 --- a/src/lib/stream/stream_cipher.cpp +++ b/src/lib/stream/stream_cipher.cpp @@ -51,7 +51,7 @@ void StreamCipher::set_iv(const byte[], size_t iv_len) } #if defined(BOTAN_HAS_CHACHA) -BOTAN_REGISTER_T_NOARGS(StreamCipher, ChaCha); +BOTAN_REGISTER_T_1LEN(StreamCipher, ChaCha, 20); #endif #if defined(BOTAN_HAS_SALSA20) diff --git a/src/lib/stream/stream_cipher.h b/src/lib/stream/stream_cipher.h index 8c9b28147..bff1fd1a6 100644 --- a/src/lib/stream/stream_cipher.h +++ b/src/lib/stream/stream_cipher.h @@ -8,7 +8,6 @@ #ifndef BOTAN_STREAM_CIPHER_H__ #define BOTAN_STREAM_CIPHER_H__ -#include <botan/transform.h> #include <botan/sym_algo.h> #include <botan/scan_name.h> diff --git a/src/lib/tls/tls_reader.h b/src/lib/tls/tls_reader.h index b3c6db0c9..88bc4e932 100644 --- a/src/lib/tls/tls_reader.h +++ b/src/lib/tls/tls_reader.h @@ -50,10 +50,10 @@ class TLS_Data_Reader m_offset += bytes; } - u16bit get_u32bit() + u32bit get_u32bit() { assert_at_least(4); - u16bit result = make_u32bit(m_buf[m_offset ], m_buf[m_offset+1], + u32bit result = make_u32bit(m_buf[m_offset ], m_buf[m_offset+1], m_buf[m_offset+2], m_buf[m_offset+3]); m_offset += 4; return result; diff --git a/src/lib/tls/tls_record.cpp b/src/lib/tls/tls_record.cpp index efa6e2d18..8af6587e3 100644 --- a/src/lib/tls/tls_record.cpp +++ b/src/lib/tls/tls_record.cpp @@ -139,20 +139,16 @@ Connection_Cipher_State::format_ad(u64bit msg_sequence, Protocol_Version version, u16bit msg_length) { - std::vector<byte> m_ad; - m_ad.reserve(13); + std::vector<byte> ad(13); - for(size_t i = 0; i != 8; ++i) - m_ad.push_back(get_byte(i, msg_sequence)); - m_ad.push_back(msg_type); + store_be(msg_sequence, &ad[0]); + ad[8] = msg_type; + ad[9] = version.major_version(); + ad[10] = version.minor_version(); + ad[11] = get_byte(0, msg_length); + ad[12] = get_byte(1, msg_length); - m_ad.push_back(version.major_version()); - m_ad.push_back(version.minor_version()); - - m_ad.push_back(get_byte(0, msg_length)); - m_ad.push_back(get_byte(1, msg_length)); - - return m_ad; + return ad; } void write_record(secure_vector<byte>& output, @@ -425,7 +421,7 @@ void decrypt_record(secure_vector<byte>& output, u16bit pad_size = tls_padding_check(record_contents, record_len); // This mask is zero if there is not enough room in the packet - const u16bit size_ok_mask = CT::is_less<u16bit>(mac_size + pad_size + iv_size, record_len); + const u16bit size_ok_mask = CT::is_lte<u16bit>(mac_size + pad_size + iv_size, record_len); pad_size &= size_ok_mask; CT::unpoison(record_contents, record_len); @@ -454,9 +450,13 @@ void decrypt_record(secure_vector<byte>& output, CT::unpoison(ok_mask); if(ok_mask) + { output.assign(plaintext_block, plaintext_block + plaintext_length); + } else + { throw TLS_Exception(Alert::BAD_RECORD_MAC, "Message authentication failure"); + } } } diff --git a/src/lib/utils/ct_utils.h b/src/lib/utils/ct_utils.h index 5a1d03d4f..1f095ba88 100644 --- a/src/lib/utils/ct_utils.h +++ b/src/lib/utils/ct_utils.h @@ -129,6 +129,12 @@ inline T is_less(T x, T y) } template<typename T> +inline T is_lte(T x, T y) + { + return expand_mask<T>(x <= y); + } + +template<typename T> inline void conditional_copy_mem(T value, T* to, const T* from0, |