aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/hacking.rst129
-rw-r--r--doc/news.rst21
-rw-r--r--src/build-data/cc/clang.txt1
-rw-r--r--src/cli/asn1.cpp3
-rw-r--r--src/cli/bench.cpp10
-rw-r--r--src/cli/cli.h27
-rw-r--r--src/cli/pubkey.cpp93
-rw-r--r--src/cli/utils.cpp6
-rw-r--r--src/lib/math/mp/info.txt3
-rw-r--r--src/lib/math/mp/mp_asm.cpp2
-rw-r--r--src/lib/math/mp/mp_comba.cpp3
-rw-r--r--src/lib/math/mp/mp_core.h9
-rw-r--r--src/lib/math/mp/mp_karat.cpp45
-rw-r--r--src/lib/math/mp/mp_mulop.cpp73
-rw-r--r--src/lib/pk_pad/mgf1/mgf1.h6
-rw-r--r--src/lib/pubkey/mce/info.txt1
-rw-r--r--src/lib/pubkey/mce/mce_kem.cpp91
-rw-r--r--src/lib/pubkey/mce/mce_kem.h55
-rw-r--r--src/lib/pubkey/mceies/mceies.cpp13
-rw-r--r--src/lib/pubkey/pk_ops.cpp43
-rw-r--r--src/lib/pubkey/pk_ops.h40
-rw-r--r--src/lib/pubkey/pk_ops_impl.h40
-rw-r--r--src/lib/pubkey/pk_utils.h3
-rw-r--r--src/lib/pubkey/pubkey.cpp40
-rw-r--r--src/lib/pubkey/pubkey.h81
-rw-r--r--src/lib/pubkey/rsa/rsa.cpp62
-rw-r--r--src/lib/tls/tls_session_manager.h2
-rw-r--r--src/lib/utils/loadstor.h42
-rw-r--r--src/lib/utils/mem_ops.h15
-rwxr-xr-xsrc/scripts/comba.py8
-rw-r--r--src/tests/data/nist_x509/expected.txt76
-rw-r--r--src/tests/data/pubkey/rsa_kem.vec25
-rw-r--r--src/tests/main.cpp6
-rw-r--r--src/tests/test_dh.cpp2
-rw-r--r--src/tests/test_mceliece.cpp32
-rw-r--r--src/tests/test_pubkey.cpp135
-rw-r--r--src/tests/test_pubkey.h16
-rw-r--r--src/tests/test_rng.h2
-rw-r--r--src/tests/test_rsa.cpp20
-rw-r--r--src/tests/test_x509_path.cpp300
-rw-r--r--src/tests/tests.h1
41 files changed, 977 insertions, 605 deletions
diff --git a/doc/hacking.rst b/doc/hacking.rst
index 5f7d34e76..7c7ae3fb2 100644
--- a/doc/hacking.rst
+++ b/doc/hacking.rst
@@ -1,50 +1,49 @@
-
Source Code Layout
=================================================
-Under `src` there are directories
+Under ``src`` there are directories
-* `lib` is the library itself, more on that below
-* `cli` is the command line application `botan`
-* `tests` contain what you would expect. Input files go under `tests/data`.
-* `build-data` contains files read by the configure script. For
- example `build-data/cc/gcc.txt` describes various gcc options.
-* `scripts` contains misc scripts: install, distribution, various
- codegen things. Scripts controlling CI go under `scripts/ci`.
-* `python/botan.py` is the Python ctypes wrapper
+* ``lib`` is the library itself, more on that below
+* ``cli`` is the command line application ``botan``
+* ``tests`` contain what you would expect. Input files go under ``tests/data``.
+* ``build-data`` contains files read by the configure script. For
+ example ``build-data/cc/gcc.txt`` describes various gcc options.
+* ``scripts`` contains misc scripts: install, distribution, various
+ codegen things. Scripts controlling CI go under ``scripts/ci``.
+* ``python/botan.py`` is the Python ctypes wrapper
Library Layout
========================================
-* `base` defines some high level types
-* `utils` contains various utility functions and types
-* `codec` has hex, base64
-* `block` contains the block cipher implementations
-* `modes` contains block cipher modes (CBC, GCM, etc)
-* `stream` contains the stream ciphers
-* `hash` contains the hash function implementations
-* `passhash` contains password hashing algorithms for authentication
-* `kdf` contains the key derivation functions
-* `mac` contains the message authentication codes
-* `pbkdf` contains password hashing algorithms for key derivation
-* `math` is the math library for public key operations. It is divided into
- four parts: `mp` which are the low level algorithms; `bigint` which is
- a C++ wrapper around `mp`; `numbertheory` which contains algorithms like
- primality testing and exponentiation; and `ec_gfp` which defines elliptic
+* ``base`` defines some high level types
+* ``utils`` contains various utility functions and types
+* ``codec`` has hex, base64
+* ``block`` contains the block cipher implementations
+* ``modes`` contains block cipher modes (CBC, GCM, etc)
+* ``stream`` contains the stream ciphers
+* ``hash`` contains the hash function implementations
+* ``passhash`` contains password hashing algorithms for authentication
+* ``kdf`` contains the key derivation functions
+* ``mac`` contains the message authentication codes
+* ``pbkdf`` contains password hashing algorithms for key derivation
+* ``math`` is the math library for public key operations. It is divided into
+ four parts: ``mp`` which are the low level algorithms; ``bigint`` which is
+ a C++ wrapper around ``mp``; ``numbertheory`` which contains algorithms like
+ primality testing and exponentiation; and ``ec_gfp`` which defines elliptic
curves over prime fields.
-* `pubkey` contains the public key implementations
-* `pk_pad` contains padding schemes for public key algorithms
-* `rng` contains the random number generators
-* `entropy` has various entropy sources
-* `asn1` is the DER encoder/decoder
-* `cert` has `x509` (X.509 PKI OCSP is also here) and `cvc` (Card Verifiable Ceritifcates,
+* ``pubkey`` contains the public key implementations
+* ``pk_pad`` contains padding schemes for public key algorithms
+* ``rng`` contains the random number generators
+* ``entropy`` has various entropy sources
+* ``asn1`` is the DER encoder/decoder
+* ``cert`` has ``x509`` (X.509 PKI OCSP is also here) and ``cvc`` (Card Verifiable Ceritifcates,
for ePassports)
-* `tls` contains the TLS implementation
-* `filters` is a filter/pipe API for data transforms
-* `compression` has the compression wrappers (zlib, bzip2, lzma)
-* `ffi` is the C99 API
-* `prov` contains bindings to external libraries like OpenSSL
-* `misc` contains odds and ends: format preserving encryption, SRP, threshold
+* ``tls`` contains the TLS implementation
+* ``filters`` is a filter/pipe API for data transforms
+* ``compression`` has the compression wrappers (zlib, bzip2, lzma)
+* ``ffi`` is the C99 API
+* ``prov`` contains bindings to external libraries like OpenSSL
+* ``misc`` contains odds and ends: format preserving encryption, SRP, threshold
secret sharing, all or nothing transform, and others
Copyright Notice
@@ -66,7 +65,7 @@ change are consecutive, avoid year ranges: specify each year separated
by a comma.
Also if you are a new contributor or making an addition in a new year,
-include an update to `doc/license.txt` in your PR.
+include an update to ``doc/license.txt`` in your PR.
Style Conventions
========================================
@@ -84,32 +83,35 @@ some code calling your idealized API, then just implement that API.
This can often help avoid cut-and-paste by creating the correct
abstractions needed to solve the problem at hand.
-The C++11 `auto` keyword is very convenient but only use it when the
+The C++11 ``auto`` keyword is very convenient but only use it when the
type truly is obvious (considering also the potential for unexpected
integer conversions and the like, such as an apparent uint8_t being
promoted to an int).
-If a variable is defined and not modified, declare it `const`
+If a variable is defined and not modified, declare it ``const``.
+Some exception for very short-lived variables, but generally speaking
+being able to read the declaration and know it will not be modified
+is useful.
-Use `override` annotations whenever overriding a virtual function.
+Use ``override`` annotations whenever overriding a virtual function.
A formatting setup for emacs is included in `scripts/indent.el` but
the basic formatting style should be obvious. No tabs, and remove
trailing whitespace.
-Use m_ prefix on all member variables. The current code is not
+Use ``m_`` prefix on all member variables. The current code is not
consistent but all new code should use it.
Prefer using braces on both sides of if/else blocks, even if only
using a single statement. Again the current code doesn't always do
this.
-Avoid `using namespace` declarations, even inside of single functions.
-One allowed exception is `using namespace std::placeholders` in
-functions which use `std::bind`.
+Avoid ``using namespace`` declarations, even inside of single functions.
+One allowed exception is ``using namespace std::placeholders`` in
+functions which use ``std::bind``.
-Use `::` to explicitly refer to the global namespace (eg, when calling
-an OS or library function like `::select` or `::sqlite3_open`).
+Use ``::`` to explicitly refer to the global namespace (eg, when calling
+an OS or library function like ``::select`` or ``::sqlite3_open``).
Sending patches
========================================
@@ -120,16 +122,16 @@ change email the mailing list or open a discussion ticket on github
before starting out to make sure you are on the right path.
Depending on what your change is, your PR should probably also include
-an update to `doc/news.rst` with a note explaining the change. If your
+an update to ``doc/news.rst`` with a note explaining the change. If your
change is a simple bug fix, a one sentence description is perhaps
sufficient. If there is an existing ticket on GitHub with discussion
or other information, reference it in your change note as 'GH #000'.
-Update `doc/credits.txt` with your information so people know what
+Update ``doc/credits.txt`` with your information so people know what
you did! (This is optional)
If you are interested in contributing but don't know where to start
-check out `doc/todo.rst` for some ideas - these are changes we would
+check out ``doc/todo.rst`` for some ideas - these are changes we would
almost certainly accept once they've passed code review.
Also, try building and testing it on whatever hardware you have handy,
@@ -218,19 +220,34 @@ developers or auditors.
Python
========================================
-The house language for scripts is Python. The aim is to support 2.7 and latest
-3.x with the minimum possible number of explicit version checks (ideally zero).
-Support for CPython 2.6, PyPy, etc is a bonus but not required.
+Scripts should be in Python whenever possible.
+
+For configure.py (and install.py) the target is stock (no modules outside the
+standard library) CPython 2.7 plus latest CPython 3.x. Support for CPython 2.6,
+PyPy, etc is great when viable (in the sense of not causing problems for 2.7 or
+3.x, and not requiring huge blocks of version dependent code). As running this
+program succesfully is required for a working build making it as portable as
+possible is considered key.
+
+The python wrapper botan.py targets CPython 2.7, 3.x, and latest PyPy. Note that
+a single file is used to avoid dealing with any of Python's various crazy module
+distribution issues.
+
+For random scripts not typically run by an end-user (codegen, visualization, and
+so on) there isn't any need to worry about 2.6 and even just running under
+Python2 xor Python3 is acceptable if needed. Here it's fine to depend on any
+useful modules such as graphviz or matplotlib, regardless if it is available
+from a stock CPython install.
Build Tools and Hints
========================================
If you don't already use it for all your C/C++ development, install
-`ccache` now and configure a large cache on a fast disk. It allows for
+``ccache`` now and configure a large cache on a fast disk. It allows for
very quick rebuilds by caching the compiler output.
-Use `--with-sanitizers` to enable ASan. UBSan has to be added separately
-with --cc-abi-flags at the moment as GCC 4.8 does not have UBSan.
+Use ``--with-sanitizers`` to enable ASan. UBSan has to be added separately
+with ``--cc-abi-flags`` at the moment as GCC 4.8 does not have UBSan.
Other Ways You Can Help
========================================
diff --git a/doc/news.rst b/doc/news.rst
index 39753a752..e340033c4 100644
--- a/doc/news.rst
+++ b/doc/news.rst
@@ -4,6 +4,11 @@ Release Notes
Version 1.11.26, Not Yet Released
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+* Deprecation warning: Nyberg-Rueppel signatures, MARS, RC2, RC5, RC6,
+ SAFER, HAS-160, RIPEMD-128, and MD2 are being considered for removal
+ in a future release. If there is a compelling use case for keeping
+ any of them in the library, please open a discussion ticket on GitHub.
+
* Root all exceptions thrown by the library in the `Botan::Exception` class.
Previously the library would in many cases throw `std::runtime_error`
or `std::invalid_argument` exceptions which would make it hard to determine
@@ -21,6 +26,22 @@ Version 1.11.26, Not Yet Released
random number generation, RSA key generation, and signing are
supported. Tested using Trousers and an ST TPM
+* Add generalized interface for KEM (key encapsulation) techniques. Convert
+ McEliece KEM to use it. The previous interfaces McEliece_KEM_Encryptor and
+ McEliece_KEM_Decryptor have been removed. The new KEM interface now uses a KDF
+ to hash the resulting keys; to get the same output as previously provided by
+ McEliece_KEM_Encryptor, use "KDF1(SHA-512)" and request exactly 64 bytes.
+
+* Add support for RSA-KEM from ISO 18033-2
+
+* Avoid calling memcpy, memset, or memmove with a length of zero to
+ avoid undefined behavior, as calling these functions with an invalid
+ or null pointer, even with a length of zero, is invalid. Often there
+ are corner cases where this can occur, such as pointing to the very
+ end of a buffer.
+
+* Export MGF1 function mgf1_mask GH #380
+
Version 1.11.25, 2015-12-07
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/build-data/cc/clang.txt b/src/build-data/cc/clang.txt
index b290bbc13..3382f5d65 100644
--- a/src/build-data/cc/clang.txt
+++ b/src/build-data/cc/clang.txt
@@ -16,6 +16,7 @@ maintainer_warning_flags "-Qunused-arguments -Werror -Wno-error=unused-parameter
compile_flags "-c"
debug_info_flags "-g"
optimization_flags "-O3"
+sanitizer_flags "-fsanitize=address,undefined -fsanitize-coverage=edge,indirect-calls,8bit-counters -fno-sanitize-recover=undefined"
shared_flags "-fPIC"
coverage_flags "--coverage"
diff --git a/src/cli/asn1.cpp b/src/cli/asn1.cpp
index 8096f2d19..957fa1f24 100644
--- a/src/cli/asn1.cpp
+++ b/src/cli/asn1.cpp
@@ -147,6 +147,9 @@ std::string type_name(Botan::ASN1_Tag type)
case Botan::BOOLEAN:
return "BOOLEAN";
+
+ default:
+ return "TAG(" + std::to_string(static_cast<size_t>(type)) + ")";
}
return "(UNKNOWN)";
diff --git a/src/cli/bench.cpp b/src/cli/bench.cpp
index d2688421c..ba498d767 100644
--- a/src/cli/bench.cpp
+++ b/src/cli/bench.cpp
@@ -132,16 +132,6 @@ class Timer
uint64_t m_event_count = 0, m_event_mult = 0;
};
-inline bool operator<(const Timer& x, const Timer& y)
- {
- return (x.get_name() < y.get_name());
- }
-
-inline bool operator==(const Timer& x, const Timer& y)
- {
- return (x.get_name() == y.get_name());
- }
-
std::ostream& operator<<(std::ostream& out, Timer& timer)
{
const double events_per_second = timer.events() / timer.seconds();
diff --git a/src/cli/cli.h b/src/cli/cli.h
index df7e345f5..85d6770ba 100644
--- a/src/cli/cli.h
+++ b/src/cli/cli.h
@@ -106,6 +106,7 @@ class Command
// for checking all spec strings at load time
//parse_spec();
}
+ virtual ~Command() = default;
int run(const std::vector<std::string>& params)
{
@@ -439,31 +440,9 @@ class Command
}
template<typename Alloc>
- void write_output_file(const std::string& who,
- const std::vector<uint8_t, Alloc>& vec) const
+ void write_output(const std::vector<uint8_t, Alloc>& vec)
{
- write_output_file(who, vec.begin(), vec.size());
- }
-
- void write_output_file(const std::string& output_file,
- const uint8_t buf[], size_t buf_len) const
- {
- std::ofstream out(output_file, std::ios::binary);
- if(!out.good())
- throw CLI_IO_Error("writing", output_file);
-
- out.write(reinterpret_cast<const char*>(buf), buf_len);
- out.close();
- }
-
- void write_output_file(const std::string& output_file, const std::string& outstr) const
- {
- std::ofstream out(output_file);
- if(!out.good())
- throw CLI_IO_Error("writing", output_file);
-
- out.write(outstr.data(), outstr.size());
- out.close();
+ output().write(reinterpret_cast<const char*>(vec.data()), vec.size());
}
private:
diff --git a/src/cli/pubkey.cpp b/src/cli/pubkey.cpp
index 35d50592f..2616f6065 100644
--- a/src/cli/pubkey.cpp
+++ b/src/cli/pubkey.cpp
@@ -24,6 +24,10 @@
#include <botan/rsa.h>
#endif
+#if defined(BOTAN_HAS_DSA)
+ #include <botan/dsa.h>
+#endif
+
#if defined(BOTAN_HAS_ECDSA)
#include <botan/ecdsa.h>
#endif
@@ -41,7 +45,7 @@ namespace Botan_CLI {
class PK_Keygen : public Command
{
public:
- PK_Keygen() : Command("keygen --algo=RSA --params= --passphrase= --pbe= --pbe-millis=300") {}
+ PK_Keygen() : Command("keygen --algo=RSA --params= --passphrase= --pbe= --pbe-millis=300 --der-out") {}
std::unique_ptr<Botan::Private_Key> do_keygen(const std::string& algo,
const std::string& params,
@@ -59,6 +63,15 @@ class PK_Keygen : public Command
};
#endif
+#if defined(BOTAN_HAS_DSA)
+ generators["DSA"] = [&rng](std::string param) -> std::unique_ptr<Botan::Private_Key> {
+ if(param.empty())
+ param = "dsa/botan/2048";
+ return std::unique_ptr<Botan::Private_Key>(
+ new Botan::DSA_PrivateKey(rng, param));
+ };
+#endif
+
#if defined(BOTAN_HAS_ECDSA)
generators["ECDSA"] = [&rng](std::string param) {
if(param.empty())
@@ -105,18 +118,32 @@ class PK_Keygen : public Command
std::unique_ptr<Botan::Private_Key> key(do_keygen(get_arg("algo"), get_arg("params"), rng));
const std::string pass = get_arg("passphrase");
+ const bool der_out = flag_set("der-out");
- if(pass.empty())
+ const std::chrono::milliseconds pbe_millis(get_arg_sz("pbe-millis"));
+ const std::string pbe = get_arg("pbe");
+
+ if(der_out)
{
- output() << Botan::PKCS8::PEM_encode(*key);
+ if(pass.empty())
+ {
+ write_output(Botan::PKCS8::BER_encode(*key));
+ }
+ else
+ {
+ write_output(Botan::PKCS8::BER_encode(*key, rng, pass, pbe_millis, pbe));
+ }
}
else
{
- output() << Botan::PKCS8::PEM_encode(*key,
- rng,
- pass,
- std::chrono::milliseconds(get_arg_sz("pbe-millis")),
- get_arg("pbe"));
+ if(pass.empty())
+ {
+ output() << Botan::PKCS8::PEM_encode(*key);
+ }
+ else
+ {
+ output() << Botan::PKCS8::PEM_encode(*key, rng, pass, pbe_millis, pbe);
+ }
}
}
};
@@ -235,39 +262,59 @@ BOTAN_REGISTER_COMMAND(Gen_DL_Group);
class PKCS8_Tool : public Command
{
public:
- PKCS8_Tool() : Command("pkcs8 --pass-in= --pub-out --pass-out= --pbe= --pbe-millis=300 key") {}
+ PKCS8_Tool() : Command("pkcs8 --pass-in= --pub-out --der-out --pass-out= --pbe= --pbe-millis=300 key") {}
void go() override
{
Botan::AutoSeeded_RNG rng;
- std::unique_ptr<Botan::Private_Key> key(Botan::PKCS8::load_key(get_arg("key"),
- rng,
- get_arg("pass-in")));
+ std::unique_ptr<Botan::Private_Key> key(
+ Botan::PKCS8::load_key(get_arg("key"),
+ rng,
+ get_arg("pass-in")));
+
+ const std::chrono::milliseconds pbe_millis(get_arg_sz("pbe-millis"));
+ const std::string pbe = get_arg("pbe");
+ const bool der_out = flag_set("der-out");
if(flag_set("pub-out"))
{
- output() << Botan::X509::PEM_encode(*key);
+ if(der_out)
+ {
+ write_output(Botan::X509::BER_encode(*key));
+ }
+ else
+ {
+ output() << Botan::X509::PEM_encode(*key);
+ }
}
else
{
const std::string pass = get_arg("pass-out");
- if(pass.empty())
+ if(der_out)
{
- output() << Botan::PKCS8::PEM_encode(*key);
+ if(pass.empty())
+ {
+ write_output(Botan::PKCS8::BER_encode(*key));
+ }
+ else
+ {
+ write_output(Botan::PKCS8::BER_encode(*key, rng, pass, pbe_millis, pbe));
+ }
}
else
{
- output() << Botan::PKCS8::PEM_encode(*key,
- rng,
- pass,
- std::chrono::milliseconds(get_arg_sz("pbe-millis")),
- get_arg("pbe"));
- }
-
+ if(pass.empty())
+ {
+ output() << Botan::PKCS8::PEM_encode(*key);
+ }
+ else
+ {
+ output() << Botan::PKCS8::PEM_encode(*key, rng, pass, pbe_millis, pbe);
+ }
+ }
}
-
}
};
diff --git a/src/cli/utils.cpp b/src/cli/utils.cpp
index f3ce5f0f9..9302ec5d0 100644
--- a/src/cli/utils.cpp
+++ b/src/cli/utils.cpp
@@ -124,7 +124,11 @@ class Hash : public Command
const size_t buf_size = get_arg_sz("buf-size");
- for(auto fsname : get_arg_list("files"))
+ auto files = get_arg_list("files");
+ if(files.empty())
+ files.push_back("-"); // read stdin if no arguments on command line
+
+ for(auto fsname : files)
{
auto update_hash = [&](const uint8_t b[], size_t l) { hash_fn->update(b, l); };
read_file(fsname, update_hash, buf_size);
diff --git a/src/lib/math/mp/info.txt b/src/lib/math/mp/info.txt
index a47475f7b..6aa0142f3 100644
--- a/src/lib/math/mp/info.txt
+++ b/src/lib/math/mp/info.txt
@@ -1,11 +1,10 @@
-define BIGINT_MP 20131128
+define BIGINT_MP 20151225
<source>
mp_asm.cpp
mp_comba.cpp
mp_karat.cpp
mp_monty.cpp
-mp_mulop.cpp
mp_misc.cpp
mp_shift.cpp
</source>
diff --git a/src/lib/math/mp/mp_asm.cpp b/src/lib/math/mp/mp_asm.cpp
index cc573a792..b7d90552e 100644
--- a/src/lib/math/mp/mp_asm.cpp
+++ b/src/lib/math/mp/mp_asm.cpp
@@ -1,5 +1,5 @@
/*
-* Lowest Level MPI Algorithms
+* MPI Add, Subtract, Word Multiply
* (C) 1999-2010 Jack Lloyd
* 2006 Luca Piccarreta
*
diff --git a/src/lib/math/mp/mp_comba.cpp b/src/lib/math/mp/mp_comba.cpp
index 0170c9fcd..1ebd29817 100644
--- a/src/lib/math/mp/mp_comba.cpp
+++ b/src/lib/math/mp/mp_comba.cpp
@@ -1,6 +1,7 @@
/*
* Comba Multiplication and Squaring
-* (C) 1999-2007,2011,2014 Jack Lloyd
+*
+* This file was automatically generated by comba.py
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
diff --git a/src/lib/math/mp/mp_core.h b/src/lib/math/mp/mp_core.h
index b97384d18..9921f1f07 100644
--- a/src/lib/math/mp/mp_core.h
+++ b/src/lib/math/mp/mp_core.h
@@ -81,15 +81,6 @@ void bigint_shr2(word y[], const word x[], size_t x_size,
size_t word_shift, size_t bit_shift);
/*
-* Simple O(N^2) Multiplication and Squaring
-*/
-void bigint_simple_mul(word z[],
- const word x[], size_t x_size,
- const word y[], size_t y_size);
-
-void bigint_simple_sqr(word z[], const word x[], size_t x_size);
-
-/*
* Linear Multiply
*/
void bigint_linmul2(word x[], size_t x_size, word y);
diff --git a/src/lib/math/mp/mp_karat.cpp b/src/lib/math/mp/mp_karat.cpp
index 96d9adae2..c7f179191 100644
--- a/src/lib/math/mp/mp_karat.cpp
+++ b/src/lib/math/mp/mp_karat.cpp
@@ -1,5 +1,5 @@
/*
-* Karatsuba Multiplication/Squaring
+* Multiplication and Squaring
* (C) 1999-2010 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
@@ -16,6 +16,37 @@ namespace {
const size_t KARATSUBA_MULTIPLY_THRESHOLD = 32;
const size_t KARATSUBA_SQUARE_THRESHOLD = 32;
+namespace {
+
+/*
+* Simple O(N^2) Multiplication
+*/
+void basecase_mul(word z[],
+ const word x[], size_t x_size,
+ const word y[], size_t y_size)
+ {
+ const size_t x_size_8 = x_size - (x_size % 8);
+
+ clear_mem(z, x_size + y_size);
+
+ for(size_t i = 0; i != y_size; ++i)
+ {
+ const word y_i = y[i];
+
+ word carry = 0;
+
+ for(size_t j = 0; j != x_size_8; j += 8)
+ carry = word8_madd3(z + i + j, x + j, y_i, carry);
+
+ for(size_t j = x_size_8; j != x_size; ++j)
+ z[i+j] = word_madd3(x[j], y_i, z[i+j], &carry);
+
+ z[x_size+i] = carry;
+ }
+ }
+
+}
+
/*
* Karatsuba Multiplication Operation
*/
@@ -31,7 +62,7 @@ void karatsuba_mul(word z[], const word x[], const word y[], size_t N,
else if(N == 16)
return bigint_comba_mul16(z, x, y);
else
- return bigint_simple_mul(z, x, N, y, N);
+ return basecase_mul(z, x, N, y, N);
}
const size_t N2 = N / 2;
@@ -101,7 +132,7 @@ void karatsuba_sqr(word z[], const word x[], size_t N, word workspace[])
else if(N == 16)
return bigint_comba_sqr16(z, x);
else
- return bigint_simple_sqr(z, x, N);
+ return basecase_mul(z, x, N, x, N);
}
const size_t N2 = N / 2;
@@ -262,7 +293,7 @@ void bigint_mul(word z[], size_t z_size, word workspace[],
y_sw < KARATSUBA_MULTIPLY_THRESHOLD ||
!workspace)
{
- bigint_simple_mul(z, x, x_sw, y, y_sw);
+ basecase_mul(z, x, x_sw, y, y_sw);
}
else
{
@@ -271,7 +302,7 @@ void bigint_mul(word z[], size_t z_size, word workspace[],
if(N)
karatsuba_mul(z, x, y, N, workspace);
else
- bigint_simple_mul(z, x, x_sw, y, y_sw);
+ basecase_mul(z, x, x_sw, y, y_sw);
}
}
@@ -307,7 +338,7 @@ void bigint_sqr(word z[], size_t z_size, word workspace[],
}
else if(x_size < KARATSUBA_SQUARE_THRESHOLD || !workspace)
{
- bigint_simple_sqr(z, x, x_sw);
+ basecase_mul(z, x, x_sw, x, x_sw);
}
else
{
@@ -316,7 +347,7 @@ void bigint_sqr(word z[], size_t z_size, word workspace[],
if(N)
karatsuba_sqr(z, x, N, workspace);
else
- bigint_simple_sqr(z, x, x_sw);
+ basecase_mul(z, x, x_sw, x, x_sw);
}
}
diff --git a/src/lib/math/mp/mp_mulop.cpp b/src/lib/math/mp/mp_mulop.cpp
deleted file mode 100644
index 432c7ef53..000000000
--- a/src/lib/math/mp/mp_mulop.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
-* Simple O(N^2) Multiplication and Squaring
-* (C) 1999-2008 Jack Lloyd
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#include <botan/internal/mp_core.h>
-#include <botan/internal/mp_madd.h>
-#include <botan/internal/mp_asmi.h>
-#include <botan/mem_ops.h>
-
-namespace Botan {
-
-/*
-* Simple O(N^2) Multiplication
-*/
-void bigint_simple_mul(word z[], const word x[], size_t x_size,
- const word y[], size_t y_size)
- {
- const size_t x_size_8 = x_size - (x_size % 8);
-
- clear_mem(z, x_size + y_size);
-
- for(size_t i = 0; i != y_size; ++i)
- {
- const word y_i = y[i];
-
- word carry = 0;
-
- for(size_t j = 0; j != x_size_8; j += 8)
- carry = word8_madd3(z + i + j, x + j, y_i, carry);
-
- for(size_t j = x_size_8; j != x_size; ++j)
- z[i+j] = word_madd3(x[j], y_i, z[i+j], &carry);
-
- z[x_size+i] = carry;
- }
- }
-
-/*
-* Simple O(N^2) Squaring
-*
-* This is exactly the same algorithm as bigint_simple_mul, however
-* because C/C++ compilers suck at alias analysis it is good to have
-* the version where the compiler knows that x == y
-*
-* There is an O(n^1.5) squaring algorithm specified in Handbook of
-* Applied Cryptography, chapter 14
-*
-*/
-void bigint_simple_sqr(word z[], const word x[], size_t x_size)
- {
- const size_t x_size_8 = x_size - (x_size % 8);
-
- clear_mem(z, 2*x_size);
-
- for(size_t i = 0; i != x_size; ++i)
- {
- const word x_i = x[i];
- word carry = 0;
-
- for(size_t j = 0; j != x_size_8; j += 8)
- carry = word8_madd3(z + i + j, x + j, x_i, carry);
-
- for(size_t j = x_size_8; j != x_size; ++j)
- z[i+j] = word_madd3(x[j], x_i, z[i+j], &carry);
-
- z[x_size+i] = carry;
- }
- }
-
-}
diff --git a/src/lib/pk_pad/mgf1/mgf1.h b/src/lib/pk_pad/mgf1/mgf1.h
index ed2f1d023..bddb8bba8 100644
--- a/src/lib/pk_pad/mgf1/mgf1.h
+++ b/src/lib/pk_pad/mgf1/mgf1.h
@@ -15,9 +15,9 @@ namespace Botan {
/**
* MGF1 from PKCS #1 v2.0
*/
-void mgf1_mask(HashFunction& hash,
- const byte in[], size_t in_len,
- byte out[], size_t out_len);
+void BOTAN_DLL mgf1_mask(HashFunction& hash,
+ const byte in[], size_t in_len,
+ byte out[], size_t out_len);
}
diff --git a/src/lib/pubkey/mce/info.txt b/src/lib/pubkey/mce/info.txt
index 1e9b848dd..bb0f06764 100644
--- a/src/lib/pubkey/mce/info.txt
+++ b/src/lib/pubkey/mce/info.txt
@@ -1,7 +1,6 @@
define MCELIECE 20150922
<header:public>
-mce_kem.h
mceliece.h
polyn_gf2m.h
gf2m_small_m.h
diff --git a/src/lib/pubkey/mce/mce_kem.cpp b/src/lib/pubkey/mce/mce_kem.cpp
index dede67731..b2cefaab2 100644
--- a/src/lib/pubkey/mce/mce_kem.cpp
+++ b/src/lib/pubkey/mce/mce_kem.cpp
@@ -1,51 +1,74 @@
/**
- * (C) 2014 cryptosource GmbH
- * (C) 2014 Falko Strenzke [email protected]
- *
- * Botan is released under the Simplified BSD License (see license.txt)
- *
- */
-
-#include <botan/mce_kem.h>
+* (C) 2014 cryptosource GmbH
+* (C) 2014 Falko Strenzke [email protected]
+* (C) 2015 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*
+*/
+
#include <botan/internal/mce_internal.h>
-#include <botan/sha2_64.h>
+#include <botan/internal/pk_ops_impl.h>
+#include <botan/internal/pk_utils.h>
namespace Botan {
-McEliece_KEM_Encryptor::McEliece_KEM_Encryptor(const McEliece_PublicKey& public_key) :
- m_key(public_key)
+class MCE_KEM_Encryptor : public PK_Ops::KEM_Encryption_with_KDF
{
- }
+ public:
+ typedef McEliece_PublicKey Key_Type;
-std::pair<secure_vector<byte>, secure_vector<byte>>
-McEliece_KEM_Encryptor::encrypt(RandomNumberGenerator& rng)
- {
- const secure_vector<byte> plaintext = m_key.random_plaintext_element(rng);
+ MCE_KEM_Encryptor(const McEliece_PublicKey& key,
+ const std::string& kdf) :
+ KEM_Encryption_with_KDF(kdf), m_key(key) {}
+
+ private:
+ void raw_kem_encrypt(secure_vector<byte>& out_encapsulated_key,
+ secure_vector<byte>& raw_shared_key,
+ Botan::RandomNumberGenerator& rng) override
+ {
+ secure_vector<byte> plaintext = m_key.random_plaintext_element(rng);
- secure_vector<byte> ciphertext, error_mask;
- mceliece_encrypt(ciphertext, error_mask, plaintext, m_key, rng);
+ secure_vector<byte> ciphertext, error_mask;
+ mceliece_encrypt(ciphertext, error_mask, plaintext, m_key, rng);
- SHA_512 hash;
- hash.update(plaintext);
- hash.update(error_mask);
- secure_vector<byte> sym_key = hash.final();
+ raw_shared_key.clear();
+ raw_shared_key += plaintext;
+ raw_shared_key += error_mask;
- return std::make_pair(ciphertext, sym_key);
- }
+ out_encapsulated_key.swap(ciphertext);
+ }
-McEliece_KEM_Decryptor::McEliece_KEM_Decryptor(const McEliece_PrivateKey& key) : m_key(key) { }
+ const McEliece_PublicKey& m_key;
+ };
-secure_vector<Botan::byte> McEliece_KEM_Decryptor::decrypt(const byte msg[], size_t msg_len)
+class MCE_KEM_Decryptor : public PK_Ops::KEM_Decryption_with_KDF
{
- secure_vector<byte> plaintext, error_mask;
- mceliece_decrypt(plaintext, error_mask, msg, msg_len, m_key);
+ public:
+ typedef McEliece_PrivateKey Key_Type;
+
+ MCE_KEM_Decryptor(const McEliece_PrivateKey& key,
+ const std::string& kdf) :
+ KEM_Decryption_with_KDF(kdf), m_key(key) {}
+
+ private:
+ secure_vector<byte>
+ raw_kem_decrypt(const byte encap_key[], size_t len) override
+ {
+ secure_vector<byte> plaintext, error_mask;
+ mceliece_decrypt(plaintext, error_mask, encap_key, len, m_key);
+
+ secure_vector<byte> output;
+ output.reserve(plaintext.size() + error_mask.size());
+ output.insert(output.end(), plaintext.begin(), plaintext.end());
+ output.insert(output.end(), error_mask.begin(), error_mask.end());
+ return output;
+ }
- SHA_512 hash;
- hash.update(plaintext);
- hash.update(error_mask);
+ const McEliece_PrivateKey& m_key;
+ };
- secure_vector<byte> sym_key = hash.final();
- return sym_key;
- }
+BOTAN_REGISTER_PK_KEM_ENCRYPTION_OP("McEliece", MCE_KEM_Encryptor);
+BOTAN_REGISTER_PK_KEM_DECRYPTION_OP("McEliece", MCE_KEM_Decryptor);
}
diff --git a/src/lib/pubkey/mce/mce_kem.h b/src/lib/pubkey/mce/mce_kem.h
deleted file mode 100644
index cd899d568..000000000
--- a/src/lib/pubkey/mce/mce_kem.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/**
- * (C) 2014 cryptosource GmbH
- * (C) 2014 Falko Strenzke [email protected]
- *
- * Botan is released under the Simplified BSD License (see license.txt)
- *
- */
-
-#ifndef BOTAN_MCE_KEM_H__
-#define BOTAN_MCE_KEM_H__
-
-#include <botan/mceliece.h>
-#include <utility>
-
-namespace Botan {
-
-class BOTAN_DLL McEliece_KEM_Encryptor
- {
- public:
- McEliece_KEM_Encryptor(const McEliece_PublicKey& public_key);
-
- /**
- * returns the pair (mceliece ciphertext, symmetric key)
- */
- std::pair<secure_vector<byte>, secure_vector<byte>> encrypt(RandomNumberGenerator& rng);
-
- private:
- const McEliece_PublicKey& m_key;
- };
-
-class BOTAN_DLL McEliece_KEM_Decryptor
- {
- public:
- McEliece_KEM_Decryptor(const McEliece_PrivateKey& mce_key);
-
- /**
- * returns the derived 512-bit symmetric key
- */
- secure_vector<Botan::byte> decrypt(const byte msg[], size_t msg_len);
-
- /**
- * returns the derived 512-bit symmetric key
- */
- template<typename Alloc>
- secure_vector<Botan::byte> decrypt_vec(const std::vector<byte, Alloc>& v)
- {
- return decrypt(v.data(), v.size());
- }
-
- private:
- const McEliece_PrivateKey& m_key;
- };
-}
-
-#endif
diff --git a/src/lib/pubkey/mceies/mceies.cpp b/src/lib/pubkey/mceies/mceies.cpp
index e83fa257e..0af71719a 100644
--- a/src/lib/pubkey/mceies/mceies.cpp
+++ b/src/lib/pubkey/mceies/mceies.cpp
@@ -8,7 +8,7 @@
#include <botan/mceies.h>
#include <botan/aead.h>
#include <botan/mceliece.h>
-#include <botan/mce_kem.h>
+#include <botan/pubkey.h>
namespace Botan {
@@ -36,11 +36,10 @@ mceies_encrypt(const McEliece_PublicKey& pubkey,
RandomNumberGenerator& rng,
const std::string& algo)
{
- McEliece_KEM_Encryptor kem_op(pubkey);
+ PK_KEM_Encryptor kem_op(pubkey, "KDF1(SHA-512)");
- const std::pair<secure_vector<byte>,secure_vector<byte>> mce_ciphertext__key = kem_op.encrypt(rng);
- const secure_vector<byte>& mce_ciphertext = mce_ciphertext__key.first;
- const secure_vector<byte>& mce_key = mce_ciphertext__key.second;
+ secure_vector<byte> mce_ciphertext, mce_key;
+ kem_op.encrypt(mce_ciphertext, mce_key, 64, rng);
const size_t mce_code_bytes = (pubkey.get_code_length() + 7) / 8;
@@ -75,7 +74,7 @@ mceies_decrypt(const McEliece_PrivateKey& privkey,
{
try
{
- McEliece_KEM_Decryptor kem_op(privkey);
+ PK_KEM_Decryptor kem_op(privkey, "KDF1(SHA-512)");
const size_t mce_code_bytes = (privkey.get_code_length() + 7) / 8;
@@ -88,7 +87,7 @@ mceies_decrypt(const McEliece_PrivateKey& privkey,
if(ct_len < mce_code_bytes + nonce_len + aead->tag_size())
throw Exception("Input message too small to be valid");
- const secure_vector<byte> mce_key = kem_op.decrypt(ct, mce_code_bytes);
+ const secure_vector<byte> mce_key = kem_op.decrypt(ct, mce_code_bytes, 64);
aead->set_key(aead_key(mce_key, *aead));
aead->set_associated_data(ad, ad_len);
diff --git a/src/lib/pubkey/pk_ops.cpp b/src/lib/pubkey/pk_ops.cpp
index bc421eb90..81b087894 100644
--- a/src/lib/pubkey/pk_ops.cpp
+++ b/src/lib/pubkey/pk_ops.cpp
@@ -129,4 +129,47 @@ bool PK_Ops::Verification_with_EMSA::is_valid_signature(const byte sig[], size_t
}
}
+void PK_Ops::KEM_Encryption_with_KDF::kem_encrypt(secure_vector<byte>& out_encapsulated_key,
+ secure_vector<byte>& out_shared_key,
+ size_t desired_shared_key_len,
+ Botan::RandomNumberGenerator& rng,
+ const uint8_t salt[],
+ size_t salt_len)
+ {
+ secure_vector<byte> raw_shared;
+ this->raw_kem_encrypt(out_encapsulated_key, raw_shared, rng);
+
+ out_shared_key = m_kdf->derive_key(desired_shared_key_len,
+ raw_shared.data(), raw_shared.size(),
+ salt, salt_len);
+ }
+
+PK_Ops::KEM_Encryption_with_KDF::KEM_Encryption_with_KDF(const std::string& kdf)
+ {
+ m_kdf.reset(get_kdf(kdf));
+ }
+
+PK_Ops::KEM_Encryption_with_KDF::~KEM_Encryption_with_KDF() {}
+
+secure_vector<byte>
+PK_Ops::KEM_Decryption_with_KDF::kem_decrypt(const byte encap_key[],
+ size_t len,
+ size_t desired_shared_key_len,
+ const uint8_t salt[],
+ size_t salt_len)
+ {
+ secure_vector<byte> raw_shared = this->raw_kem_decrypt(encap_key, len);
+
+ return m_kdf->derive_key(desired_shared_key_len,
+ raw_shared.data(), raw_shared.size(),
+ salt, salt_len);
+ }
+
+PK_Ops::KEM_Decryption_with_KDF::KEM_Decryption_with_KDF(const std::string& kdf)
+ {
+ m_kdf.reset(get_kdf(kdf));
+ }
+
+PK_Ops::KEM_Decryption_with_KDF::~KEM_Decryption_with_KDF() {}
+
}
diff --git a/src/lib/pubkey/pk_ops.h b/src/lib/pubkey/pk_ops.h
index 3a2a8bdb5..6fc21ea4a 100644
--- a/src/lib/pubkey/pk_ops.h
+++ b/src/lib/pubkey/pk_ops.h
@@ -47,11 +47,13 @@ typedef PK_Spec<Private_Key> PK_Spec_Private_Key;
class BOTAN_DLL Encryption
{
public:
+ typedef PK_Spec_Public_Key Spec;
+
virtual size_t max_input_bits() const = 0;
- virtual secure_vector<byte> encrypt(const byte msg[], size_t msg_len, RandomNumberGenerator& rng) = 0;
-
- typedef PK_Spec_Public_Key Spec;
+ virtual secure_vector<byte> encrypt(const byte msg[],
+ size_t msg_len,
+ RandomNumberGenerator& rng) = 0;
virtual ~Encryption() {}
};
@@ -164,6 +166,38 @@ class BOTAN_DLL Key_Agreement
virtual ~Key_Agreement() {}
};
+/**
+* KEM (key encapsulation)
+*/
+class BOTAN_DLL KEM_Encryption
+ {
+ public:
+ typedef PK_Spec_Public_Key Spec;
+
+ virtual void kem_encrypt(secure_vector<byte>& out_encapsulated_key,
+ secure_vector<byte>& out_shared_key,
+ size_t desired_shared_key_len,
+ Botan::RandomNumberGenerator& rng,
+ const uint8_t salt[],
+ size_t salt_len) = 0;
+
+ virtual ~KEM_Encryption() {}
+ };
+
+class BOTAN_DLL KEM_Decryption
+ {
+ public:
+ typedef PK_Spec_Private_Key Spec;
+
+ virtual secure_vector<byte> kem_decrypt(const byte encap_key[],
+ size_t len,
+ size_t desired_shared_key_len,
+ const uint8_t salt[],
+ size_t salt_len) = 0;
+
+ virtual ~KEM_Decryption() {}
+ };
+
}
}
diff --git a/src/lib/pubkey/pk_ops_impl.h b/src/lib/pubkey/pk_ops_impl.h
index f27de4af4..0acceb53c 100644
--- a/src/lib/pubkey/pk_ops_impl.h
+++ b/src/lib/pubkey/pk_ops_impl.h
@@ -139,6 +139,46 @@ class Key_Agreement_with_KDF : public Key_Agreement
std::unique_ptr<KDF> m_kdf;
};
+class KEM_Encryption_with_KDF : public KEM_Encryption
+ {
+ public:
+ void kem_encrypt(secure_vector<byte>& out_encapsulated_key,
+ secure_vector<byte>& out_shared_key,
+ size_t desired_shared_key_len,
+ Botan::RandomNumberGenerator& rng,
+ const uint8_t salt[],
+ size_t salt_len) override;
+
+ protected:
+ virtual void raw_kem_encrypt(secure_vector<byte>& out_encapsulated_key,
+ secure_vector<byte>& raw_shared_key,
+ Botan::RandomNumberGenerator& rng) = 0;
+
+ KEM_Encryption_with_KDF(const std::string& kdf);
+ ~KEM_Encryption_with_KDF();
+ private:
+ std::unique_ptr<KDF> m_kdf;
+ };
+
+class KEM_Decryption_with_KDF : public KEM_Decryption
+ {
+ public:
+ secure_vector<byte> kem_decrypt(const byte encap_key[],
+ size_t len,
+ size_t desired_shared_key_len,
+ const uint8_t salt[],
+ size_t salt_len);
+
+ protected:
+ virtual secure_vector<byte>
+ raw_kem_decrypt(const byte encap_key[], size_t len) = 0;
+
+ KEM_Decryption_with_KDF(const std::string& kdf);
+ ~KEM_Decryption_with_KDF();
+ private:
+ std::unique_ptr<KDF> m_kdf;
+ };
+
}
}
diff --git a/src/lib/pubkey/pk_utils.h b/src/lib/pubkey/pk_utils.h
index 326a6ea68..04a0bf5ca 100644
--- a/src/lib/pubkey/pk_utils.h
+++ b/src/lib/pubkey/pk_utils.h
@@ -32,6 +32,9 @@ OP* make_pk_op(const typename T::Spec& spec)
#define BOTAN_REGISTER_PK_VERIFY_OP(NAME, TYPE) BOTAN_REGISTER_PK_OP(PK_Ops::Verification, NAME, TYPE)
#define BOTAN_REGISTER_PK_KEY_AGREE_OP(NAME, TYPE) BOTAN_REGISTER_PK_OP(PK_Ops::Key_Agreement, NAME, TYPE)
+#define BOTAN_REGISTER_PK_KEM_ENCRYPTION_OP(NAME, TYPE) BOTAN_REGISTER_PK_OP(PK_Ops::KEM_Encryption, NAME, TYPE)
+#define BOTAN_REGISTER_PK_KEM_DECRYPTION_OP(NAME, TYPE) BOTAN_REGISTER_PK_OP(PK_Ops::KEM_Decryption, NAME, TYPE)
+
}
#endif
diff --git a/src/lib/pubkey/pubkey.cpp b/src/lib/pubkey/pubkey.cpp
index b9923f54b..e870dfdec 100644
--- a/src/lib/pubkey/pubkey.cpp
+++ b/src/lib/pubkey/pubkey.cpp
@@ -59,6 +59,46 @@ secure_vector<byte> PK_Decryptor_EME::dec(const byte msg[], size_t length) const
return m_op->decrypt(msg, length);
}
+PK_KEM_Encryptor::PK_KEM_Encryptor(const Public_Key& key,
+ const std::string& param,
+ const std::string& provider)
+ {
+ m_op.reset(get_pk_op<PK_Ops::KEM_Encryption>("KEM", key, param, provider));
+ }
+
+void PK_KEM_Encryptor::encrypt(secure_vector<byte>& out_encapsulated_key,
+ secure_vector<byte>& out_shared_key,
+ size_t desired_shared_key_len,
+ Botan::RandomNumberGenerator& rng,
+ const uint8_t salt[],
+ size_t salt_len)
+ {
+ m_op->kem_encrypt(out_encapsulated_key,
+ out_shared_key,
+ desired_shared_key_len,
+ rng,
+ salt,
+ salt_len);
+ }
+
+PK_KEM_Decryptor::PK_KEM_Decryptor(const Private_Key& key,
+ const std::string& param,
+ const std::string& provider)
+ {
+ m_op.reset(get_pk_op<PK_Ops::KEM_Decryption>("KEM", key, param, provider));
+ }
+
+secure_vector<byte> PK_KEM_Decryptor::decrypt(const byte encap_key[],
+ size_t encap_key_len,
+ size_t desired_shared_key_len,
+ const uint8_t salt[],
+ size_t salt_len)
+ {
+ return m_op->kem_decrypt(encap_key, encap_key_len,
+ desired_shared_key_len,
+ salt, salt_len);
+ }
+
PK_Key_Agreement::PK_Key_Agreement(const Private_Key& key, const std::string& kdf)
{
m_op.reset(get_pk_op<PK_Ops::Key_Agreement>("Key agreement", key, kdf));
diff --git a/src/lib/pubkey/pubkey.h b/src/lib/pubkey/pubkey.h
index 637e522e4..a8caf58ac 100644
--- a/src/lib/pubkey/pubkey.h
+++ b/src/lib/pubkey/pubkey.h
@@ -438,6 +438,87 @@ class BOTAN_DLL PK_Decryptor_EME : public PK_Decryptor
std::unique_ptr<PK_Ops::Decryption> m_op;
};
+class BOTAN_DLL PK_KEM_Encryptor
+ {
+ public:
+ PK_KEM_Encryptor(const Public_Key& key,
+ const std::string& kem_param = "",
+ const std::string& provider = "");
+
+ void encrypt(secure_vector<byte>& out_encapsulated_key,
+ secure_vector<byte>& out_shared_key,
+ size_t desired_shared_key_len,
+ Botan::RandomNumberGenerator& rng,
+ const uint8_t salt[],
+ size_t salt_len);
+
+ template<typename Alloc>
+ void encrypt(secure_vector<byte>& out_encapsulated_key,
+ secure_vector<byte>& out_shared_key,
+ size_t desired_shared_key_len,
+ Botan::RandomNumberGenerator& rng,
+ const std::vector<uint8_t, Alloc>& salt)
+ {
+ this->encrypt(out_encapsulated_key,
+ out_shared_key,
+ desired_shared_key_len,
+ rng,
+ salt.data(), salt.size());
+ }
+
+ void encrypt(secure_vector<byte>& out_encapsulated_key,
+ secure_vector<byte>& out_shared_key,
+ size_t desired_shared_key_len,
+ Botan::RandomNumberGenerator& rng)
+ {
+ this->encrypt(out_encapsulated_key,
+ out_shared_key,
+ desired_shared_key_len,
+ rng,
+ nullptr,
+ 0);
+ }
+
+ private:
+ std::unique_ptr<PK_Ops::KEM_Encryption> m_op;
+ };
+
+class BOTAN_DLL PK_KEM_Decryptor
+ {
+ public:
+ PK_KEM_Decryptor(const Private_Key& key,
+ const std::string& kem_param = "",
+ const std::string& provider = "");
+
+ secure_vector<byte> decrypt(const byte encap_key[],
+ size_t encap_key_len,
+ size_t desired_shared_key_len,
+ const uint8_t salt[],
+ size_t salt_len);
+
+ secure_vector<byte> decrypt(const byte encap_key[],
+ size_t encap_key_len,
+ size_t desired_shared_key_len)
+ {
+ return this->decrypt(encap_key, encap_key_len,
+ desired_shared_key_len,
+ nullptr, 0);
+ }
+
+ template<typename Alloc1, typename Alloc2>
+ secure_vector<byte> decrypt(const std::vector<byte, Alloc1>& encap_key,
+ size_t desired_shared_key_len,
+ const std::vector<byte, Alloc2>& salt)
+ {
+ return this->decrypt(encap_key.data(), encap_key.size(),
+ desired_shared_key_len,
+ salt.data(), salt.size());
+ }
+
+ private:
+ std::unique_ptr<PK_Ops::KEM_Decryption> m_op;
+ };
+
}
#endif
diff --git a/src/lib/pubkey/rsa/rsa.cpp b/src/lib/pubkey/rsa/rsa.cpp
index 5804d0034..d18843315 100644
--- a/src/lib/pubkey/rsa/rsa.cpp
+++ b/src/lib/pubkey/rsa/rsa.cpp
@@ -1,6 +1,6 @@
/*
* RSA
-* (C) 1999-2010 Jack Lloyd
+* (C) 1999-2010,2015 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -13,6 +13,8 @@
#include <botan/reducer.h>
#include <future>
+#include <iostream>
+
namespace Botan {
/*
@@ -156,11 +158,34 @@ class RSA_Decryption_Operation : public PK_Ops::Decryption_with_EME,
const BigInt m(msg, msg_len);
const BigInt x = blinded_private_op(m);
const BigInt c = m_powermod_e_n(x);
- BOTAN_ASSERT(m == c, "RSA sign consistency check");
+ BOTAN_ASSERT(m == c, "RSA decrypt consistency check");
return BigInt::encode_locked(x);
}
};
+class RSA_KEM_Decryption_Operation : public PK_Ops::KEM_Decryption_with_KDF,
+ private RSA_Private_Operation
+ {
+ public:
+ typedef RSA_PrivateKey Key_Type;
+
+ RSA_KEM_Decryption_Operation(const RSA_PrivateKey& key,
+ const std::string& kdf) :
+ PK_Ops::KEM_Decryption_with_KDF(kdf),
+ RSA_Private_Operation(key)
+ {}
+
+ secure_vector<byte>
+ raw_kem_decrypt(const byte encap_key[], size_t len) override
+ {
+ const BigInt m(encap_key, len);
+ const BigInt x = blinded_private_op(m);
+ const BigInt c = m_powermod_e_n(x);
+ BOTAN_ASSERT(m == c, "RSA KEM consistency check");
+ return BigInt::encode_1363(x, n.bytes());
+ }
+ };
+
/**
* RSA public (encrypt/verify) operation
*/
@@ -181,6 +206,8 @@ class RSA_Public_Operation
return powermod_e_n(m);
}
+ const BigInt& get_n() const { return n; }
+
const BigInt& n;
Fixed_Exponent_Power_Mod powermod_e_n;
};
@@ -230,11 +257,42 @@ class RSA_Verify_Operation : public PK_Ops::Verification_with_EMSA,
}
};
+class RSA_KEM_Encryption_Operation : public PK_Ops::KEM_Encryption_with_KDF,
+ private RSA_Public_Operation
+ {
+ public:
+ typedef RSA_PublicKey Key_Type;
+
+ RSA_KEM_Encryption_Operation(const RSA_PublicKey& key,
+ const std::string& kdf) :
+ PK_Ops::KEM_Encryption_with_KDF(kdf),
+ RSA_Public_Operation(key) {}
+
+ private:
+ void raw_kem_encrypt(secure_vector<byte>& out_encapsulated_key,
+ secure_vector<byte>& raw_shared_key,
+ Botan::RandomNumberGenerator& rng) override
+ {
+ const BigInt r = BigInt::random_integer(rng, 1, get_n());
+ std::cout << "R = " << r << "\n";
+ const BigInt c = public_op(r);
+ std::cout << "C0 = " << c << "\n";
+
+ out_encapsulated_key = BigInt::encode_locked(c);
+ raw_shared_key = BigInt::encode_locked(r);
+ }
+ };
+
+
BOTAN_REGISTER_PK_ENCRYPTION_OP("RSA", RSA_Encryption_Operation);
BOTAN_REGISTER_PK_DECRYPTION_OP("RSA", RSA_Decryption_Operation);
+
BOTAN_REGISTER_PK_SIGNATURE_OP("RSA", RSA_Signature_Operation);
BOTAN_REGISTER_PK_VERIFY_OP("RSA", RSA_Verify_Operation);
+BOTAN_REGISTER_PK_KEM_ENCRYPTION_OP("RSA", RSA_KEM_Encryption_Operation);
+BOTAN_REGISTER_PK_KEM_DECRYPTION_OP("RSA", RSA_KEM_Decryption_Operation);
+
}
}
diff --git a/src/lib/tls/tls_session_manager.h b/src/lib/tls/tls_session_manager.h
index 5ab151c26..e01462f66 100644
--- a/src/lib/tls/tls_session_manager.h
+++ b/src/lib/tls/tls_session_manager.h
@@ -127,7 +127,7 @@ class BOTAN_DLL Session_Manager_In_Memory : public Session_Manager
void remove_entry(const std::vector<byte>& session_id) override;
- size_t remove_all();
+ size_t remove_all() override;
void save(const Session& session_data) override;
diff --git a/src/lib/utils/loadstor.h b/src/lib/utils/loadstor.h
index 53700fc86..8d33c2eef 100644
--- a/src/lib/utils/loadstor.h
+++ b/src/lib/utils/loadstor.h
@@ -308,24 +308,27 @@ inline void load_le(T out[],
const byte in[],
size_t count)
{
+ if(count > 0)
+ {
#if defined(BOTAN_TARGET_CPU_HAS_KNOWN_ENDIANNESS)
- std::memcpy(out, in, sizeof(T)*count);
+ std::memcpy(out, in, sizeof(T)*count);
#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
- const size_t blocks = count - (count % 4);
- const size_t left = count - blocks;
+ const size_t blocks = count - (count % 4);
+ const size_t left = count - blocks;
- for(size_t i = 0; i != blocks; i += 4)
- bswap_4(out + i);
+ for(size_t i = 0; i != blocks; i += 4)
+ bswap_4(out + i);
- for(size_t i = 0; i != left; ++i)
- out[blocks+i] = reverse_bytes(out[blocks+i]);
+ for(size_t i = 0; i != left; ++i)
+ out[blocks+i] = reverse_bytes(out[blocks+i]);
#endif
#else
- for(size_t i = 0; i != count; ++i)
- out[i] = load_le<T>(in, i);
+ for(size_t i = 0; i != count; ++i)
+ out[i] = load_le<T>(in, i);
#endif
+ }
}
/**
@@ -397,24 +400,27 @@ inline void load_be(T out[],
const byte in[],
size_t count)
{
+ if(count > 0)
+ {
#if defined(BOTAN_TARGET_CPU_HAS_KNOWN_ENDIANNESS)
- std::memcpy(out, in, sizeof(T)*count);
+ std::memcpy(out, in, sizeof(T)*count);
#if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
- const size_t blocks = count - (count % 4);
- const size_t left = count - blocks;
+ const size_t blocks = count - (count % 4);
+ const size_t left = count - blocks;
- for(size_t i = 0; i != blocks; i += 4)
- bswap_4(out + i);
+ for(size_t i = 0; i != blocks; i += 4)
+ bswap_4(out + i);
- for(size_t i = 0; i != left; ++i)
- out[blocks+i] = reverse_bytes(out[blocks+i]);
+ for(size_t i = 0; i != left; ++i)
+ out[blocks+i] = reverse_bytes(out[blocks+i]);
#endif
#else
- for(size_t i = 0; i != count; ++i)
- out[i] = load_be<T>(in, i);
+ for(size_t i = 0; i != count; ++i)
+ out[i] = load_be<T>(in, i);
#endif
+ }
}
/**
diff --git a/src/lib/utils/mem_ops.h b/src/lib/utils/mem_ops.h
index 6ea7bdafe..d11e3368c 100644
--- a/src/lib/utils/mem_ops.h
+++ b/src/lib/utils/mem_ops.h
@@ -28,7 +28,10 @@ BOTAN_DLL void zero_mem(void* ptr, size_t n);
*/
template<typename T> inline void clear_mem(T* ptr, size_t n)
{
- std::memset(ptr, 0, sizeof(T)*n);
+ if(n > 0)
+ {
+ std::memset(ptr, 0, sizeof(T)*n);
+ }
}
/**
@@ -39,7 +42,10 @@ template<typename T> inline void clear_mem(T* ptr, size_t n)
*/
template<typename T> inline void copy_mem(T* out, const T* in, size_t n)
{
- std::memmove(out, in, sizeof(T)*n);
+ if(n > 0)
+ {
+ std::memmove(out, in, sizeof(T)*n);
+ }
}
/**
@@ -51,7 +57,10 @@ template<typename T> inline void copy_mem(T* out, const T* in, size_t n)
template<typename T>
inline void set_mem(T* ptr, size_t n, byte val)
{
- std::memset(ptr, val, sizeof(T)*n);
+ if(n > 0)
+ {
+ std::memset(ptr, val, sizeof(T)*n);
+ }
}
/**
diff --git a/src/scripts/comba.py b/src/scripts/comba.py
index dcac14657..f0165a3ce 100755
--- a/src/scripts/comba.py
+++ b/src/scripts/comba.py
@@ -1,7 +1,10 @@
-#!/usr/bin/python
+#!/usr/bin/python2
import sys
+# (C) 2011,2014,2015 Jack Lloyd
+# Botan is released under the Simplified BSD License (see license.txt)
+
# Used to generate src/lib/math/mp/mp_comba.cpp
def comba_indexes(N):
@@ -78,7 +81,8 @@ def main(args = None):
print """/*
* Comba Multiplication and Squaring
-* (C) 1999-2007,2011,2014 Jack Lloyd
+*
+* This file was automatically generated by comba.py
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
diff --git a/src/tests/data/nist_x509/expected.txt b/src/tests/data/nist_x509/expected.txt
new file mode 100644
index 000000000..0b2535fca
--- /dev/null
+++ b/src/tests/data/nist_x509/expected.txt
@@ -0,0 +1,76 @@
+test01:Verified
+test02:Signature error
+test03:Signature error
+test04:Verified
+test05:Certificate is not yet valid
+test06:Certificate is not yet valid
+test07:Verified
+test08:Certificate is not yet valid
+test09:Certificate has expired
+test10:Certificate has expired
+test11:Certificate has expired
+test12:Verified
+test13:Certificate issuer not found
+test14:Certificate issuer not found
+test15:Verified
+test16:Verified
+test17:Verified
+test18:Verified
+test19:No revocation data
+test20:Certificate is revoked
+test21:Certificate is revoked
+test22:CA certificate not allowed to issue certs
+test23:CA certificate not allowed to issue certs
+test24:Verified
+test25:CA certificate not allowed to issue certs
+test26:Verified
+test27:Verified
+test28:CA certificate not allowed to issue certs
+test29:CA certificate not allowed to issue certs
+test30:Verified
+test31:CA certificate not allowed to issue CRLs
+test32:CA certificate not allowed to issue CRLs
+test33:Verified
+test34:Verified
+test35:Verified
+test36:Verified
+test37:Verified
+test38:Verified
+test39:Verified
+test40:Verified
+test41:Verified
+test42:Verified
+test43:Verified
+test44:Verified
+#test45:Explicit policy required
+#test46:
+#test47:Explicit policy required
+test48:Verified
+test49:Verified
+test50:Verified
+test51:Verified
+test52:Verified
+test53:Verified
+test54:Certificate chain too long
+test55:Certificate chain too long
+test56:Verified
+test57:Verified
+test58:Certificate chain too long
+test59:Certificate chain too long
+test60:Certificate chain too long
+test61:Certificate chain too long
+test62:Verified
+test63:Verified
+test64:CRL bad signature
+test65:No revocation data
+test66:No revocation data
+test67:Verified
+test68:Certificate is revoked
+test69:Certificate is revoked
+test70:Certificate is revoked
+test71:Certificate is revoked
+test72:CRL has expired
+test73:CRL has expired
+test74:Verified
+#test75:
+#test76:
diff --git a/src/tests/data/pubkey/rsa_kem.vec b/src/tests/data/pubkey/rsa_kem.vec
new file mode 100644
index 000000000..6fb76fcfe
--- /dev/null
+++ b/src/tests/data/pubkey/rsa_kem.vec
@@ -0,0 +1,25 @@
+
+# RSA-KEM tests vectors from ISO-18033-2
+# http://www.shoup.net/iso/std4.pdf
+
+# R values here are -1 from the actual desired value to account for
+# some logic in random_integer wrt the bounds
+
+# Test C.6.2
+E = 65537
+P = 74100103850091296168511028051948833436338123529747970640732238422269665602829
+Q = 79461607023043824134896992211543210236933205105414344240218914846895267687977
+R = 032E45326FA859A72EC235ACFF929B15D1372E30B207255F0611B8F785D764374152E0AC009E509E7BA30CD2F1778E113B64E135CF4E2292C75EFE5288EDFDA3
+C0 = 4603E5324CAB9CEF8365C817052D954D44447B1667099EDC69942D32CD594E4FFCF268AE3836E2C35744AAA53AE201FE499806B67DEDAA26BF72ECBD117A6FC0
+KDF = KDF2(SHA-1)
+K = 0E6A26EB7B956CCB8B3BDC1CA975BC57C3989E8FBAD31A224655D800C46954840F
+
+# Test C.6.4
+
+E = 65537
+P = 74100103850091296168511028051948833436338123529747970640732238422269665602829
+Q = 79461607023043824134896992211543210236933205105414344240218914846895267687977
+R = 032E45326FA859A72EC235ACFF929B15D1372E30B207255F0611B8F785D764374152E0AC009E509E7BA30CD2F1778E113B64E135CF4E2292C75EFE5288EDFDA3
+C0 = 4603E5324CAB9CEF8365C817052D954D44447B1667099EDC69942D32CD594E4FFCF268AE3836E2C35744AAA53AE201FE499806B67DEDAA26BF72ECBD117A6FC0
+KDF = KDF2(SHA-256)
+K = 10a2403db42a8743cb989de86e668d168cbe6046
diff --git a/src/tests/main.cpp b/src/tests/main.cpp
index 692bc41af..57a525dbd 100644
--- a/src/tests/main.cpp
+++ b/src/tests/main.cpp
@@ -71,7 +71,7 @@ class Test_Runner : public Botan_CLI::Command
const size_t threads = get_arg_sz("threads");
const size_t soak_level = get_arg_sz("soak");
const std::string drbg_seed = get_arg("drbg-seed");
- bool log_success = flag_set("log-success");
+ const bool log_success = flag_set("log-success");
const std::string data_dir = get_arg_or("data-dir", "src/tests/data");
std::vector<std::string> req = get_arg_list("suites");
@@ -211,7 +211,9 @@ class Test_Runner : public Botan_CLI::Command
for(auto&& test_name : tests_to_run)
{
auto run_it = [test_name] {
- return Botan_Tests::Test::run_test(test_name, false); };
+ return Botan_Tests::Test::run_test(test_name, false);
+ };
+
fut_results.push_back(std::async(std::launch::async, run_it));
while(fut_results.size() > threads)
diff --git a/src/tests/test_dh.cpp b/src/tests/test_dh.cpp
index 643206031..a30564f92 100644
--- a/src/tests/test_dh.cpp
+++ b/src/tests/test_dh.cpp
@@ -28,7 +28,7 @@ class Diffie_Hellman_KAT_Tests : public PK_Key_Agreement_Test
{"KDF"})
{}
- std::string default_kdf(const VarMap&) { return "Raw"; }
+ std::string default_kdf(const VarMap&) const override { return "Raw"; }
std::unique_ptr<Botan::Private_Key> load_our_key(const VarMap& vars) override
{
diff --git a/src/tests/test_mceliece.cpp b/src/tests/test_mceliece.cpp
index d894f2045..36ecd660e 100644
--- a/src/tests/test_mceliece.cpp
+++ b/src/tests/test_mceliece.cpp
@@ -11,7 +11,6 @@
#if defined(BOTAN_HAS_MCELIECE)
#include <botan/mceliece.h>
-#include <botan/mce_kem.h>
#include <botan/pubkey.h>
#include <botan/oids.h>
#include <botan/hmac_drbg.h>
@@ -81,13 +80,17 @@ class McEliece_Keygen_Encrypt_Test : public Text_Based_Test
rng.clear();
rng.add_entropy(encrypt_seed.data(), encrypt_seed.size());
- Botan::McEliece_KEM_Encryptor kem_enc(mce_priv);
- Botan::McEliece_KEM_Decryptor kem_dec(mce_priv);
+ Botan::PK_KEM_Encryptor kem_enc(mce_priv, "KDF1(SHA-512)");
+ Botan::PK_KEM_Decryptor kem_dec(mce_priv, "KDF1(SHA-512)");
- const auto kem = kem_enc.encrypt(rng);
- result.test_eq("ciphertext", kem.first, ciphertext);
- result.test_eq("encrypt shared", kem.second, shared_key);
- result.test_eq("decrypt shared", kem_dec.decrypt_vec(kem.first), shared_key);
+ Botan::secure_vector<byte> encap_key, prod_shared_key;
+ kem_enc.encrypt(encap_key, prod_shared_key, 64, rng);
+
+ Botan::secure_vector<byte> dec_shared_key = kem_dec.decrypt(encap_key.data(), encap_key.size(), 64);
+
+ result.test_eq("ciphertext", encap_key, ciphertext);
+ result.test_eq("encrypt shared", prod_shared_key, shared_key);
+ result.test_eq("decrypt shared", dec_shared_key, shared_key);
return result;
}
@@ -176,18 +179,19 @@ class McEliece_Tests : public Test
{
Test::Result result("McEliece KEM");
- Botan::McEliece_KEM_Encryptor pub_op(pk);
- Botan::McEliece_KEM_Decryptor priv_op(sk);
+ Botan::PK_KEM_Encryptor enc_op(pk, "KDF2(SHA-256)");
+ Botan::PK_KEM_Decryptor dec_op(sk, "KDF2(SHA-256)");
for(size_t i = 0; i <= Test::soak_level(); i++)
{
- const std::pair<Botan::secure_vector<byte>,Botan::secure_vector<byte> > ciphertext__sym_key = pub_op.encrypt(Test::rng());
- const Botan::secure_vector<byte>& ciphertext = ciphertext__sym_key.first;
- const Botan::secure_vector<byte>& sym_key_encr = ciphertext__sym_key.second;
+ Botan::secure_vector<byte> salt = Test::rng().random_vec(i);
+
+ Botan::secure_vector<byte> encap_key, shared_key;
+ enc_op.encrypt(encap_key, shared_key, 64, Test::rng(), salt);
- const Botan::secure_vector<byte> sym_key_decr = priv_op.decrypt(ciphertext.data(), ciphertext.size());
+ Botan::secure_vector<byte> shared_key2 = dec_op.decrypt(encap_key, 64, salt);
- result.test_eq("same key", sym_key_decr, sym_key_encr);
+ result.test_eq("same key", shared_key, shared_key2);
}
return result;
}
diff --git a/src/tests/test_pubkey.cpp b/src/tests/test_pubkey.cpp
index 14f36dbbd..4521717e9 100644
--- a/src/tests/test_pubkey.cpp
+++ b/src/tests/test_pubkey.cpp
@@ -249,6 +249,46 @@ PK_Encryption_Decryption_Test::run_one_test(const std::string&, const VarMap& va
return result;
}
+Test::Result PK_KEM_Test::run_one_test(const std::string&, const VarMap& vars)
+ {
+ const std::vector<uint8_t> K = get_req_bin(vars, "K");
+ const std::vector<uint8_t> C0 = get_req_bin(vars, "C0");
+ const std::vector<uint8_t> salt = get_opt_bin(vars, "Salt");
+ const std::string kdf = get_req_str(vars, "KDF");
+
+ Test::Result result(algo_name() + "/" + kdf + " KEM");
+
+ std::unique_ptr<Botan::Private_Key> privkey = load_private_key(vars);
+
+ const size_t desired_key_len = K.size();
+
+ Botan::PK_KEM_Encryptor enc(*privkey, kdf);
+
+ Fixed_Output_RNG fixed_output_rng(get_req_bin(vars, "R"));
+
+ Botan::secure_vector<byte> produced_encap_key, shared_key;
+ enc.encrypt(produced_encap_key,
+ shared_key,
+ desired_key_len,
+ fixed_output_rng,
+ salt);
+
+ result.test_eq("C0 matches", produced_encap_key, C0);
+ result.test_eq("K matches", shared_key, K);
+
+ Botan::PK_KEM_Decryptor dec(*privkey, kdf);
+
+ const Botan::secure_vector<uint8_t> decr_shared_key =
+ dec.decrypt(C0.data(), C0.size(),
+ desired_key_len,
+ salt.data(),
+ salt.size());
+
+ result.test_eq("decrypted K matches", decr_shared_key, K);
+
+ return result;
+ }
+
Test::Result PK_Key_Agreement_Test::run_one_test(const std::string&, const VarMap& vars)
{
const std::vector<uint8_t> shared = get_req_bin(vars, "K");
@@ -288,55 +328,102 @@ PK_Key_Generation_Test::test_key(const std::string& algo, const Botan::Private_K
{
Test::Result result(algo + " keygen");
- const std::string pub_pem = Botan::X509::PEM_encode(key);
+ try
+ {
+ Botan::DataSource_Memory data_src(Botan::X509::PEM_encode(key));
+ std::unique_ptr<Botan::Public_Key> loaded(Botan::X509::load_key(data_src));
+
+ result.test_eq("recovered public key from private", loaded.get(), true);
+ result.test_eq("public key has same type", loaded->algo_name(), key.algo_name());
+ result.test_eq("public key passes checks", loaded->check_key(Test::rng(), false), true);
+ }
+ catch(std::exception& e)
+ {
+ result.test_failure("roundtrip PEM public key", e.what());
+ }
try
{
- Botan::DataSource_Memory input_pub(pub_pem);
- std::unique_ptr<Botan::Public_Key> restored_pub(Botan::X509::load_key(input_pub));
+ Botan::DataSource_Memory data_src(Botan::X509::BER_encode(key));
+ std::unique_ptr<Botan::Public_Key> loaded(Botan::X509::load_key(data_src));
- result.test_eq("recovered public key from private", restored_pub.get(), true);
- result.test_eq("public key has same type", restored_pub->algo_name(), key.algo_name());
- result.test_eq("public key passes checks", restored_pub->check_key(Test::rng(), false), true);
+ result.test_eq("recovered public key from private", loaded.get(), true);
+ result.test_eq("public key has same type", loaded->algo_name(), key.algo_name());
+ result.test_eq("public key passes checks", loaded->check_key(Test::rng(), false), true);
}
catch(std::exception& e)
{
- result.test_failure("roundtrip public key", e.what());
+ result.test_failure("roundtrip BER public key", e.what());
}
- const std::string priv_pem = Botan::PKCS8::PEM_encode(key);
+ try
+ {
+ Botan::DataSource_Memory data_src(Botan::PKCS8::PEM_encode(key));
+ std::unique_ptr<Botan::Private_Key> loaded(
+ Botan::PKCS8::load_key(data_src, Test::rng()));
+
+ result.test_eq("recovered private key from PEM blob", loaded.get(), true);
+ result.test_eq("reloaded key has same type", loaded->algo_name(), key.algo_name());
+ result.test_eq("private key passes checks", loaded->check_key(Test::rng(), false), true);
+ }
+ catch(std::exception& e)
+ {
+ result.test_failure("roundtrip PEM private key", e.what());
+ }
+ /*
+ // Currently broken GH #379
try
{
- Botan::DataSource_Memory input_priv(priv_pem);
- std::unique_ptr<Botan::Private_Key> restored_priv(
- Botan::PKCS8::load_key(input_priv, Test::rng()));
+ Botan::DataSource_Memory data_src(Botan::PKCS8::BER_encode(key));
+ std::unique_ptr<Botan::Public_Key> loaded(Botan::PKCS8::load_key(data_src, Test::rng()));
- result.test_eq("recovered private key from blob", restored_priv.get(), true);
- result.test_eq("reloaded key has same type", restored_priv->algo_name(), key.algo_name());
- result.test_eq("private key passes checks", restored_priv->check_key(Test::rng(), false), true);
+ result.test_eq("recovered public key from private", loaded.get(), true);
+ result.test_eq("public key has same type", loaded->algo_name(), key.algo_name());
+ result.test_eq("public key passes checks", loaded->check_key(Test::rng(), false), true);
}
catch(std::exception& e)
{
- result.test_failure("roundtrip private key", e.what());
+ result.test_failure("roundtrip BER private key", e.what());
}
+ */
const std::string passphrase = Test::random_password();
- const std::string enc_priv_pem = Botan::PKCS8::PEM_encode(key, Test::rng(), passphrase,
- std::chrono::milliseconds(10));
+
try
{
- Botan::DataSource_Memory input_priv(priv_pem);
- std::unique_ptr<Botan::Private_Key> restored_priv(
- Botan::PKCS8::load_key(input_priv, Test::rng(), passphrase));
+ Botan::DataSource_Memory data_src(
+ Botan::PKCS8::PEM_encode(key, Test::rng(), passphrase,
+ std::chrono::milliseconds(10)));
+
+ std::unique_ptr<Botan::Private_Key> loaded(
+ Botan::PKCS8::load_key(data_src, Test::rng(), passphrase));
+
+ result.test_eq("recovered private key from encrypted blob", loaded.get(), true);
+ result.test_eq("reloaded key has same type", loaded->algo_name(), key.algo_name());
+ result.test_eq("private key passes checks", loaded->check_key(Test::rng(), false), true);
+ }
+ catch(std::exception& e)
+ {
+ result.test_failure("roundtrip encrypted PEM private key", e.what());
+ }
+
+ try
+ {
+ Botan::DataSource_Memory data_src(
+ Botan::PKCS8::BER_encode(key, Test::rng(), passphrase,
+ std::chrono::milliseconds(10)));
+
+ std::unique_ptr<Botan::Private_Key> loaded(
+ Botan::PKCS8::load_key(data_src, Test::rng(), passphrase));
- result.test_eq("recovered private key from encrypted blob", restored_priv.get(), true);
- result.test_eq("reloaded key has same type", restored_priv->algo_name(), key.algo_name());
- result.test_eq("private key passes checks", restored_priv->check_key(Test::rng(), false), true);
+ result.test_eq("recovered private key from BER blob", loaded.get(), true);
+ result.test_eq("reloaded key has same type", loaded->algo_name(), key.algo_name());
+ result.test_eq("private key passes checks", loaded->check_key(Test::rng(), false), true);
}
catch(std::exception& e)
{
- result.test_failure("roundtrip private key", e.what());
+ result.test_failure("roundtrip encrypted BER private key", e.what());
}
return result;
diff --git a/src/tests/test_pubkey.h b/src/tests/test_pubkey.h
index edb36f07b..beb1b2ea2 100644
--- a/src/tests/test_pubkey.h
+++ b/src/tests/test_pubkey.h
@@ -87,6 +87,22 @@ class PK_Key_Agreement_Test : public Text_Based_Test
Test::Result run_one_test(const std::string& header, const VarMap& vars) override;
};
+class PK_KEM_Test : public Text_Based_Test
+ {
+ public:
+ //using Text_Based_Test::Text_Based_Test;
+
+ PK_KEM_Test(const std::string& algo,
+ const std::string& test_src,
+ const std::vector<std::string>& required_keys,
+ const std::vector<std::string>& optional_keys = {}) :
+ Text_Based_Test(algo, test_src, required_keys, optional_keys) {}
+
+ virtual std::unique_ptr<Botan::Private_Key> load_private_key(const VarMap& vars) = 0;
+ private:
+ Test::Result run_one_test(const std::string& header, const VarMap& vars) override;
+ };
+
class PK_Key_Generation_Test : public Test
{
protected:
diff --git a/src/tests/test_rng.h b/src/tests/test_rng.h
index 343356550..83ae9698a 100644
--- a/src/tests/test_rng.h
+++ b/src/tests/test_rng.h
@@ -32,7 +32,7 @@ class Fixed_Output_RNG : public Botan::RandomNumberGenerator
size_t reseed_with_sources(Botan::Entropy_Sources&,
size_t,
- std::chrono::milliseconds) { return 0; }
+ std::chrono::milliseconds) override { return 0; }
void randomize(uint8_t out[], size_t len) override
{
diff --git a/src/tests/test_rsa.cpp b/src/tests/test_rsa.cpp
index 2720ae49a..6c89a5b29 100644
--- a/src/tests/test_rsa.cpp
+++ b/src/tests/test_rsa.cpp
@@ -38,6 +38,25 @@ class RSA_ES_KAT_Tests : public PK_Encryption_Decryption_Test
}
};
+class RSA_KEM_Tests : public PK_KEM_Test
+ {
+ public:
+ RSA_KEM_Tests() : PK_KEM_Test("RSA", "pubkey/rsa_kem.vec",
+ {"E", "P", "Q", "R", "C0", "KDF", "OutLen", "K"})
+ {}
+
+ std::unique_ptr<Botan::Private_Key> load_private_key(const VarMap& vars) override
+ {
+ const BigInt p = get_req_bn(vars, "P");
+ const BigInt q = get_req_bn(vars, "Q");
+ const BigInt e = get_req_bn(vars, "E");
+
+ std::unique_ptr<Botan::Private_Key> key(new Botan::RSA_PrivateKey(Test::rng(), p, q, e));
+ return key;
+ }
+
+ };
+
class RSA_Signature_KAT_Tests : public PK_Signature_Generation_Test
{
public:
@@ -100,6 +119,7 @@ class RSA_Keygen_Tests : public PK_Key_Generation_Test
BOTAN_REGISTER_TEST("rsa_encrypt", RSA_ES_KAT_Tests);
BOTAN_REGISTER_TEST("rsa_sign", RSA_Signature_KAT_Tests);
BOTAN_REGISTER_TEST("rsa_verify", RSA_Signature_Verify_Tests);
+BOTAN_REGISTER_TEST("rsa_kem", RSA_KEM_Tests);
BOTAN_REGISTER_TEST("rsa_keygen", RSA_Keygen_Tests);
#endif
diff --git a/src/tests/test_x509_path.cpp b/src/tests/test_x509_path.cpp
index 149c6ec2a..646f573a4 100644
--- a/src/tests/test_x509_path.cpp
+++ b/src/tests/test_x509_path.cpp
@@ -25,6 +25,33 @@ namespace {
#if defined(BOTAN_HAS_X509_CERTIFICATES)
+std::map<std::string, std::string> read_results(const std::string& results_file)
+ {
+ std::ifstream in(results_file);
+ if(!in.good())
+ throw Test_Error("Failed reading " + results_file);
+
+ std::map<std::string, std::string> m;
+ std::string line;
+ while(in.good())
+ {
+ std::getline(in, line);
+ if(line == "")
+ continue;
+ if(line[0] == '#')
+ continue;
+
+ std::vector<std::string> parts = Botan::split_on(line, ':');
+
+ if(parts.size() != 2)
+ throw Test_Error("Invalid line " + line);
+
+ m[parts[0]] = parts[1];
+ }
+
+ return m;
+ }
+
class X509test_Path_Validation_Tests : public Test
{
public:
@@ -33,26 +60,27 @@ class X509test_Path_Validation_Tests : public Test
std::vector<Test::Result> results;
// Test certs generated by https://github.com/yymax/x509test
- const std::string test_dir = "src/tests/data/x509test";
- std::map<std::string, std::string> expected = read_results(test_dir + "/expected.txt");
+ std::map<std::string, std::string> expected =
+ read_results(Test::data_file("x509test/expected.txt"));
const Botan::Path_Validation_Restrictions default_restrictions;
- Botan::X509_Certificate root(test_dir + "/root.pem");
+ Botan::X509_Certificate root(Test::data_file("x509test/root.pem"));
Botan::Certificate_Store_In_Memory trusted;
trusted.add_certificate(root);
for(auto i = expected.begin(); i != expected.end(); ++i)
{
Test::Result result("X509test path validation");
- const std::string fsname = i->first;
- const std::string expected = i->second;
+ const std::string filename = i->first;
+ const std::string expected_result = i->second;
- std::vector<Botan::X509_Certificate> certs = load_cert_file(test_dir + "/" + fsname);
+ std::vector<Botan::X509_Certificate> certs =
+ load_cert_file(Test::data_file("x509test/" + filename));
if(certs.empty())
- throw Test_Error("Failed to read certs from " + fsname);
+ throw Test_Error("Failed to read certs from " + filename);
Botan::Path_Validation_Result path_result = Botan::x509_path_validate(
certs, default_restrictions, trusted,
@@ -61,7 +89,7 @@ class X509test_Path_Validation_Tests : public Test
if(path_result.successful_validation() && path_result.trust_root() != root)
path_result = Botan::Path_Validation_Result(Botan::Certificate_Status_Code::CANNOT_ESTABLISH_TRUST);
- result.test_eq("validation result", path_result.result_string(), expected);
+ result.test_eq("validation result", path_result.result_string(), expected_result);
results.push_back(result);
}
@@ -86,32 +114,6 @@ class X509test_Path_Validation_Tests : public Test
return certs;
}
- std::map<std::string, std::string> read_results(const std::string& results_file)
- {
- std::ifstream in(results_file);
- if(!in.good())
- throw Test_Error("Failed reading " + results_file);
-
- std::map<std::string, std::string> m;
- std::string line;
- while(in.good())
- {
- std::getline(in, line);
- if(line == "")
- continue;
- if(line[0] == '#')
- continue;
-
- std::vector<std::string> parts = Botan::split_on(line, ':');
-
- if(parts.size() != 2)
- throw Test_Error("Invalid line " + line);
-
- m[parts[0]] = parts[1];
- }
-
- return m;
- }
};
BOTAN_REGISTER_TEST("x509_path_x509test", X509test_Path_Validation_Tests);
@@ -120,142 +122,8 @@ class NIST_Path_Validation_Tests : public Test
{
public:
std::vector<Test::Result> run() override;
-
- private:
- std::map<size_t, Botan::Path_Validation_Result::Code> get_expected();
};
-/*
- The expected results are essentially the error codes that best coorespond
- to the problem described in the testing documentation.
-
- There are a few cases where the tests say there should or should not be an
- error, and I disagree. A few of the tests have test results different from
- what they "should" be: these changes are marked as such, and have comments
- explaining the problem at hand.
-*/
-std::map<size_t, Botan::Path_Validation_Result::Code> NIST_Path_Validation_Tests::get_expected()
- {
- using namespace Botan;
-
- std::map<size_t, Path_Validation_Result::Code> expected_results;
-
-
- // TODO read from a file
- expected_results[1] = Certificate_Status_Code::VERIFIED;
- expected_results[2] = Certificate_Status_Code::SIGNATURE_ERROR;
- expected_results[3] = Certificate_Status_Code::SIGNATURE_ERROR;
- expected_results[4] = Certificate_Status_Code::VERIFIED;
- expected_results[5] = Certificate_Status_Code::CERT_NOT_YET_VALID;
- expected_results[6] = Certificate_Status_Code::CERT_NOT_YET_VALID;
- expected_results[7] = Certificate_Status_Code::VERIFIED;
- expected_results[8] = Certificate_Status_Code::CERT_NOT_YET_VALID;
- expected_results[9] = Certificate_Status_Code::CERT_HAS_EXPIRED;
- expected_results[10] = Certificate_Status_Code::CERT_HAS_EXPIRED;
- expected_results[11] = Certificate_Status_Code::CERT_HAS_EXPIRED;
- expected_results[12] = Certificate_Status_Code::VERIFIED;
- expected_results[13] = Certificate_Status_Code::CERT_ISSUER_NOT_FOUND;
-
- expected_results[14] = Certificate_Status_Code::CERT_ISSUER_NOT_FOUND;
- expected_results[15] = Certificate_Status_Code::VERIFIED;
- expected_results[16] = Certificate_Status_Code::VERIFIED;
- expected_results[17] = Certificate_Status_Code::VERIFIED;
- expected_results[18] = Certificate_Status_Code::VERIFIED;
-
- expected_results[19] = Certificate_Status_Code::NO_REVOCATION_DATA;
- expected_results[20] = Certificate_Status_Code::CERT_IS_REVOKED;
- expected_results[21] = Certificate_Status_Code::CERT_IS_REVOKED;
-
- expected_results[22] = Certificate_Status_Code::CA_CERT_NOT_FOR_CERT_ISSUER;
- expected_results[23] = Certificate_Status_Code::CA_CERT_NOT_FOR_CERT_ISSUER;
- expected_results[24] = Certificate_Status_Code::VERIFIED;
- expected_results[25] = Certificate_Status_Code::CA_CERT_NOT_FOR_CERT_ISSUER;
- expected_results[26] = Certificate_Status_Code::VERIFIED;
- expected_results[27] = Certificate_Status_Code::VERIFIED;
- expected_results[28] = Certificate_Status_Code::CA_CERT_NOT_FOR_CERT_ISSUER;
- expected_results[29] = Certificate_Status_Code::CA_CERT_NOT_FOR_CERT_ISSUER;
- expected_results[30] = Certificate_Status_Code::VERIFIED;
-
- expected_results[31] = Certificate_Status_Code::CA_CERT_NOT_FOR_CRL_ISSUER;
- expected_results[32] = Certificate_Status_Code::CA_CERT_NOT_FOR_CRL_ISSUER;
- expected_results[33] = Certificate_Status_Code::VERIFIED;
-
- /*
- Policy tests: a little trickier because there are other inputs
- which affect the result.
-
- In the case of the tests currently in the suite, the default
- method (with acceptable policy being "any-policy" and with no
- explicit policy required), will almost always result in a verified
- status. This is not particularly helpful. So, we should do several
- different tests for each test set:
-
- 1) With the user policy as any-policy and no explicit policy
- 2) With the user policy as any-policy and an explicit policy required
- 3) With the user policy as test-policy-1 (2.16.840.1.101.3.1.48.1) and
- an explicit policy required
- 4) With the user policy as either test-policy-1 or test-policy-2 and an
- explicit policy required
-
- This provides reasonably good coverage of the possible outcomes.
- */
-
- expected_results[34] = Certificate_Status_Code::VERIFIED;
- expected_results[35] = Certificate_Status_Code::VERIFIED;
- expected_results[36] = Certificate_Status_Code::VERIFIED;
- expected_results[37] = Certificate_Status_Code::VERIFIED;
- expected_results[38] = Certificate_Status_Code::VERIFIED;
- expected_results[39] = Certificate_Status_Code::VERIFIED;
- expected_results[40] = Certificate_Status_Code::VERIFIED;
- expected_results[41] = Certificate_Status_Code::VERIFIED;
- expected_results[42] = Certificate_Status_Code::VERIFIED;
- expected_results[43] = Certificate_Status_Code::VERIFIED;
- expected_results[44] = Certificate_Status_Code::VERIFIED;
-
- //expected_results[45] = Certificate_Status_Code::EXPLICIT_POLICY_REQUIRED;
- //expected_results[46] = Certificate_Status_Code::ACCEPT;
- //expected_results[47] = Certificate_Status_Code::EXPLICIT_POLICY_REQUIRED;
-
- expected_results[48] = Certificate_Status_Code::VERIFIED;
- expected_results[49] = Certificate_Status_Code::VERIFIED;
- expected_results[50] = Certificate_Status_Code::VERIFIED;
- expected_results[51] = Certificate_Status_Code::VERIFIED;
- expected_results[52] = Certificate_Status_Code::VERIFIED;
- expected_results[53] = Certificate_Status_Code::VERIFIED;
-
- expected_results[54] = Certificate_Status_Code::CERT_CHAIN_TOO_LONG;
- expected_results[55] = Certificate_Status_Code::CERT_CHAIN_TOO_LONG;
- expected_results[56] = Certificate_Status_Code::VERIFIED;
- expected_results[57] = Certificate_Status_Code::VERIFIED;
- expected_results[58] = Certificate_Status_Code::CERT_CHAIN_TOO_LONG;
- expected_results[59] = Certificate_Status_Code::CERT_CHAIN_TOO_LONG;
- expected_results[60] = Certificate_Status_Code::CERT_CHAIN_TOO_LONG;
- expected_results[61] = Certificate_Status_Code::CERT_CHAIN_TOO_LONG;
- expected_results[62] = Certificate_Status_Code::VERIFIED;
- expected_results[63] = Certificate_Status_Code::VERIFIED;
-
- expected_results[64] = Certificate_Status_Code::CRL_BAD_SIGNATURE;
-
- expected_results[65] = Certificate_Status_Code::NO_REVOCATION_DATA;
- expected_results[66] = Certificate_Status_Code::NO_REVOCATION_DATA;
-
- expected_results[67] = Certificate_Status_Code::VERIFIED;
-
- expected_results[68] = Certificate_Status_Code::CERT_IS_REVOKED;
- expected_results[69] = Certificate_Status_Code::CERT_IS_REVOKED;
- expected_results[70] = Certificate_Status_Code::CERT_IS_REVOKED;
- expected_results[71] = Certificate_Status_Code::CERT_IS_REVOKED;
- expected_results[72] = Certificate_Status_Code::CRL_HAS_EXPIRED;
- expected_results[73] = Certificate_Status_Code::CRL_HAS_EXPIRED;
- expected_results[74] = Certificate_Status_Code::VERIFIED;
-
- /* These tests use weird CRL extensions which aren't supported yet */
- //expected_results[75] = ;
- //expected_results[76] = ;
-
- return expected_results;
- }
-
std::vector<Test::Result> NIST_Path_Validation_Tests::run()
{
std::vector<Test::Result> results;
@@ -270,12 +138,12 @@ std::vector<Test::Result> NIST_Path_Validation_Tests::run()
* - Tests #75 and #76 are skipped as they make use of relatively
* obscure CRL extensions which are not supported.
*/
- const std::string root_test_dir = "src/tests/data/nist_x509/";
+ const std::string nist_test_dir = Test::data_dir() + "/nist_x509";
try
{
// Do nothing, just test filesystem access
- Botan::get_files_recursive(root_test_dir);
+ Botan::get_files_recursive(nist_test_dir);
}
catch(Botan::No_Filesystem_Access)
{
@@ -285,80 +153,60 @@ std::vector<Test::Result> NIST_Path_Validation_Tests::run()
return results;
}
- const size_t total_tests = 76;
- std::map<size_t, Botan::Path_Validation_Result::Code> expected_results = get_expected();
+ std::map<std::string, std::string> expected =
+ read_results(Test::data_file("nist_x509/expected.txt"));
- for(size_t test_no = 1; test_no <= total_tests; ++test_no)
+ for(auto i = expected.begin(); i != expected.end(); ++i)
{
- try
- {
- Test::Result result("NIST path validation");
- const std::string test_dir = root_test_dir + "/test" + (test_no <= 9 ? "0" : "") + std::to_string(test_no);
+ const std::string test_name = i->first;
+ const std::string expected_result = i->second;
+ printf("%s %s\n", test_name.c_str(), expected_result.c_str());
- const std::vector<std::string> all_files = Botan::get_files_recursive(test_dir);
- if (all_files.empty())
- {
- result.test_failure("No test files found in " + test_dir);
- continue;
- }
-
- std::vector<std::string> certs, crls;
- std::string root_cert, to_verify;
+ const std::string test_dir = nist_test_dir + "/" + test_name;
- for(const auto &current : all_files)
- {
- if(current.find("int") != std::string::npos && current.find(".crt") != std::string::npos)
- certs.push_back(current);
- else if(current.find("root.crt") != std::string::npos)
- root_cert = current;
- else if(current.find("end.crt") != std::string::npos)
- to_verify = current;
- else if(current.find(".crl") != std::string::npos)
- crls.push_back(current);
- }
-
- if(expected_results.find(test_no) == expected_results.end())
- {
- result.test_note("Skipping test");
- continue;
- }
-
- Botan::Certificate_Store_In_Memory store;
+ Test::Result result("NIST path validation");
- store.add_certificate(Botan::X509_Certificate(root_cert));
+ const std::vector<std::string> all_files = Botan::get_files_recursive(test_dir);
- Botan::X509_Certificate end_user(to_verify);
+ if(all_files.empty())
+ {
+ result.test_failure("No test files found in " + test_dir);
+ results.push_back(result);
+ continue;
+ }
- for(size_t i = 0; i != certs.size(); i++)
- store.add_certificate(Botan::X509_Certificate(certs[i]));
+ Botan::Certificate_Store_In_Memory store;
- for(size_t i = 0; i != crls.size(); i++)
+ for(auto&& file : all_files)
+ {
+ if(file.find(".crt") != std::string::npos && file != "end.crt")
{
- Botan::DataSource_Stream in(crls[i], true);
+ store.add_certificate(Botan::X509_Certificate(file));
+ }
+ else if(file.find(".crl") != std::string::npos)
+ {
+ Botan::DataSource_Stream in(file, true);
Botan::X509_CRL crl(in);
store.add_crl(crl);
+ }
}
- Botan::Path_Validation_Restrictions restrictions(true);
+ Botan::X509_Certificate end_user(test_dir + "/end.crt");
- Botan::Path_Validation_Result validation_result =
- Botan::x509_path_validate(end_user,
- restrictions,
- store);
+ Botan::Path_Validation_Restrictions restrictions(true);
- auto expected = expected_results[test_no];
+ Botan::Path_Validation_Result validation_result =
+ Botan::x509_path_validate(end_user,
+ restrictions,
+ store);
- result.test_eq("path validation result",
- validation_result.result_string(),
- Botan::Path_Validation_Result::status_string(expected));
+ result.test_eq(test_name + " path validation result",
+ validation_result.result_string(),
+ expected_result);
- results.push_back(result);
- }
- catch(std::exception& e)
- {
- results.push_back(Test::Result::Failure("NIST X509 " + std::to_string(test_no), e.what()));
- }
+ results.push_back(result);
}
+
return results;
}
diff --git a/src/tests/tests.h b/src/tests/tests.h
index e12f5f6de..f98194278 100644
--- a/src/tests/tests.h
+++ b/src/tests/tests.h
@@ -388,7 +388,6 @@ class Text_Based_Test : public Test
std::set<std::string> m_required_keys;
std::set<std::string> m_optional_keys;
std::string m_output_key;
- bool m_clear_between_cb = false;
bool m_first = true;
std::unique_ptr<std::ifstream> m_cur;