aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/asn1/oid_lookup/default.cpp10
-rw-r--r--src/lib/base/algo_registry.h4
-rw-r--r--src/lib/base/info.txt3
-rw-r--r--src/lib/base/transform.cpp20
-rw-r--r--src/lib/base/transform.h182
-rw-r--r--src/lib/block/threefish/threefish.cpp6
-rw-r--r--src/lib/compression/bzip2/bzip2.cpp12
-rw-r--r--src/lib/compression/bzip2/bzip2.h14
-rw-r--r--src/lib/compression/bzip2/info.txt2
-rw-r--r--src/lib/compression/compress_utils.h4
-rw-r--r--src/lib/compression/compression.cpp69
-rw-r--r--src/lib/compression/compression.h92
-rw-r--r--src/lib/compression/lzma/info.txt2
-rw-r--r--src/lib/compression/lzma/lzma.cpp9
-rw-r--r--src/lib/compression/lzma/lzma.h11
-rw-r--r--src/lib/compression/zlib/info.txt2
-rw-r--r--src/lib/compression/zlib/zlib.cpp31
-rw-r--r--src/lib/compression/zlib/zlib.h41
-rw-r--r--src/lib/filters/aead_filt.h6
-rw-r--r--src/lib/filters/cipher_filter.cpp114
-rw-r--r--src/lib/filters/cipher_filter.h (renamed from src/lib/filters/transform_filter.h)22
-rw-r--r--src/lib/filters/comp_filter.cpp84
-rw-r--r--src/lib/filters/comp_filter.h44
-rw-r--r--src/lib/filters/info.txt6
-rw-r--r--src/lib/filters/key_filt.cpp4
-rw-r--r--src/lib/filters/transform_filter.cpp119
-rw-r--r--src/lib/kdf/kdf.cpp17
-rw-r--r--src/lib/kdf/sp800_108/info.txt6
-rw-r--r--src/lib/kdf/sp800_108/sp800_108.cpp157
-rw-r--r--src/lib/kdf/sp800_108/sp800_108.h81
-rw-r--r--src/lib/kdf/sp800_56c/info.txt6
-rw-r--r--src/lib/kdf/sp800_56c/sp800_56c.cpp45
-rw-r--r--src/lib/kdf/sp800_56c/sp800_56c.h39
-rw-r--r--src/lib/math/numbertheory/mp_numth.cpp14
-rw-r--r--src/lib/math/numbertheory/numthry.h11
-rw-r--r--src/lib/misc/pbes2/pbes2.h3
-rw-r--r--src/lib/modes/aead/aead.cpp4
-rw-r--r--src/lib/modes/cipher_mode.cpp52
-rw-r--r--src/lib/modes/cipher_mode.h153
-rw-r--r--src/lib/modes/mode_utils.h18
-rw-r--r--src/lib/pubkey/ecc_key/ecc_key.cpp21
-rw-r--r--src/lib/pubkey/ecc_key/ecc_key.h28
-rw-r--r--src/lib/pubkey/ecdsa/ecdsa.h2
-rw-r--r--src/lib/pubkey/ecgdsa/ecgdsa.cpp148
-rw-r--r--src/lib/pubkey/ecgdsa/ecgdsa.h91
-rw-r--r--src/lib/pubkey/ecgdsa/info.txt11
-rw-r--r--src/lib/pubkey/pk_algs.cpp14
-rw-r--r--src/lib/rng/auto_rng/auto_rng.h2
-rw-r--r--src/lib/stream/chacha/chacha.cpp25
-rw-r--r--src/lib/stream/chacha/chacha.h15
-rw-r--r--src/lib/stream/stream_cipher.cpp2
-rw-r--r--src/lib/stream/stream_cipher.h1
-rw-r--r--src/lib/tls/tls_reader.h4
-rw-r--r--src/lib/tls/tls_record.cpp26
-rw-r--r--src/lib/utils/ct_utils.h6
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,