aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/build-data/botan.doxy.in1
-rw-r--r--src/cli/speed.cpp13
-rw-r--r--src/cli/tls_client.cpp58
-rw-r--r--src/cli/tls_utils.cpp10
-rw-r--r--src/configs/sphinx/conf.py2
-rw-r--r--src/lib/block/block_cipher.cpp18
-rw-r--r--src/lib/block/serpent/serpent.cpp7
-rw-r--r--src/lib/ffi/ffi.h37
-rw-r--r--src/lib/ffi/ffi_pkey_algs.cpp82
-rw-r--r--src/lib/math/mp/mp_madd.h2
-rw-r--r--src/lib/modes/cipher_mode.cpp19
-rw-r--r--src/lib/prov/commoncrypto/commoncrypto.h29
-rw-r--r--src/lib/prov/commoncrypto/commoncrypto_block.cpp152
-rw-r--r--src/lib/prov/commoncrypto/commoncrypto_mode.cpp240
-rw-r--r--src/lib/prov/commoncrypto/commoncrypto_utils.cpp187
-rw-r--r--src/lib/prov/commoncrypto/commoncrypto_utils.h36
-rw-r--r--src/lib/prov/commoncrypto/info.txt5
-rw-r--r--src/lib/pubkey/curve25519/curve25519.h3
-rw-r--r--src/lib/pubkey/curve25519/info.txt1
-rw-r--r--src/lib/x509/info.txt1
-rwxr-xr-xsrc/scripts/ci/setup_travis.sh2
-rw-r--r--src/tests/data/cryptobox.vec92
-rw-r--r--src/tests/test_certstor.cpp5
-rw-r--r--src/tests/test_cryptobox.cpp84
-rw-r--r--src/tests/test_ffi.cpp58
25 files changed, 1064 insertions, 80 deletions
diff --git a/src/build-data/botan.doxy.in b/src/build-data/botan.doxy.in
index c3261a7a9..743a6e0b4 100644
--- a/src/build-data/botan.doxy.in
+++ b/src/build-data/botan.doxy.in
@@ -157,6 +157,7 @@ PREDEFINED = BOTAN_HAS_AES_ARMV8 \
BOTAN_HAS_AES_POWER8 \
BOTAN_HAS_AES_SSSE3 \
BOTAN_HAS_CHACHA_SSE2 \
+ BOTAN_HAS_CHACHA_AVX2 \
BOTAN_HAS_IDEA_SSE2 \
BOTAN_HAS_NOEKEON_SIMD \
BOTAN_HAS_SERPENT_SIMD \
diff --git a/src/cli/speed.cpp b/src/cli/speed.cpp
index f7e9da1cf..80fe6591b 100644
--- a/src/cli/speed.cpp
+++ b/src/cli/speed.cpp
@@ -277,6 +277,8 @@ class Summary final
std::vector<size_t> unique_buffer_sizes(const std::string& cmdline_arg)
{
+ const size_t MAX_BUF_SIZE = 64*1024*1024;
+
std::set<size_t> buf;
for(std::string size_str : Botan::split_on(cmdline_arg, ','))
{
@@ -294,8 +296,11 @@ std::vector<size_t> unique_buffer_sizes(const std::string& cmdline_arg)
throw CLI_Usage_Error("Invalid integer value '" + size_str + "' for option buf-size");
}
- if(x == 0 || x > 16*1024*1024)
- throw CLI_Usage_Error("Invalid integer value '" + size_str + "' for option buf-size");
+ if(x == 0)
+ throw CLI_Usage_Error("Cannot have a zero-sized buffer");
+
+ if(x > MAX_BUF_SIZE)
+ throw CLI_Usage_Error("Specified buffer size is too large");
buf.insert(x);
}
@@ -513,9 +518,9 @@ class Speed final : public Command
}
#endif
#if defined(BOTAN_HAS_CIPHER_MODES)
- else if(auto enc = Botan::Cipher_Mode::create(algo, Botan::ENCRYPTION))
+ else if(auto enc = Botan::Cipher_Mode::create(algo, Botan::ENCRYPTION, provider))
{
- auto dec = Botan::Cipher_Mode::create_or_throw(algo, Botan::DECRYPTION);
+ auto dec = Botan::Cipher_Mode::create_or_throw(algo, Botan::DECRYPTION, provider);
bench_cipher_mode(*enc, *dec, msec, buf_sizes);
}
#endif
diff --git a/src/cli/tls_client.cpp b/src/cli/tls_client.cpp
index c7bb134e2..aef8e2512 100644
--- a/src/cli/tls_client.cpp
+++ b/src/cli/tls_client.cpp
@@ -31,6 +31,31 @@
namespace Botan_CLI {
+class CLI_Policy : public Botan::TLS::Policy
+ {
+ public:
+
+ CLI_Policy(Botan::TLS::Protocol_Version req_version) : m_version(req_version) {}
+
+ std::vector<std::string> allowed_ciphers() const override
+ {
+ // Allow CBC mode only in versions which don't support AEADs
+ if(m_version.supports_aead_modes() == false)
+ {
+ return { "AES-256", "AES-128" };
+ }
+
+ return Botan::TLS::Policy::allowed_ciphers();
+ }
+
+ bool allow_tls10() const override { return m_version == Botan::TLS::Protocol_Version::TLS_V10; }
+ bool allow_tls11() const override { return m_version == Botan::TLS::Protocol_Version::TLS_V11; }
+ bool allow_tls12() const override { return m_version == Botan::TLS::Protocol_Version::TLS_V12; }
+
+ private:
+ Botan::TLS::Protocol_Version m_version;
+ };
+
class TLS_Client final : public Command, public Botan::TLS::Callbacks
{
public:
@@ -101,11 +126,6 @@ class TLS_Client final : public Command, public Botan::TLS::Callbacks
policy.reset(new Botan::TLS::Text_Policy(policy_stream));
}
- if(!policy)
- {
- policy.reset(new Botan::TLS::Policy);
- }
-
if(transport != "tcp" && transport != "udp")
{
throw CLI_Usage_Error("Invalid transport type '" + transport + "' for TLS");
@@ -115,19 +135,35 @@ class TLS_Client final : public Command, public Botan::TLS::Callbacks
const std::vector<std::string> protocols_to_offer = Botan::split_on(next_protos, ',');
- m_sockfd = connect_to_host(host, port, use_tcp);
-
- using namespace std::placeholders;
-
- auto version = policy->latest_supported_version(!use_tcp);
+ Botan::TLS::Protocol_Version version =
+ use_tcp ? Botan::TLS::Protocol_Version::TLS_V12 : Botan::TLS::Protocol_Version::DTLS_V12;
if(flag_set("tls1.0"))
{
version = Botan::TLS::Protocol_Version::TLS_V10;
+ if(!policy)
+ policy.reset(new CLI_Policy(version));
}
else if(flag_set("tls1.1"))
{
version = Botan::TLS::Protocol_Version::TLS_V11;
+ if(!policy)
+ policy.reset(new CLI_Policy(version));
+ }
+ else if(flag_set("tls1.2"))
+ {
+ version = Botan::TLS::Protocol_Version::TLS_V12;
+ if(!policy)
+ policy.reset(new CLI_Policy(version));
+ }
+ else if(!policy)
+ {
+ policy.reset(new Botan::TLS::Policy);
+ }
+
+ if(policy->acceptable_protocol_version(version) == false)
+ {
+ throw CLI_Usage_Error("The policy specified does not allow the requested TLS version");
}
struct sockaddr_storage addrbuf;
@@ -139,6 +175,8 @@ class TLS_Client final : public Command, public Botan::TLS::Callbacks
hostname = host;
}
+ m_sockfd = connect_to_host(host, port, use_tcp);
+
Basic_Credentials_Manager creds(use_system_cert_store, trusted_CAs);
Botan::TLS::Client client(*this, *session_mgr, creds, *policy, rng(),
diff --git a/src/cli/tls_utils.cpp b/src/cli/tls_utils.cpp
index 2429b5de6..16813c13a 100644
--- a/src/cli/tls_utils.cpp
+++ b/src/cli/tls_utils.cpp
@@ -55,8 +55,8 @@ class TLS_All_Policy final : public Botan::TLS::Policy
return { "ECDSA", "RSA", "DSA" };
}
- bool allow_tls10() const override { return false; }
- bool allow_tls11() const override { return false; }
+ bool allow_tls10() const override { return true; }
+ bool allow_tls11() const override { return true; }
bool allow_tls12() const override { return true; }
};
@@ -138,6 +138,12 @@ class TLS_Ciphersuites final : public Command
policy.reset(new Botan::TLS::Text_Policy(policy_txt));
}
+ if(policy->acceptable_protocol_version(version) == false)
+ {
+ error_output() << "Error: the policy specified does not allow the given TLS version\n";
+ return;
+ }
+
for(uint16_t suite_id : policy->ciphersuite_list(version, with_srp))
{
const Botan::TLS::Ciphersuite suite(Botan::TLS::Ciphersuite::by_id(suite_id));
diff --git a/src/configs/sphinx/conf.py b/src/configs/sphinx/conf.py
index c172f9411..127fd5401 100644
--- a/src/configs/sphinx/conf.py
+++ b/src/configs/sphinx/conf.py
@@ -47,7 +47,7 @@ version_patch = version_info['release_patch']
is_website_build = check_for_tag('website')
-needs_sphinx = '1.3'
+needs_sphinx = '1.2'
templates_path = ['templates']
diff --git a/src/lib/block/block_cipher.cpp b/src/lib/block/block_cipher.cpp
index 3ace6cd4f..fb0564646 100644
--- a/src/lib/block/block_cipher.cpp
+++ b/src/lib/block/block_cipher.cpp
@@ -98,12 +98,27 @@
#include <botan/internal/openssl.h>
#endif
+#if defined(BOTAN_HAS_COMMONCRYPTO)
+ #include <botan/internal/commoncrypto.h>
+#endif
+
namespace Botan {
std::unique_ptr<BlockCipher>
BlockCipher::create(const std::string& algo,
const std::string& provider)
{
+#if defined(BOTAN_HAS_COMMONCRYPTO)
+ if(provider.empty() || provider == "commoncrypto")
+ {
+ if(auto bc = make_commoncrypto_block_cipher(algo))
+ return bc;
+
+ if(!provider.empty())
+ return nullptr;
+ }
+#endif
+
#if defined(BOTAN_HAS_OPENSSL)
if(provider.empty() || provider == "openssl")
{
@@ -115,7 +130,6 @@ BlockCipher::create(const std::string& algo,
}
#endif
- // TODO: CommonCrypto
// TODO: CryptoAPI
// TODO: /dev/crypto
@@ -343,7 +357,7 @@ BlockCipher::create_or_throw(const std::string& algo,
std::vector<std::string> BlockCipher::providers(const std::string& algo)
{
- return probe_providers_of<BlockCipher>(algo, { "base", "openssl" });
+ return probe_providers_of<BlockCipher>(algo, { "base", "openssl", "commoncrypto" });
}
}
diff --git a/src/lib/block/serpent/serpent.cpp b/src/lib/block/serpent/serpent.cpp
index d9001d19f..7bdda0f9f 100644
--- a/src/lib/block/serpent/serpent.cpp
+++ b/src/lib/block/serpent/serpent.cpp
@@ -276,6 +276,13 @@ void Serpent::clear()
std::string Serpent::provider() const
{
+#if defined(BOTAN_HAS_SERPENT_AVX2)
+ if(CPUID::has_avx2())
+ {
+ return "avx2";
+ }
+#endif
+
#if defined(BOTAN_HAS_SERPENT_SIMD)
if(CPUID::has_simd_32())
{
diff --git a/src/lib/ffi/ffi.h b/src/lib/ffi/ffi.h
index 0a537491c..ff7086488 100644
--- a/src/lib/ffi/ffi.h
+++ b/src/lib/ffi/ffi.h
@@ -1217,6 +1217,22 @@ BOTAN_PUBLIC_API(2,2) int botan_pubkey_ed25519_get_pubkey(botan_pubkey_t key,
uint8_t pubkey[32]);
/*
+* Algorithm specific key operations: X25519
+*/
+
+BOTAN_PUBLIC_API(2,8) int botan_privkey_load_x25519(botan_privkey_t* key,
+ const uint8_t privkey[32]);
+
+BOTAN_PUBLIC_API(2,8) int botan_pubkey_load_x25519(botan_pubkey_t* key,
+ const uint8_t pubkey[32]);
+
+BOTAN_PUBLIC_API(2,8) int botan_privkey_x25519_get_privkey(botan_privkey_t key,
+ uint8_t output[32]);
+
+BOTAN_PUBLIC_API(2,8) int botan_pubkey_x25519_get_pubkey(botan_pubkey_t key,
+ uint8_t pubkey[32]);
+
+/*
* Algorithm specific key operations: ECDSA and ECDH
*/
BOTAN_PUBLIC_API(2,2)
@@ -1513,7 +1529,7 @@ int botan_key_unwrap3394(const uint8_t wrapped_key[], size_t wrapped_key_len,
typedef struct botan_hotp_struct* botan_hotp_t;
/**
-* Initialize an HOTP instance
+* Initialize a HOTP instance
*/
BOTAN_PUBLIC_API(2,8)
int botan_hotp_init(botan_hotp_t* hotp,
@@ -1528,7 +1544,7 @@ BOTAN_PUBLIC_API(2,8)
int botan_hotp_destroy(botan_hotp_t hotp);
/**
-* Generate an HOTP code for the provided counter
+* Generate a HOTP code for the provided counter
*/
BOTAN_PUBLIC_API(2,8)
int botan_hotp_generate(botan_hotp_t hotp,
@@ -1536,7 +1552,7 @@ int botan_hotp_generate(botan_hotp_t hotp,
uint64_t hotp_counter);
/**
-* Verify an HOTP code
+* Verify a HOTP code
*/
BOTAN_PUBLIC_API(2,8)
int botan_hotp_check(botan_hotp_t hotp,
@@ -1553,7 +1569,7 @@ int botan_hotp_check(botan_hotp_t hotp,
typedef struct botan_totp_struct* botan_totp_t;
/**
-* Initialize an TOTP instance
+* Initialize a TOTP instance
*/
BOTAN_PUBLIC_API(2,8)
int botan_totp_init(botan_totp_t* totp,
@@ -1569,7 +1585,10 @@ BOTAN_PUBLIC_API(2,8)
int botan_totp_destroy(botan_totp_t totp);
/**
-* Generate an TOTP code for the provided counter
+* Generate a TOTP code for the provided timestamp
+* @param totp the TOTP object
+* @param totp_code the OTP code will be written here
+* @param timestamp the current local timestamp
*/
BOTAN_PUBLIC_API(2,8)
int botan_totp_generate(botan_totp_t totp,
@@ -1577,10 +1596,12 @@ int botan_totp_generate(botan_totp_t totp,
uint64_t timestamp);
/**
-* Verify an TOTP code
+* Verify a TOTP code
* @param totp the TOTP object
-* @param clock_drift if non-null and otp code is valid,
-* set to the drift between the two clocks.
+* @param totp_code the presented OTP
+* @param timestamp the current local timestamp
+* @param acceptable_clock_drift specifies the acceptable amount
+* of clock drift (in terms of time steps) between the two hosts.
*/
BOTAN_PUBLIC_API(2,8)
int botan_totp_check(botan_totp_t totp,
diff --git a/src/lib/ffi/ffi_pkey_algs.cpp b/src/lib/ffi/ffi_pkey_algs.cpp
index 52cbfa954..e98cb542b 100644
--- a/src/lib/ffi/ffi_pkey_algs.cpp
+++ b/src/lib/ffi/ffi_pkey_algs.cpp
@@ -843,6 +843,88 @@ int botan_pubkey_ed25519_get_pubkey(botan_pubkey_t key,
#endif
}
+/* X25519 specific operations */
+
+int botan_privkey_load_x25519(botan_privkey_t* key,
+ const uint8_t privkey[32])
+ {
+#if defined(BOTAN_HAS_X25519)
+ *key = nullptr;
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() -> int {
+ const Botan::secure_vector<uint8_t> privkey_vec(privkey, privkey + 32);
+ *key = new botan_privkey_struct(new Botan::X25519_PrivateKey(privkey_vec));
+ return BOTAN_FFI_SUCCESS;
+ });
+#else
+ BOTAN_UNUSED(key, privkey);
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+#endif
+ }
+
+int botan_pubkey_load_x25519(botan_pubkey_t* key,
+ const uint8_t pubkey[32])
+ {
+#if defined(BOTAN_HAS_X25519)
+ *key = nullptr;
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() -> int {
+ const std::vector<uint8_t> pubkey_vec(pubkey, pubkey + 32);
+ *key = new botan_pubkey_struct(new Botan::X25519_PublicKey(pubkey_vec));
+ return BOTAN_FFI_SUCCESS;
+ });
+#else
+ BOTAN_UNUSED(key, pubkey);
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+#endif
+ }
+
+int botan_privkey_x25519_get_privkey(botan_privkey_t key,
+ uint8_t output[32])
+ {
+#if defined(BOTAN_HAS_X25519)
+ return BOTAN_FFI_DO(Botan::Private_Key, key, k, {
+ if(Botan::X25519_PrivateKey* x25519 = dynamic_cast<Botan::X25519_PrivateKey*>(&k))
+ {
+ const Botan::secure_vector<uint8_t>& x25519_key = x25519->get_x();
+ if(x25519_key.size() != 32)
+ return BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE;
+ Botan::copy_mem(output, x25519_key.data(), x25519_key.size());
+ return BOTAN_FFI_SUCCESS;
+ }
+ else
+ {
+ return BOTAN_FFI_ERROR_BAD_PARAMETER;
+ }
+ });
+#else
+ BOTAN_UNUSED(key, output);
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+#endif
+ }
+
+int botan_pubkey_x25519_get_pubkey(botan_pubkey_t key,
+ uint8_t output[32])
+ {
+#if defined(BOTAN_HAS_X25519)
+ return BOTAN_FFI_DO(Botan::Public_Key, key, k, {
+ if(Botan::X25519_PublicKey* x25519 = dynamic_cast<Botan::X25519_PublicKey*>(&k))
+ {
+ const std::vector<uint8_t>& x25519_key = x25519->public_value();
+ if(x25519_key.size() != 32)
+ return BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE;
+ Botan::copy_mem(output, x25519_key.data(), x25519_key.size());
+ return BOTAN_FFI_SUCCESS;
+ }
+ else
+ {
+ return BOTAN_FFI_ERROR_BAD_PARAMETER;
+ }
+ });
+#else
+ BOTAN_UNUSED(key, output);
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+#endif
+ }
+
int botan_privkey_create_mceliece(botan_privkey_t* key_obj, botan_rng_t rng_obj, size_t n, size_t t)
{
const std::string mce_params = std::to_string(n) + "," + std::to_string(t);
diff --git a/src/lib/math/mp/mp_madd.h b/src/lib/math/mp/mp_madd.h
index 4f34efe39..43c769c7c 100644
--- a/src/lib/math/mp/mp_madd.h
+++ b/src/lib/math/mp/mp_madd.h
@@ -34,14 +34,12 @@ namespace Botan {
#if defined(BOTAN_USE_GCC_INLINE_ASM)
#define BOTAN_MP_USE_X86_32_ASM
- #define ASM(x) x "\n\t"
#elif defined(BOTAN_BUILD_COMPILER_IS_MSVC)
#define BOTAN_MP_USE_X86_32_MSVC_ASM
#endif
#elif defined(BOTAN_TARGET_ARCH_IS_X86_64) && (BOTAN_MP_WORD_BITS == 64) && (BOTAN_USE_GCC_INLINE_ASM)
#define BOTAN_MP_USE_X86_64_ASM
- #define ASM(x) x "\n\t"
#endif
#if defined(BOTAN_MP_USE_X86_32_ASM) || defined(BOTAN_MP_USE_X86_64_ASM)
diff --git a/src/lib/modes/cipher_mode.cpp b/src/lib/modes/cipher_mode.cpp
index 00d7a4db0..710f16ba2 100644
--- a/src/lib/modes/cipher_mode.cpp
+++ b/src/lib/modes/cipher_mode.cpp
@@ -35,6 +35,10 @@
#include <botan/internal/openssl.h>
#endif
+#if defined(BOTAN_HAS_COMMONCRYPTO)
+ #include <botan/internal/commoncrypto.h>
+#endif
+
namespace Botan {
std::unique_ptr<Cipher_Mode> Cipher_Mode::create_or_throw(const std::string& algo,
@@ -51,6 +55,19 @@ std::unique_ptr<Cipher_Mode> Cipher_Mode::create(const std::string& algo,
Cipher_Dir direction,
const std::string& provider)
{
+#if defined(BOTAN_HAS_COMMONCRYPTO)
+ if(provider.empty() || provider == "commoncrypto")
+ {
+ std::unique_ptr<Cipher_Mode> commoncrypto_cipher(make_commoncrypto_cipher_mode(algo, direction));
+
+ if(commoncrypto_cipher)
+ return commoncrypto_cipher;
+
+ if(!provider.empty())
+ return std::unique_ptr<Cipher_Mode>();
+ }
+#endif
+
#if defined(BOTAN_HAS_OPENSSL)
if(provider.empty() || provider == "openssl")
{
@@ -172,7 +189,7 @@ std::unique_ptr<Cipher_Mode> Cipher_Mode::create(const std::string& algo,
//static
std::vector<std::string> Cipher_Mode::providers(const std::string& algo_spec)
{
- const std::vector<std::string>& possible = { "base", "openssl" };
+ const std::vector<std::string>& possible = { "base", "openssl", "commoncrypto" };
std::vector<std::string> providers;
for(auto&& prov : possible)
{
diff --git a/src/lib/prov/commoncrypto/commoncrypto.h b/src/lib/prov/commoncrypto/commoncrypto.h
index 34b2a3f35..958cbab7d 100644
--- a/src/lib/prov/commoncrypto/commoncrypto.h
+++ b/src/lib/prov/commoncrypto/commoncrypto.h
@@ -16,14 +16,33 @@
namespace Botan {
+class Cipher_Mode;
+class BlockCipher;
class HashFunction;
+enum Cipher_Dir : int;
+typedef int32_t CCCryptorStatus;
-class BOTAN_PUBLIC_API(2,0) CommonCrypto_Error final : public Exception
- {
- public:
+class BOTAN_PUBLIC_API(2, 0) CommonCrypto_Error final : public Exception
+ {
+ std::string ccryptorstatus_to_string(CCCryptorStatus status);
+
+ public:
CommonCrypto_Error(const std::string& what) :
- Exception(what + " failed.") {}
- };
+ Exception(what + " failed.") {}
+
+ CommonCrypto_Error(const std::string& what, int32_t status) :
+ Exception(what + std::string(" failed. Status: ") + ccryptorstatus_to_string(status)) {}
+ };
+
+/* Cipher Modes */
+
+Cipher_Mode*
+make_commoncrypto_cipher_mode(const std::string& name, Cipher_Dir direction);
+
+/* Block Ciphers */
+
+std::unique_ptr<BlockCipher>
+make_commoncrypto_block_cipher(const std::string& name);
/* Hash */
diff --git a/src/lib/prov/commoncrypto/commoncrypto_block.cpp b/src/lib/prov/commoncrypto/commoncrypto_block.cpp
new file mode 100644
index 000000000..e912ed57e
--- /dev/null
+++ b/src/lib/prov/commoncrypto/commoncrypto_block.cpp
@@ -0,0 +1,152 @@
+/*
+* Block Ciphers via CommonCrypto
+* (C) 2018 Jose Luis Pereira
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/hex.h>
+
+#include <botan/block_cipher.h>
+#include <botan/internal/commoncrypto.h>
+#include <CommonCrypto/CommonCrypto.h>
+
+#include "commoncrypto_utils.h"
+
+namespace Botan {
+
+namespace {
+
+class CommonCrypto_BlockCipher final : public BlockCipher
+ {
+ public:
+ CommonCrypto_BlockCipher(const std::string& name, const CommonCryptor_Opts& opts);
+
+ ~CommonCrypto_BlockCipher();
+
+ void clear() override;
+ std::string provider() const override { return "commoncrypto"; }
+ std::string name() const override { return m_cipher_name; }
+ BlockCipher* clone() const override;
+
+ size_t block_size() const override { return m_opts.block_size; }
+
+ Key_Length_Specification key_spec() const override { return m_opts.key_spec; }
+
+ void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override
+ {
+ verify_key_set(m_key_set);
+ size_t total_len = blocks * m_opts.block_size;
+ size_t out_len = 0;
+
+ CCCryptorStatus status = CCCryptorUpdate(m_encrypt, in, total_len,
+ out, total_len, &out_len);
+ if(status != kCCSuccess)
+ {
+ throw CommonCrypto_Error("CCCryptorUpdate encrypt", status);
+ }
+ }
+
+ void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override
+ {
+ verify_key_set(m_key_set);
+ size_t total_len = blocks * m_opts.block_size;
+ size_t out_len = 0;
+
+ CCCryptorStatus status = CCCryptorUpdate(m_decrypt, in, total_len,
+ out, total_len, &out_len);
+ if(status != kCCSuccess)
+ {
+ throw CommonCrypto_Error("CCCryptorUpdate decrypt", status);
+ }
+ }
+
+ void key_schedule(const uint8_t key[], size_t key_len) override;
+
+ std::string m_cipher_name;
+ CommonCryptor_Opts m_opts;
+
+ CCCryptorRef m_encrypt = nullptr;
+ CCCryptorRef m_decrypt = nullptr;
+ bool m_key_set;
+ };
+
+CommonCrypto_BlockCipher::CommonCrypto_BlockCipher(const std::string& algo_name,
+ const CommonCryptor_Opts& opts) :
+ m_cipher_name(algo_name),
+ m_opts(opts),
+ m_key_set(false)
+ {
+ }
+
+CommonCrypto_BlockCipher::~CommonCrypto_BlockCipher()
+ {
+ if(m_encrypt)
+ {
+ CCCryptorRelease(m_encrypt);
+ }
+ if(m_decrypt)
+ {
+ CCCryptorRelease(m_decrypt);
+ }
+ }
+
+/*
+* Set the key
+*/
+void CommonCrypto_BlockCipher::key_schedule(const uint8_t key[], size_t length)
+ {
+ secure_vector<uint8_t> full_key(key, key + length);
+
+ commoncrypto_adjust_key_size(key, length, m_opts, full_key);
+
+ CCCryptorStatus status;
+ status = CCCryptorCreate(kCCEncrypt, m_opts.algo, kCCOptionECBMode,
+ full_key.data(), full_key.size(), nullptr, &m_encrypt);
+ if(status != kCCSuccess)
+ {
+ throw CommonCrypto_Error("CCCryptorCreate encrypt", status);
+ }
+ status = CCCryptorCreate(kCCDecrypt, m_opts.algo, kCCOptionECBMode,
+ full_key.data(), full_key.size(), nullptr, &m_decrypt);
+ if(status != kCCSuccess)
+ {
+ throw CommonCrypto_Error("CCCryptorCreate decrypt", status);
+ }
+
+ m_key_set = true;
+ }
+
+/*
+* Return a clone of this object
+*/
+BlockCipher* CommonCrypto_BlockCipher::clone() const
+ {
+ return new CommonCrypto_BlockCipher(m_cipher_name, m_opts);
+ }
+
+/*
+* Clear memory of sensitive data
+*/
+void CommonCrypto_BlockCipher::clear()
+ {
+ m_key_set = false;
+ }
+}
+
+std::unique_ptr<BlockCipher>
+make_commoncrypto_block_cipher(const std::string& name)
+ {
+
+ try
+ {
+ CommonCryptor_Opts opts = commoncrypto_opts_from_algo(name);
+ return std::unique_ptr<BlockCipher>(new CommonCrypto_BlockCipher(name, opts));
+ }
+ catch(CommonCrypto_Error e)
+ {
+ return nullptr;
+ }
+ }
+}
+
diff --git a/src/lib/prov/commoncrypto/commoncrypto_mode.cpp b/src/lib/prov/commoncrypto/commoncrypto_mode.cpp
new file mode 100644
index 000000000..baae11679
--- /dev/null
+++ b/src/lib/prov/commoncrypto/commoncrypto_mode.cpp
@@ -0,0 +1,240 @@
+/*
+* Cipher Modes via CommonCrypto
+* (C) 2018 Jose Pereira
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/cipher_mode.h>
+#include <botan/internal/rounding.h>
+#include <botan/internal/commoncrypto.h>
+
+#include "commoncrypto_utils.h"
+
+#include <limits.h>
+
+namespace Botan {
+
+namespace {
+
+class CommonCrypto_Cipher_Mode final : public Cipher_Mode
+ {
+ public:
+ CommonCrypto_Cipher_Mode(const std::string& name,
+ Cipher_Dir direction,
+ const CommonCryptor_Opts& opts);
+
+ ~CommonCrypto_Cipher_Mode();
+
+ std::string provider() const override { return "commoncrypto"; }
+ std::string name() const override { return m_mode_name; }
+
+ void start_msg(const uint8_t nonce[], size_t nonce_len) override;
+ size_t process(uint8_t msg[], size_t msg_len) override;
+ void finish(secure_vector<uint8_t>& final_block, size_t offset0) override;
+ size_t output_length(size_t input_length) const override;
+ size_t update_granularity() const override;
+ size_t minimum_final_size() const override;
+ size_t default_nonce_length() const override;
+ bool valid_nonce_length(size_t nonce_len) const override;
+ void clear() override;
+ void reset() override;
+ Key_Length_Specification key_spec() const override;
+
+ private:
+ void key_schedule(const uint8_t key[], size_t length) override;
+
+ const std::string m_mode_name;
+ Cipher_Dir m_direction;
+ CommonCryptor_Opts m_opts;
+ CCCryptorRef m_cipher = nullptr;
+ bool m_key_set;
+ bool m_nonce_set;
+ };
+
+CommonCrypto_Cipher_Mode::CommonCrypto_Cipher_Mode(const std::string& name,
+ Cipher_Dir direction, const CommonCryptor_Opts& opts) :
+ m_mode_name(name),
+ m_direction(direction),
+ m_opts(opts),
+ m_key_set(false),
+ m_nonce_set(false)
+ {
+ }
+
+CommonCrypto_Cipher_Mode::~CommonCrypto_Cipher_Mode()
+ {
+ if(m_cipher)
+ {
+ CCCryptorRelease(m_cipher);
+ }
+ }
+
+void CommonCrypto_Cipher_Mode::start_msg(const uint8_t nonce[], size_t nonce_len)
+ {
+ verify_key_set(m_key_set);
+
+ if(!valid_nonce_length(nonce_len))
+ { throw Invalid_IV_Length(name(), nonce_len); }
+ if(nonce_len)
+ {
+ CCCryptorStatus status = CCCryptorReset(m_cipher, nonce);
+ if(status != kCCSuccess)
+ {
+ throw CommonCrypto_Error("CCCryptorReset on start_msg", status);
+ }
+ }
+ m_nonce_set = true;
+ }
+
+size_t CommonCrypto_Cipher_Mode::process(uint8_t msg[], size_t msg_len)
+ {
+ verify_key_set(m_key_set);
+ BOTAN_STATE_CHECK(m_nonce_set);
+
+ if(msg_len == 0)
+ { return 0; }
+ if(msg_len > INT_MAX)
+ { throw Internal_Error("msg_len overflow"); }
+ size_t outl = CCCryptorGetOutputLength(m_cipher, msg_len, false);
+
+ secure_vector<uint8_t> out(outl);
+
+ if(m_opts.padding == ccNoPadding && msg_len % m_opts.block_size)
+ {
+ msg_len = outl;
+ }
+
+ CCCryptorStatus status = CCCryptorUpdate(m_cipher, msg, msg_len,
+ out.data(), outl, &outl);
+ if(status != kCCSuccess)
+ {
+ throw CommonCrypto_Error("CCCryptorUpdate", status);
+ }
+ memcpy(msg, out.data(), outl);
+
+ return outl;
+ }
+
+void CommonCrypto_Cipher_Mode::finish(secure_vector<uint8_t>& buffer,
+ size_t offset)
+ {
+ verify_key_set(m_key_set);
+
+ BOTAN_ASSERT(buffer.size() >= offset, "Offset ok");
+ uint8_t* buf = buffer.data() + offset;
+ const size_t buf_size = buffer.size() - offset;
+
+ size_t written = process(buf, buf_size);
+
+ size_t outl = CCCryptorGetOutputLength(m_cipher, buf_size - written, true);
+ secure_vector<uint8_t> out(outl);
+
+ CCCryptorStatus status = CCCryptorFinal(
+ m_cipher, out.data(), outl, &outl);
+ if(status != kCCSuccess)
+ {
+ throw CommonCrypto_Error("CCCryptorFinal", status);
+ }
+
+ size_t new_len = offset + written + outl;
+ if(m_opts.padding != ccNoPadding || buffer.size() < new_len)
+ {
+ buffer.resize(new_len);
+ }
+ memcpy(buffer.data() - offset + written, out.data(), outl);
+ written += outl;
+ }
+
+size_t CommonCrypto_Cipher_Mode::update_granularity() const
+ {
+ return m_opts.block_size * BOTAN_BLOCK_CIPHER_PAR_MULT;
+ }
+
+size_t CommonCrypto_Cipher_Mode::minimum_final_size() const
+ {
+ return 0;
+ }
+
+size_t CommonCrypto_Cipher_Mode::default_nonce_length() const
+ {
+ return m_opts.block_size;
+ }
+
+bool CommonCrypto_Cipher_Mode::valid_nonce_length(size_t nonce_len) const
+ {
+ return (nonce_len == 0 || nonce_len == m_opts.block_size);
+ }
+
+size_t CommonCrypto_Cipher_Mode::output_length(size_t input_length) const
+ {
+ if(input_length == 0)
+ { return m_opts.block_size; }
+ else
+ { return round_up(input_length, m_opts.block_size); }
+ }
+
+void CommonCrypto_Cipher_Mode::clear()
+ {
+ m_key_set = false;
+
+ if(m_cipher == nullptr)
+ {
+ return;
+ }
+
+ if(m_cipher)
+ {
+ CCCryptorRelease(m_cipher);
+ m_cipher = nullptr;
+ }
+ }
+
+void CommonCrypto_Cipher_Mode::reset()
+ {
+ if(m_cipher == nullptr)
+ {
+ return;
+ }
+ CCCryptorStatus status = CCCryptorReset(m_cipher, nullptr);
+ if(status != kCCSuccess)
+ {
+ throw CommonCrypto_Error("CCCryptorReset", status);
+ }
+ }
+
+Key_Length_Specification CommonCrypto_Cipher_Mode::key_spec() const
+ {
+ return m_opts.key_spec;
+ }
+
+void CommonCrypto_Cipher_Mode::key_schedule(const uint8_t key[], size_t length)
+ {
+ CCCryptorStatus status;
+ CCOperation op = m_direction == ENCRYPTION ? kCCEncrypt : kCCDecrypt;
+ status = CCCryptorCreateWithMode(op, m_opts.mode, m_opts.algo, m_opts.padding,
+ nullptr, key, length, nullptr, 0, 0, 0, &m_cipher);
+ if(status != kCCSuccess)
+ {
+ throw CommonCrypto_Error("CCCryptorCreate", status);
+ }
+
+ m_key_set = true;
+ }
+}
+
+Cipher_Mode*
+make_commoncrypto_cipher_mode(const std::string& name, Cipher_Dir direction)
+ {
+
+ try
+ {
+ CommonCryptor_Opts opts = commoncrypto_opts_from_algo(name);
+ return new CommonCrypto_Cipher_Mode(name, direction, opts);
+ }
+ catch(CommonCrypto_Error e)
+ {
+ return nullptr;
+ }
+ }
+}
diff --git a/src/lib/prov/commoncrypto/commoncrypto_utils.cpp b/src/lib/prov/commoncrypto/commoncrypto_utils.cpp
new file mode 100644
index 000000000..62736b88c
--- /dev/null
+++ b/src/lib/prov/commoncrypto/commoncrypto_utils.cpp
@@ -0,0 +1,187 @@
+/*
+* Cipher Modes via CommonCrypto
+* (C) 2018 Jose Pereira
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/cipher_mode.h>
+#include <botan/parsing.h>
+#include <botan/internal/commoncrypto.h>
+#include <botan/internal/rounding.h>
+#include <botan/scan_name.h>
+
+#include "commoncrypto_utils.h"
+
+namespace Botan {
+
+std::string CommonCrypto_Error::ccryptorstatus_to_string(CCCryptorStatus status)
+ {
+ switch(status)
+ {
+ case kCCSuccess:
+ return "Success";
+ case kCCParamError:
+ return "ParamError";
+ case kCCBufferTooSmall:
+ return "BufferTooSmall";
+ case kCCMemoryFailure:
+ return "MemoryFailure";
+ case kCCAlignmentError:
+ return "AlignmentError";
+ case kCCDecodeError:
+ return "DecodeError";
+ case kCCUnimplemented:
+ return "Unimplemented";
+ case kCCOverflow:
+ return "Overflow";
+ case kCCRNGFailure:
+ return "RNGFailure";
+ case kCCUnspecifiedError:
+ return "UnspecifiedError";
+ case kCCCallSequenceError:
+ return "CallSequenceError";
+ case kCCKeySizeError:
+ return "KeySizeError";
+ default:
+ return "Unknown";
+ }
+ };
+
+
+CommonCryptor_Opts commoncrypto_opts_from_algo(const std::string& algo)
+ {
+ SCAN_Name spec(algo);
+
+ std::string algo_name = spec.algo_name();
+ std::string cipher_mode = spec.cipher_mode();
+ std::string cipher_mode_padding = spec.cipher_mode_pad();
+
+ CommonCryptor_Opts opts;
+
+ if(algo_name.compare(0, 3, "AES") == 0)
+ {
+ opts.algo = kCCAlgorithmAES;
+ opts.block_size = kCCBlockSizeAES128;
+ if(algo_name == "AES-128")
+ {
+ opts.key_spec = Key_Length_Specification(kCCKeySizeAES128);
+ }
+ else if(algo_name == "AES-192")
+ {
+ opts.key_spec = Key_Length_Specification(kCCKeySizeAES192);
+ }
+ else if(algo_name == "AES-256")
+ {
+ opts.key_spec = Key_Length_Specification(kCCKeySizeAES256);
+ }
+ else
+ {
+ throw CommonCrypto_Error("Unknown AES algorithm");
+ }
+ }
+ else if(algo_name == "DES")
+ {
+ opts.algo = kCCAlgorithmDES;
+ opts.block_size = kCCBlockSizeDES;
+ opts.key_spec = Key_Length_Specification(kCCKeySizeDES);
+ }
+ else if(algo_name == "TripleDES")
+ {
+ opts.algo = kCCAlgorithm3DES;
+ opts.block_size = kCCBlockSize3DES;
+ opts.key_spec = Key_Length_Specification(16, kCCKeySize3DES, 8);
+ }
+ else if(algo_name == "Blowfish")
+ {
+ opts.algo = kCCAlgorithmBlowfish;
+ opts.block_size = kCCBlockSizeBlowfish;
+ opts.key_spec = Key_Length_Specification(1, kCCKeySizeMaxBlowfish, 1);
+ }
+ else if(algo_name == "CAST-128")
+ {
+ opts.algo = kCCAlgorithmCAST;
+ opts.block_size = kCCBlockSizeCAST;
+ // Botan's base implementation of CAST does not support shorter keys
+ // so we limit its minimum key size to 11 here.
+ opts.key_spec = Key_Length_Specification(11, kCCKeySizeMaxCAST, 1);
+ }
+ else
+ {
+ throw CommonCrypto_Error("Unsupported cipher");
+ }
+
+ //TODO add CFB and XTS support
+ if(cipher_mode.empty() || cipher_mode == "ECB")
+ {
+ opts.mode = kCCModeECB;
+ }
+ else if(cipher_mode == "CBC")
+ {
+ opts.mode = kCCModeCBC;
+ }
+ else if(cipher_mode == "CTR")
+ {
+ opts.mode = kCCModeCTR;
+ }
+ else if(cipher_mode == "OFB")
+ {
+ opts.mode = kCCModeOFB;
+ }
+ else
+ {
+ throw CommonCrypto_Error("Unsupported cipher mode!");
+ }
+
+ if(cipher_mode_padding.empty() || cipher_mode_padding == "PKCS7")
+ {
+ opts.padding = ccPKCS7Padding;
+ }
+ else if(cipher_mode_padding == "NoPadding")
+ {
+ opts.padding = ccNoPadding;
+ }
+ else
+ {
+ throw CommonCrypto_Error("Unsupported cipher mode padding!");
+ }
+
+ return opts;
+ }
+
+
+void commoncrypto_adjust_key_size(const uint8_t key[], size_t length,
+ const CommonCryptor_Opts& opts, secure_vector<uint8_t>& full_key)
+ {
+
+ if(opts.algo == kCCAlgorithmBlowfish && length < 8)
+ {
+ size_t repeat;
+ switch(length)
+ {
+ case 1:
+ repeat = 8;
+ break;
+ case 2:
+ repeat = 4;
+ break;
+ case 3:
+ repeat = 3;
+ break;
+ default:
+ repeat = 2;
+ break;
+ }
+
+ full_key.resize(length * repeat);
+ for(int i=0; i<repeat; i++)
+ {
+ memcpy(full_key.data() + i * length, key, length);
+ }
+ }
+ else if(opts.algo == kCCAlgorithm3DES && length == 16)
+ {
+ full_key += std::make_pair(key, 8);
+ }
+ }
+}
diff --git a/src/lib/prov/commoncrypto/commoncrypto_utils.h b/src/lib/prov/commoncrypto/commoncrypto_utils.h
new file mode 100644
index 000000000..f4bdf4e24
--- /dev/null
+++ b/src/lib/prov/commoncrypto/commoncrypto_utils.h
@@ -0,0 +1,36 @@
+/*
+* Utils for calling CommonCrypto
+* (C) 2018 Jose Pereira
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_INTERNAL_COMMONCRYPTO_UTILS_H_
+#define BOTAN_INTERNAL_COMMONCRYPTO_UTILS_H_
+
+#include <botan/key_spec.h>
+
+#include <CommonCrypto/CommonCrypto.h>
+
+namespace Botan {
+
+class Key_Length_Specification;
+
+struct CommonCryptor_Opts
+ {
+ CCAlgorithm algo;
+ CCMode mode;
+ CCPadding padding;
+ size_t block_size;
+ Key_Length_Specification key_spec{0};
+ };
+
+CommonCryptor_Opts commoncrypto_opts_from_algo(const std::string& algo);
+
+void commoncrypto_adjust_key_size(const uint8_t key[], size_t length,
+ const CommonCryptor_Opts& opts, secure_vector<uint8_t>& full_key);
+
+
+}
+
+#endif
diff --git a/src/lib/prov/commoncrypto/info.txt b/src/lib/prov/commoncrypto/info.txt
index 00f92cd58..d56fe5731 100644
--- a/src/lib/prov/commoncrypto/info.txt
+++ b/src/lib/prov/commoncrypto/info.txt
@@ -11,3 +11,8 @@ commoncrypto.h
<os_features>
commoncrypto
</os_features>
+
+<requires>
+modes
+block
+</requires>
diff --git a/src/lib/pubkey/curve25519/curve25519.h b/src/lib/pubkey/curve25519/curve25519.h
index 1e06fae67..c2f8f42b3 100644
--- a/src/lib/pubkey/curve25519/curve25519.h
+++ b/src/lib/pubkey/curve25519/curve25519.h
@@ -99,6 +99,9 @@ class BOTAN_PUBLIC_API(2,0) Curve25519_PrivateKey final : public Curve25519_Publ
secure_vector<uint8_t> m_private;
};
+typedef Curve25519_PublicKey X25519_PublicKey;
+typedef Curve25519_PrivateKey X25519_PrivateKey;
+
/*
* The types above are just wrappers for curve25519_donna, plus defining
* encodings for public and private keys.
diff --git a/src/lib/pubkey/curve25519/info.txt b/src/lib/pubkey/curve25519/info.txt
index 085314cfe..3818b0606 100644
--- a/src/lib/pubkey/curve25519/info.txt
+++ b/src/lib/pubkey/curve25519/info.txt
@@ -1,5 +1,6 @@
<defines>
CURVE_25519 -> 20170621
+X25519 -> 20180910
</defines>
<header:public>
diff --git a/src/lib/x509/info.txt b/src/lib/x509/info.txt
index 6b136cbcf..20a1aa2b0 100644
--- a/src/lib/x509/info.txt
+++ b/src/lib/x509/info.txt
@@ -1,5 +1,6 @@
<defines>
X509_CERTIFICATES -> 20151023
+X509 -> 20180911
OCSP -> 20161118
</defines>
diff --git a/src/scripts/ci/setup_travis.sh b/src/scripts/ci/setup_travis.sh
index 9c6c79012..14a88a5c3 100755
--- a/src/scripts/ci/setup_travis.sh
+++ b/src/scripts/ci/setup_travis.sh
@@ -84,7 +84,7 @@ if [ "$TRAVIS_OS_NAME" = "linux" ]; then
#
sudo apt-get remove python-requests python-openssl python-roman
- sudo pip install requests pyopenssl roman sphinx
+ sudo pip install requests pyopenssl roman sphinx==1.7.9
fi
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
diff --git a/src/tests/data/cryptobox.vec b/src/tests/data/cryptobox.vec
new file mode 100644
index 000000000..cb397f92b
--- /dev/null
+++ b/src/tests/data/cryptobox.vec
@@ -0,0 +1,92 @@
+
+# Generated by Botan 2.0
+
+Input =
+Salt = 42434041464744454A4B
+Passphrase = passphrase_0
+Output = EFC2240042434041464744454A4B791BEF092F976AF5F1B9219C1F2B71BE7B247647
+
+Input = 67
+Salt = 434041464744454A4B48
+Passphrase = passphrase_1
+Output = EFC22400434041464744454A4B48AAA3FCA400FF22A576D5A20C638CB5080831AB269D
+
+Input = 6465
+Salt = 4041464744454A4B4849
+Passphrase = passphrase_2
+Output = EFC224004041464744454A4B484981121406F83782EBCAAE06FDB1B0A8599DE6D721C279
+
+Input = 656263
+Salt = 41464744454A4B48494E
+Passphrase = passphrase_3
+Output = EFC2240041464744454A4B48494EF50B4430A0E524651EC7088EBA195E25F60D342A4D1839
+
+Input = 62636061
+Salt = 464744454A4B48494E4F
+Passphrase = passphrase_4
+Output = EFC22400464744454A4B48494E4FA1842DE30D76A586A4BFE958FC777178128A31BF836327C8
+
+Input = 6360616E6F
+Salt = 4744454A4B48494E4F4C
+Passphrase = passphrase_5
+Output = EFC224004744454A4B48494E4F4CE6584DF80422FC28A9AB39BCDBDFD72988CC93404A6DF39C43
+
+Input = 60616E6F6C6D
+Salt = 44454A4B48494E4F4C4D
+Passphrase = passphrase_6
+Output = EFC2240044454A4B48494E4F4C4D0A52AB379B7EB45CF9917E63582A9F958563CF21159D2350308A
+
+Input = 616E6F6C6D6A6B
+Salt = 454A4B48494E4F4C4D52
+Passphrase = passphrase_7
+Output = EFC22400454A4B48494E4F4C4D5288055EC1F9BC81734F96CDCDCF879E939484B7A41F26AABD992CDA
+
+Input = 6E6F6C6D6A6B6869
+Salt = 4A4B48494E4F4C4D5253
+Passphrase = passphrase_8
+Output = EFC224004A4B48494E4F4C4D525348B8CBF00F22DACFEE8BCC1034EB41DA0CB1901F85BFED87E6C1F70C
+
+Input = 6F6C6D6A6B68697677
+Salt = 4B48494E4F4C4D525350
+Passphrase = passphrase_9
+Output = EFC224004B48494E4F4C4D525350C2B4D2E37730AD85D87DB14C446DEC8F32CC8FB95C90BFC8BA76B41A68
+
+Input = 6C6D6A6B686976777475
+Salt = 48494E4F4C4D52535051
+Passphrase = passphrase_10
+Output = EFC2240048494E4F4C4D525350514D0A851CB9B98EAB808A159865A578008366EAE7D71AF33B018B56B3D8EE
+
+Input = 6D6A6B6869767774757273
+Salt = 494E4F4C4D5253505156
+Passphrase = passphrase_11
+Output = EFC22400494E4F4C4D525350515620390098C6708307789436F586FE45B6F6E5D93F4A623A4CD7F64D3A4799DA
+
+Input = 6A6B68697677747572737071
+Salt = 4E4F4C4D525350515657
+Passphrase = passphrase_12
+Output = EFC224004E4F4C4D52535051565761C7CC345DD0900264648975F99051996CCE0EE29F082DB8F39CBC20E2FD5C82
+
+Input = 6B686976777475727370717E7F
+Salt = 4F4C4D52535051565754
+Passphrase = passphrase_13
+Output = EFC224004F4C4D52535051565754C537DE170C00AD72BFF5542481B19FC89C048723170CE58BD9183714897B8BE012
+
+Input = 686976777475727370717E7F7C7D
+Salt = 4C4D5253505156575455
+Passphrase = passphrase_14
+Output = EFC224004C4D5253505156575455E2F9CED9F76669C5CBD91383AE80C9F653567038A71A3D59081E1CA89A1A1843BF1E
+
+Input = 6976777475727370717E7F7C7D7A7B
+Salt = 4D52535051565754555A
+Passphrase = passphrase_15
+Output = EFC224004D52535051565754555A91AC3715C0C9F6735566794D29D76157381D17F1FC3D303370011ABDD4513D93CD5128
+
+Input = 76777475727370717E7F7C7D7A7B7879
+Salt = 52535051565754555A5B
+Passphrase = passphrase_16
+Output = EFC2240052535051565754555A5B9B0F0B4189AC0AC3E8E0587135AEC109256C8964B01095AD8A2715B1EE51C6A54F850804
+
+Input = 7946474445424340414E4F4C4D4A4B484956575455525350515E5F5C5D5A5B
+Salt = 5D62636061666764656A
+Passphrase = passphrase_31
+Output = EFC224005D62636061666764656A5272C74FD3E21444CC93423B7FA86172063741E0504078B25584C32B275D792C4B6B3BD3F517C1116D45F4F6238AC1112E93A0
diff --git a/src/tests/test_certstor.cpp b/src/tests/test_certstor.cpp
index 4963f7465..5bf8ce8fa 100644
--- a/src/tests/test_certstor.cpp
+++ b/src/tests/test_certstor.cpp
@@ -7,7 +7,8 @@
#include "tests.h"
#include <sstream>
-#if defined(BOTAN_HAS_X509) && defined(BOTAN_HAS_PUBKEY)
+#if defined(BOTAN_HAS_X509_CERTIFICATES)
+ #include <botan/x509cert.h>
#include <botan/certstor.h>
#include <botan/internal/filesystem.h>
#include <botan/pkcs8.h>
@@ -23,7 +24,7 @@ namespace Botan_Tests {
namespace {
-#if defined(BOTAN_HAS_X509) && defined(BOTAN_HAS_RSA) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
+#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_HAS_RSA) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
struct CertificateAndKey
{
diff --git a/src/tests/test_cryptobox.cpp b/src/tests/test_cryptobox.cpp
index 5e7fcf08a..d3b011eb4 100644
--- a/src/tests/test_cryptobox.cpp
+++ b/src/tests/test_cryptobox.cpp
@@ -1,14 +1,15 @@
/*
-* (C) 2014,2015 Jack Lloyd
+* (C) 2014,2015,2018 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
#include "tests.h"
+#include "test_rng.h"
#if defined(BOTAN_HAS_CRYPTO_BOX)
#include <botan/cryptobox.h>
- #include <botan/hex.h>
+ #include <botan/pem.h>
#endif
namespace Botan_Tests {
@@ -17,56 +18,55 @@ namespace {
#if defined(BOTAN_HAS_CRYPTO_BOX)
-class Cryptobox_Tests final : public Test
+class Cryptobox_KAT final : public Text_Based_Test
{
public:
- std::vector<Test::Result> run() override
+ Cryptobox_KAT() : Text_Based_Test("cryptobox.vec", "Input,Passphrase,Salt,Output") {}
+
+ Test::Result run_one_test(const std::string&, const VarMap& vars) override
{
- Test::Result result("cryptobox");
+ Test::Result result("Cryptobox");
+
+ const std::string password = vars.get_req_str("Passphrase");
+ const std::vector<uint8_t> input = vars.get_req_bin("Input");
+ const std::vector<uint8_t> salt = vars.get_req_bin("Salt");
+ const std::vector<uint8_t> expected = vars.get_req_bin("Output");
+
+ const std::string expected_pem = Botan::PEM_Code::encode(expected, "BOTAN CRYPTOBOX MESSAGE");
+
+ Fixed_Output_RNG salt_rng(salt);
+
+ const std::string ciphertext =
+ Botan::CryptoBox::encrypt(input.data(), input.size(), password, salt_rng);
+
+ result.test_eq("encryption is expected value", ciphertext, expected_pem);
+
+ result.test_eq("decryption works", Botan::CryptoBox::decrypt_bin(ciphertext, password), input);
- for(size_t i = 0; i <= 128; i += 7)
+ // Now corrupt a bit and ensure it fails
+ try
{
- const std::string password = Test::random_password();
- const std::vector<uint8_t> input = unlock(Test::rng().random_vec(i));
-
- const std::string ciphertext =
- Botan::CryptoBox::encrypt(input.data(), input.size(), password, Test::rng());
-
- // First verify decryption works
- try
- {
- const Botan::secure_vector<uint8_t> decrypted =
- Botan::CryptoBox::decrypt_bin(ciphertext, password);
- result.test_eq("decrypt", decrypted, input);
- }
- catch(std::exception& e)
- {
- result.test_failure("cryptobox decrypt", e.what());
- }
-
- // Now corrupt a bit and ensure it fails
- try
- {
- std::string corrupted = ciphertext;
- corrupted[corrupted.size()/2]++;
- Botan::CryptoBox::decrypt(corrupted, password);
- result.test_failure("Decrypted corrupted cryptobox message");
- }
- catch(Botan::Decoding_Error&)
- {
- result.test_success("Rejected corrupted cryptobox message");
- }
- catch(Botan::Invalid_Argument&)
- {
- result.test_success("Rejected corrupted cryptobox message");
- }
+ const std::vector<uint8_t> corrupted = Test::mutate_vec(expected);
+ const std::string corrupted_pem = Botan::PEM_Code::encode(corrupted, "BOTAN CRYPTOBOX MESSAGE");
+
+ Botan::CryptoBox::decrypt(corrupted_pem, password);
+ result.test_failure("Decrypted corrupted cryptobox message", corrupted);
+ }
+ catch(Botan::Decoding_Error&)
+ {
+ result.test_success("Rejected corrupted cryptobox message");
+ }
+ catch(Botan::Invalid_Argument&)
+ {
+ result.test_success("Rejected corrupted cryptobox message");
}
- return {result};
+ return result;
}
+
};
-BOTAN_REGISTER_TEST("cryptobox", Cryptobox_Tests);
+BOTAN_REGISTER_TEST("cryptobox", Cryptobox_KAT);
#endif
diff --git a/src/tests/test_ffi.cpp b/src/tests/test_ffi.cpp
index 5a323ab6d..6687697cb 100644
--- a/src/tests/test_ffi.cpp
+++ b/src/tests/test_ffi.cpp
@@ -134,6 +134,10 @@ class FFI_Unit_Tests final : public Test
results.push_back(ffi_test_ed25519(rng));
#endif
+#if defined(BOTAN_HAS_X25519)
+ results.push_back(ffi_test_x25519());
+#endif
+
TEST_FFI_OK(botan_rng_destroy, (rng));
results.push_back(result);
@@ -2420,6 +2424,60 @@ class FFI_Unit_Tests final : public Test
return result;
}
+ Test::Result ffi_test_x25519()
+ {
+ Test::Result result("FFI X25519");
+
+ // From RFC 8037
+
+ const std::vector<uint8_t> a_pub_bits =
+ Botan::hex_decode("de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f");
+ const std::vector<uint8_t> b_priv_bits =
+ Botan::hex_decode("77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a");
+ const std::vector<uint8_t> b_pub_bits =
+ Botan::hex_decode("8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a");
+ const std::vector<uint8_t> shared_secret_bits =
+ Botan::hex_decode("4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742");
+
+ botan_privkey_t b_priv;
+ TEST_FFI_OK(botan_privkey_load_x25519, (&b_priv, b_priv_bits.data()));
+
+ std::vector<uint8_t> privkey_read(32);
+ TEST_FFI_OK(botan_privkey_x25519_get_privkey, (b_priv, privkey_read.data()));
+ result.test_eq("X25519 private key", privkey_read, b_priv_bits);
+
+ std::vector<uint8_t> pubkey_read(32);
+
+ botan_pubkey_t b_pub;
+ TEST_FFI_OK(botan_privkey_export_pubkey, (&b_pub, b_priv));
+ TEST_FFI_OK(botan_pubkey_x25519_get_pubkey, (b_pub, pubkey_read.data()));
+ result.test_eq("X25519 public key b", pubkey_read, b_pub_bits);
+
+ botan_pubkey_t a_pub;
+ TEST_FFI_OK(botan_pubkey_load_x25519, (&a_pub, a_pub_bits.data()));
+ TEST_FFI_OK(botan_pubkey_x25519_get_pubkey, (a_pub, pubkey_read.data()));
+ result.test_eq("X25519 public key a", pubkey_read, a_pub_bits);
+
+ botan_pk_op_ka_t ka;
+ REQUIRE_FFI_OK(botan_pk_op_key_agreement_create, (&ka, b_priv, "Raw", 0));
+
+ std::vector<uint8_t> shared_output(32);
+ size_t shared_len = shared_output.size();
+ TEST_FFI_OK(botan_pk_op_key_agreement, (ka,
+ shared_output.data(), &shared_len,
+ a_pub_bits.data(), a_pub_bits.size(),
+ nullptr, 0));
+
+ result.test_eq("Shared secret matches expected", shared_secret_bits, shared_output);
+
+ TEST_FFI_OK(botan_pubkey_destroy, (a_pub));
+ TEST_FFI_OK(botan_pubkey_destroy, (b_pub));
+ TEST_FFI_OK(botan_privkey_destroy, (b_priv));
+ TEST_FFI_OK(botan_pk_op_key_agreement_destroy, (ka));
+
+ return result;
+ }
+
void do_elgamal_test(botan_privkey_t priv, botan_rng_t rng, Test::Result& result)
{
TEST_FFI_OK(botan_privkey_check_key, (priv, rng, 0));