aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/ffi
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2017-07-25 15:24:30 -0400
committerJack Lloyd <[email protected]>2017-07-31 10:31:53 -0400
commit5703b195f5dbf0a0df45bf0a7f39aa090666f877 (patch)
tree1f686ae1362aaef9eabe1db3c1a58ac0fd166a70 /src/lib/ffi
parentbb30a1e1ffbe839478b4bf04624d841c6d9ecfc3 (diff)
Split up ffi.cpp into several files
It was getting pretty big and would get worse over time, eg whenver I get around to adding TLS support.
Diffstat (limited to 'src/lib/ffi')
-rw-r--r--src/lib/ffi/ffi.cpp2307
-rw-r--r--src/lib/ffi/ffi.h23
-rw-r--r--src/lib/ffi/ffi_block.cpp81
-rw-r--r--src/lib/ffi/ffi_cert.cpp136
-rw-r--r--src/lib/ffi/ffi_cipher.cpp196
-rw-r--r--src/lib/ffi/ffi_hash.cpp70
-rw-r--r--src/lib/ffi/ffi_kdf.cpp98
-rw-r--r--src/lib/ffi/ffi_keywrap.cpp50
-rw-r--r--src/lib/ffi/ffi_mac.cpp64
-rw-r--r--src/lib/ffi/ffi_mp.cpp280
-rw-r--r--src/lib/ffi/ffi_mp.h21
-rw-r--r--src/lib/ffi/ffi_pk_op.cpp216
-rw-r--r--src/lib/ffi/ffi_pkey.cpp263
-rw-r--r--src/lib/ffi/ffi_pkey.h22
-rw-r--r--src/lib/ffi/ffi_pkey_algs.cpp757
-rw-r--r--src/lib/ffi/ffi_rng.cpp53
-rw-r--r--src/lib/ffi/ffi_rng.h21
-rw-r--r--src/lib/ffi/ffi_util.h197
-rw-r--r--src/lib/ffi/info.txt11
19 files changed, 2552 insertions, 2314 deletions
diff --git a/src/lib/ffi/ffi.cpp b/src/lib/ffi/ffi.cpp
index f13ab7b83..28eac401a 100644
--- a/src/lib/ffi/ffi.cpp
+++ b/src/lib/ffi/ffi.cpp
@@ -5,126 +5,13 @@
*/
#include <botan/ffi.h>
-#include <botan/system_rng.h>
-#include <botan/exceptn.h>
-#include <botan/auto_rng.h>
-#include <botan/aead.h>
-#include <botan/block_cipher.h>
-#include <botan/hash.h>
-#include <botan/mac.h>
-#include <botan/pbkdf.h>
+#include <botan/internal/ffi_util.h>
#include <botan/version.h>
-#include <botan/pkcs8.h>
-#include <botan/x509cert.h>
-#include <botan/data_src.h>
-#include <botan/pubkey.h>
-#include <botan/hex.h>
#include <botan/mem_ops.h>
-#include <botan/x509_key.h>
-#include <botan/pk_algs.h>
-#include <botan/bigint.h>
-#include <botan/reducer.h>
-#include <botan/numthry.h>
-#include <botan/divide.h>
-#include <cstring>
-#include <memory>
-
-#if defined(BOTAN_HAS_RSA)
- #include <botan/rsa.h>
-#endif
-
-#if defined(BOTAN_HAS_ELGAMAL)
- #include <botan/elgamal.h>
-#endif
-
-#if defined(BOTAN_HAS_DSA)
- #include <botan/dsa.h>
-#endif
-
-#if defined(BOTAN_HAS_ECDSA)
- #include <botan/ecdsa.h>
-#endif
-
-#if defined(BOTAN_HAS_SM2)
- #include <botan/sm2.h>
-#endif
-
-#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO)
- #include <botan/ecc_key.h>
-#endif
-
-#if defined(BOTAN_HAS_DL_PUBLIC_KEY_FAMILY)
- #include <botan/dl_algo.h>
-#endif
-
-#if defined(BOTAN_HAS_ECDH)
- #include <botan/ecdh.h>
-#endif
-
-#if defined(BOTAN_HAS_CURVE_25519)
- #include <botan/curve25519.h>
-#endif
-
-#if defined(BOTAN_HAS_ED25519)
- #include <botan/ed25519.h>
-#endif
-
-#if defined(BOTAN_HAS_MCELIECE)
- #include <botan/mceliece.h>
-#endif
-
-#if defined(BOTAN_HAS_MCEIES)
- #include <botan/mceies.h>
-#endif
-
-#if defined(BOTAN_HAS_BCRYPT)
- #include <botan/bcrypt.h>
-#endif
-
-#if defined(BOTAN_HAS_HASH_ID)
- #include <botan/hash_id.h>
-#endif
-
-#if defined(BOTAN_HAS_TLS)
- #include <botan/tls_client.h>
- #include <botan/tls_server.h>
-#endif
-
-#if defined(BOTAN_HAS_RFC3394_KEYWRAP)
- #include <botan/rfc3394.h>
-#endif
-
-namespace {
-
-#define BOTAN_ASSERT_ARG_NON_NULL(p) \
- do { if(!p) throw Botan::Invalid_Argument("Argument " #p " is null"); } while(0)
-
-class FFI_Error : public Botan::Exception
- {
- public:
- explicit FFI_Error(const std::string& what) : Exception("FFI error", what) {}
- };
-
-template<typename T, uint32_t MAGIC>
-struct botan_struct
- {
- public:
- botan_struct(T* obj) : m_magic(MAGIC), m_obj(obj) {}
- ~botan_struct() { m_magic = 0; m_obj.reset(); }
-
- bool magic_ok() const { return (m_magic == MAGIC); }
+#include <botan/hex.h>
+#include <cstdio>
- T* get() const
- {
- if(magic_ok() == false)
- throw FFI_Error("Bad magic " + std::to_string(m_magic) +
- " in ffi object expected " + std::to_string(MAGIC));
- return m_obj.get();
- }
- private:
- uint32_t m_magic = 0;
- std::unique_ptr<T> m_obj;
- };
+namespace Botan_FFI {
int ffi_error_exception_thrown(const char* func_name, const char* exn)
{
@@ -132,332 +19,11 @@ int ffi_error_exception_thrown(const char* func_name, const char* exn)
return BOTAN_FFI_ERROR_EXCEPTION_THROWN;
}
-template<typename T, uint32_t M>
-T& safe_get(botan_struct<T,M>* p)
- {
- if(!p)
- throw FFI_Error("Null pointer argument");
- if(T* t = p->get())
- return *t;
- throw FFI_Error("Invalid object pointer");
- }
-
-template<typename T, uint32_t M>
-const T& safe_get(const botan_struct<T,M>* p)
- {
- if(!p)
- throw FFI_Error("Null pointer argument");
- if(const T* t = p->get())
- return *t;
- throw FFI_Error("Invalid object pointer");
- }
-
-template<typename Thunk>
-int ffi_guard_thunk(const char* func_name, Thunk thunk)
- {
- try
- {
- return thunk();
- }
- catch(std::bad_alloc)
- {
- return ffi_error_exception_thrown(func_name, "bad_alloc");
- }
- catch(std::exception& e)
- {
- return ffi_error_exception_thrown(func_name, e.what());
- }
- catch(...)
- {
- return ffi_error_exception_thrown(func_name, "unknown exception");
- }
-
- return BOTAN_FFI_ERROR_UNKNOWN_ERROR;
- }
-
-#define BOTAN_GUARD_BLOCK(b) ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, []() t))
-
-template<typename T, uint32_t M, typename F>
-int apply_fn(botan_struct<T, M>* o, const char* func_name, F func)
- {
- try
- {
- if(!o)
- throw FFI_Error("Null object to " + std::string(func_name));
- if(T* t = o->get())
- return func(*t);
- }
- catch(std::bad_alloc)
- {
- return ffi_error_exception_thrown(func_name, "bad_alloc");
- }
- catch(std::exception& e)
- {
- return ffi_error_exception_thrown(func_name, e.what());
- }
- catch(...)
- {
- return ffi_error_exception_thrown(func_name, "unknown exception");
- }
-
- return BOTAN_FFI_ERROR_UNKNOWN_ERROR;
- }
-
-#define BOTAN_FFI_DO(T, obj, param, block) \
- apply_fn(obj, BOTAN_CURRENT_FUNCTION, \
- [=](T& param) -> int { do { block } while(0); return BOTAN_FFI_SUCCESS; })
-
-template<typename T, uint32_t M>
-int ffi_delete_object(botan_struct<T, M>* obj, const char* func_name)
- {
- try
- {
- if(obj == nullptr)
- return BOTAN_FFI_SUCCESS; // ignore delete of null objects
-
- if(obj->magic_ok() == false)
- return BOTAN_FFI_ERROR_INVALID_INPUT;
-
- delete obj;
- return BOTAN_FFI_SUCCESS;
- }
- catch(std::exception& e)
- {
- return ffi_error_exception_thrown(func_name, e.what());
- }
- catch(...)
- {
- return ffi_error_exception_thrown(func_name, "unknown exception");
- }
- }
-
-#define BOTAN_FFI_CHECKED_DELETE(o) ffi_delete_object(o, BOTAN_CURRENT_FUNCTION)
-
-inline int write_output(uint8_t out[], size_t* out_len, const uint8_t buf[], size_t buf_len)
- {
- const size_t avail = *out_len;
- *out_len = buf_len;
-
- if(avail >= buf_len)
- {
- Botan::copy_mem(out, buf, buf_len);
- return BOTAN_FFI_SUCCESS;
- }
- else
- {
- Botan::clear_mem(out, avail);
- return BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE;
- }
- }
-
-template<typename Alloc>
-int write_vec_output(uint8_t out[], size_t* out_len, const std::vector<uint8_t, Alloc>& buf)
- {
- return write_output(out, out_len, buf.data(), buf.size());
- }
-
-inline int write_str_output(uint8_t out[], size_t* out_len, const std::string& str)
- {
- return write_output(out, out_len,
- reinterpret_cast<const uint8_t*>(str.c_str()),
- str.size() + 1);
- }
-
-inline int write_str_output(char out[], size_t* out_len, const std::string& str)
- {
- return write_str_output(reinterpret_cast<uint8_t*>(out), out_len, str);
- }
-
-inline int write_str_output(char out[], size_t* out_len, const std::vector<uint8_t>& str_vec)
- {
- return write_output(reinterpret_cast<uint8_t*>(out), out_len,
- reinterpret_cast<const uint8_t*>(str_vec.data()),
- str_vec.size());
- }
-
-Botan::BigInt pubkey_get_field(const Botan::Public_Key& key,
- const std::string& field)
- {
- // Maybe this should be `return key.get_integer_field(field_name)`?
-
-#if defined(BOTAN_HAS_RSA)
- if(const Botan::RSA_PublicKey* rsa = dynamic_cast<const Botan::RSA_PublicKey*>(&key))
- {
- if(field == "n")
- return rsa->get_n();
- else if(field == "e")
- return rsa->get_e();
- else
- throw Botan::Exception("Field not supported");
- }
-#endif
-
-#if defined(BOTAN_HAS_DL_PUBLIC_KEY_FAMILY)
- // Handles DSA, ElGamal, etc
- if(const Botan::DL_Scheme_PublicKey* dl = dynamic_cast<const Botan::DL_Scheme_PublicKey*>(&key))
- {
- if(field == "p")
- return dl->group_p();
- else if(field == "q")
- return dl->group_q();
- else if(field == "g")
- return dl->group_g();
- else if(field == "y")
- return dl->get_y();
- else
- throw Botan::Exception("Field not supported");
- }
-#endif
-
-#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO)
- if(const Botan::EC_PublicKey* ecc = dynamic_cast<const Botan::EC_PublicKey*>(&key))
- {
- if(field == "public_x")
- return ecc->public_point().get_affine_x();
- else if(field == "public_y")
- return ecc->public_point().get_affine_y();
- else if(field == "base_x")
- return ecc->domain().get_base_point().get_affine_x();
- else if(field == "base_y")
- return ecc->domain().get_base_point().get_affine_y();
- else if(field == "p")
- return ecc->domain().get_curve().get_p();
- else if(field == "a")
- return ecc->domain().get_curve().get_a();
- else if(field == "b")
- return ecc->domain().get_curve().get_b();
- else if(field == "cofactor")
- return ecc->domain().get_cofactor();
- else if(field == "order")
- return ecc->domain().get_order();
- else
- throw Botan::Exception("Field not supported");
- }
-#endif
-
- // Some other algorithm type not supported by this function
- throw Botan::Exception("Unsupported algorithm type for botan_pubkey_get_field");
- }
-
-Botan::BigInt privkey_get_field(const Botan::Private_Key& key,
- const std::string& field)
- {
- //return key.get_integer_field(field);
-
-#if defined(BOTAN_HAS_RSA)
-
- if(const Botan::RSA_PrivateKey* rsa = dynamic_cast<const Botan::RSA_PrivateKey*>(&key))
- {
- if(field == "p")
- return rsa->get_p();
- else if(field == "q")
- return rsa->get_q();
- else if(field == "d")
- return rsa->get_d();
- else if(field == "c")
- return rsa->get_c();
- else if(field == "d1")
- return rsa->get_d1();
- else if(field == "d2")
- return rsa->get_d2();
- else
- return pubkey_get_field(key, field);
- }
-#endif
-
-#if defined(BOTAN_HAS_DL_PUBLIC_KEY_FAMILY)
- // Handles DSA, ElGamal, etc
- if(const Botan::DL_Scheme_PrivateKey* dl = dynamic_cast<const Botan::DL_Scheme_PrivateKey*>(&key))
- {
- if(field == "x")
- return dl->get_x();
- else
- return pubkey_get_field(key, field);
- }
-#endif
-
-#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO)
- if(const Botan::EC_PrivateKey* ecc = dynamic_cast<const Botan::EC_PrivateKey*>(&key))
- {
- if(field == "x")
- return ecc->private_value();
- else
- return pubkey_get_field(key, field);
- }
-#endif
-
- // Some other algorithm type not supported by this function
- throw Botan::Exception("Unsupported algorithm type for botan_privkey_get_field");
- }
-
-#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO)
-
-// These are always called within an existing try/catch block
-
-template<class ECPrivateKey_t>
-int privkey_load_ec(std::unique_ptr<ECPrivateKey_t>& key,
- const Botan::BigInt& scalar,
- const char* curve_name)
- {
- if(curve_name == nullptr)
- return BOTAN_FFI_ERROR_NULL_POINTER;
-
- Botan::Null_RNG null_rng;
- Botan::EC_Group grp(curve_name);
- key.reset(new ECPrivateKey_t(null_rng, grp, scalar));
- return BOTAN_FFI_SUCCESS;
- }
-
-template<class ECPublicKey_t>
-int pubkey_load_ec(std::unique_ptr<ECPublicKey_t>& key,
- const Botan::BigInt& public_x,
- const Botan::BigInt& public_y,
- const char* curve_name)
- {
- if(curve_name == nullptr)
- return BOTAN_FFI_ERROR_NULL_POINTER;
-
- Botan::Null_RNG null_rng;
- Botan::EC_Group grp(curve_name);
- Botan::PointGFp uncompressed_point(grp.get_curve(), public_x, public_y);
- key.reset(new ECPublicKey_t(grp, uncompressed_point));
- return BOTAN_FFI_SUCCESS;
- }
-
-#endif
-
-} // closes anonymous namespace
+}
extern "C" {
-#define BOTAN_FFI_DECLARE_STRUCT(NAME, TYPE, MAGIC) \
- struct NAME : public botan_struct<TYPE, MAGIC> { explicit NAME(TYPE* x) : botan_struct(x) {} }
-
-struct botan_cipher_struct : public botan_struct<Botan::Cipher_Mode, 0xB4A2BF9C>
- {
- explicit botan_cipher_struct(Botan::Cipher_Mode* x) : botan_struct(x) {}
- Botan::secure_vector<uint8_t> m_buf;
- };
-
-BOTAN_FFI_DECLARE_STRUCT(botan_rng_struct, Botan::RandomNumberGenerator, 0x4901F9C1);
-BOTAN_FFI_DECLARE_STRUCT(botan_mp_struct, Botan::BigInt, 0xC828B9D2);
-BOTAN_FFI_DECLARE_STRUCT(botan_block_cipher_struct, Botan::BlockCipher, 0x64C29716);
-BOTAN_FFI_DECLARE_STRUCT(botan_hash_struct, Botan::HashFunction, 0x1F0A4F84);
-BOTAN_FFI_DECLARE_STRUCT(botan_mac_struct, Botan::MessageAuthenticationCode, 0xA06E8FC1);
-BOTAN_FFI_DECLARE_STRUCT(botan_pubkey_struct, Botan::Public_Key, 0x2C286519);
-BOTAN_FFI_DECLARE_STRUCT(botan_privkey_struct, Botan::Private_Key, 0x7F96385E);
-BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_encrypt_struct, Botan::PK_Encryptor, 0x891F3FC3);
-BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_decrypt_struct, Botan::PK_Decryptor, 0x912F3C37);
-BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_sign_struct, Botan::PK_Signer, 0x1AF0C39F);
-BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_verify_struct, Botan::PK_Verifier, 0x2B91F936);
-BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_ka_struct, Botan::PK_Key_Agreement, 0x2939CAB1);
-
-BOTAN_FFI_DECLARE_STRUCT(botan_x509_cert_struct, Botan::X509_Certificate, 0x8F628937);
-
-
-#if defined(BOTAN_HAS_TLS)
-BOTAN_FFI_DECLARE_STRUCT(botan_tls_channel_struct, Botan::TLS::Channel, 0x0212FE99);
-#endif
+using namespace Botan_FFI;
/*
* Versioning
@@ -508,1866 +74,5 @@ int botan_hex_encode(const uint8_t* in, size_t len, char* out, uint32_t flags)
});
}
-int botan_rng_init(botan_rng_t* rng_out, const char* rng_type)
- {
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- BOTAN_ASSERT_ARG_NON_NULL(rng_out);
-
- const std::string rng_type_s(rng_type ? rng_type : "system");
-
- std::unique_ptr<Botan::RandomNumberGenerator> rng;
-
- if(rng_type_s == "system")
- rng.reset(new Botan::System_RNG);
- else if(rng_type_s == "user")
- rng.reset(new Botan::AutoSeeded_RNG);
- else
- return BOTAN_FFI_ERROR_BAD_PARAMETER;
-
- *rng_out = new botan_rng_struct(rng.release());
- return BOTAN_FFI_SUCCESS;
- });
- }
-
-int botan_rng_destroy(botan_rng_t rng)
- {
- return BOTAN_FFI_CHECKED_DELETE(rng);
- }
-
-int botan_rng_get(botan_rng_t rng, uint8_t* out, size_t out_len)
- {
- return BOTAN_FFI_DO(Botan::RandomNumberGenerator, rng, r, { r.randomize(out, out_len); });
- }
-
-int botan_rng_reseed(botan_rng_t rng, size_t bits)
- {
- return BOTAN_FFI_DO(Botan::RandomNumberGenerator, rng, r, { r.reseed_from_rng(Botan::system_rng(), bits); });
- }
-
-int botan_mp_init(botan_mp_t* mp_out)
- {
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- BOTAN_ASSERT_ARG_NON_NULL(mp_out);
-
- *mp_out = new botan_mp_struct(new Botan::BigInt);
- return BOTAN_FFI_SUCCESS;
- });
- }
-
-int botan_mp_clear(botan_mp_t mp)
- {
- return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { bn.clear(); });
- }
-
-int botan_mp_set_from_int(botan_mp_t mp, int initial_value)
- {
- return BOTAN_FFI_DO(Botan::BigInt, mp, bn, {
- if(initial_value >= 0)
- {
- bn = Botan::BigInt(static_cast<uint64_t>(initial_value));
- }
- else
- {
- bn = Botan::BigInt(static_cast<uint64_t>(-initial_value));
- bn.flip_sign();
- }
- });
- }
-
-int botan_mp_set_from_str(botan_mp_t mp, const char* str)
- {
- return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { bn = Botan::BigInt(str); });
- }
-
-int botan_mp_set_from_radix_str(botan_mp_t mp, const char* str, size_t radix)
- {
- return BOTAN_FFI_DO(Botan::BigInt, mp, bn, {
- Botan::BigInt::Base base;
- if(radix == 10)
- base = Botan::BigInt::Decimal;
- else if(radix == 16)
- base = Botan::BigInt::Hexadecimal;
- else
- return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
-
- const uint8_t* bytes = reinterpret_cast<const uint8_t*>(str);
- const size_t len = strlen(str);
-
- bn = Botan::BigInt::decode(bytes, len, base);
- });
- }
-
-int botan_mp_set_from_mp(botan_mp_t dest, const botan_mp_t source)
- {
- return BOTAN_FFI_DO(Botan::BigInt, dest, bn, { bn = safe_get(source); });
- }
-
-int botan_mp_is_negative(const botan_mp_t mp)
- {
- return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { return bn.is_negative() ? 1 : 0; });
- }
-
-int botan_mp_is_positive(const botan_mp_t mp)
- {
- return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { return bn.is_positive() ? 1 : 0; });
- }
-
-int botan_mp_flip_sign(botan_mp_t mp)
- {
- return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { bn.flip_sign(); });
- }
-
-int botan_mp_from_bin(botan_mp_t mp, const uint8_t bin[], size_t bin_len)
- {
- return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { bn.binary_decode(bin, bin_len); });
- }
-
-int botan_mp_to_hex(const botan_mp_t mp, char* out)
- {
- return BOTAN_FFI_DO(Botan::BigInt, mp, bn, {
- std::vector<uint8_t> hex = Botan::BigInt::encode(bn, Botan::BigInt::Hexadecimal);
- std::memcpy(out, hex.data(), hex.size());
- out[hex.size()] = 0; // null terminate
- });
- }
-
-int botan_mp_to_str(const botan_mp_t mp, uint8_t digit_base, char* out, size_t* out_len)
- {
- return BOTAN_FFI_DO(Botan::BigInt, mp, bn, {
- Botan::BigInt::Base base;
- if(digit_base == 0 || digit_base == 10)
- base = Botan::BigInt::Decimal;
- else if(digit_base == 16)
- base = Botan::BigInt::Hexadecimal;
- else
- throw FFI_Error("botan_mp_to_str invalid digit base");
-
- std::vector<uint8_t> hex = Botan::BigInt::encode(bn, base);
- hex.push_back(0); // null terminator
- return write_str_output(out, out_len, hex);
- });
- }
-
-int botan_mp_to_bin(const botan_mp_t mp, uint8_t vec[])
- {
- return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { bn.binary_encode(vec); });
- }
-
-int botan_mp_to_uint32(const botan_mp_t mp, uint32_t* val)
- {
- if(val == nullptr) {
- return BOTAN_FFI_ERROR_NULL_POINTER;
- }
- return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { *val = bn.to_u32bit(); });
- }
-
-int botan_mp_destroy(botan_mp_t mp)
- {
- return BOTAN_FFI_CHECKED_DELETE(mp);
- }
-
-int botan_mp_add(botan_mp_t result, const botan_mp_t x, const botan_mp_t y)
- {
- return BOTAN_FFI_DO(Botan::BigInt, result, res, { res = safe_get(x) + safe_get(y); });
- }
-
-int botan_mp_sub(botan_mp_t result, const botan_mp_t x, const botan_mp_t y)
- {
- return BOTAN_FFI_DO(Botan::BigInt, result, res, { res = safe_get(x) - safe_get(y); });
- }
-
-int botan_mp_mul(botan_mp_t result, const botan_mp_t x, const botan_mp_t y)
- {
- return BOTAN_FFI_DO(Botan::BigInt, result, res, { res = safe_get(x) * safe_get(y); });
- }
-
-int botan_mp_div(botan_mp_t quotient,
- botan_mp_t remainder,
- const botan_mp_t x, const botan_mp_t y)
- {
- return BOTAN_FFI_DO(Botan::BigInt, quotient, q, {
- Botan::BigInt r;
- Botan::divide(safe_get(x), safe_get(y), q, r);
- safe_get(remainder) = r;
- });
- }
-
-int botan_mp_equal(const botan_mp_t x_w, const botan_mp_t y_w)
- {
- return BOTAN_FFI_DO(Botan::BigInt, x_w, x, { return x == safe_get(y_w); });
- }
-
-int botan_mp_is_zero(const botan_mp_t mp)
- {
- return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { return bn.is_zero(); });
- }
-
-int botan_mp_is_odd(const botan_mp_t mp)
- {
- return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { return bn.is_odd(); });
- }
-
-int botan_mp_is_even(const botan_mp_t mp)
- {
- return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { return bn.is_even(); });
- }
-
-int botan_mp_cmp(int* result, const botan_mp_t x_w, const botan_mp_t y_w)
- {
- return BOTAN_FFI_DO(Botan::BigInt, x_w, x, { *result = x.cmp(safe_get(y_w)); });
- }
-
-int botan_mp_swap(botan_mp_t x_w, botan_mp_t y_w)
- {
- return BOTAN_FFI_DO(Botan::BigInt, x_w, x, { x.swap(safe_get(y_w)); });
- }
-
-// Return (base^exponent) % modulus
-int botan_mp_powmod(botan_mp_t out, const botan_mp_t base, const botan_mp_t exponent, const botan_mp_t modulus)
- {
- return BOTAN_FFI_DO(Botan::BigInt, out, o,
- { o = Botan::power_mod(safe_get(base), safe_get(exponent), safe_get(modulus)); });
- }
-
-int botan_mp_lshift(botan_mp_t out, const botan_mp_t in, size_t shift)
- {
- return BOTAN_FFI_DO(Botan::BigInt, out, o, { o = safe_get(in) << shift; });
- }
-
-int botan_mp_rshift(botan_mp_t out, const botan_mp_t in, size_t shift)
- {
- return BOTAN_FFI_DO(Botan::BigInt, out, o, { o = safe_get(in) >> shift; });
- }
-
-int botan_mp_mod_inverse(botan_mp_t out, const botan_mp_t in, const botan_mp_t modulus)
- {
- return BOTAN_FFI_DO(Botan::BigInt, out, o, { o = Botan::inverse_mod(safe_get(in), safe_get(modulus)); });
- }
-
-int botan_mp_mod_mul(botan_mp_t out, const botan_mp_t x, const botan_mp_t y, const botan_mp_t modulus)
- {
- return BOTAN_FFI_DO(Botan::BigInt, out, o, {
- Botan::Modular_Reducer reducer(safe_get(modulus));
- o = reducer.multiply(safe_get(x), safe_get(y));
- });
- }
-
-int botan_mp_rand_bits(botan_mp_t rand_out, botan_rng_t rng, size_t bits)
- {
- return BOTAN_FFI_DO(Botan::RandomNumberGenerator, rng, r, {
- safe_get(rand_out).randomize(r, bits); });
- }
-
-int botan_mp_rand_range(botan_mp_t rand_out,
- botan_rng_t rng,
- const botan_mp_t lower,
- const botan_mp_t upper)
- {
- return BOTAN_FFI_DO(Botan::RandomNumberGenerator, rng, r, {
- safe_get(rand_out) = Botan::BigInt::random_integer(r, safe_get(lower), safe_get(upper)); });
- }
-
-int botan_mp_gcd(botan_mp_t out, const botan_mp_t x, const botan_mp_t y)
- {
- return BOTAN_FFI_DO(Botan::BigInt, out, o, {
- o = Botan::gcd(safe_get(x), safe_get(y)); });
- }
-
-int botan_mp_is_prime(const botan_mp_t mp, botan_rng_t rng, size_t test_prob)
- {
- return BOTAN_FFI_DO(Botan::BigInt, mp, n,
- { return (Botan::is_prime(n, safe_get(rng), test_prob)) ? 1 : 0; });
- }
-
-int botan_mp_get_bit(const botan_mp_t mp, size_t bit)
- {
- return BOTAN_FFI_DO(Botan::BigInt, mp, n, { return (n.get_bit(bit)); });
- }
-
-int botan_mp_set_bit(botan_mp_t mp, size_t bit)
- {
- return BOTAN_FFI_DO(Botan::BigInt, mp, n, { n.set_bit(bit); });
- }
-
-int botan_mp_clear_bit(botan_mp_t mp, size_t bit)
- {
- return BOTAN_FFI_DO(Botan::BigInt, mp, n, { n.clear_bit(bit); });
- }
-
-int botan_mp_num_bits(const botan_mp_t mp, size_t* bits)
- {
- return BOTAN_FFI_DO(Botan::BigInt, mp, n, { *bits = n.bits(); });
- }
-
-int botan_mp_num_bytes(const botan_mp_t mp, size_t* bytes)
- {
- return BOTAN_FFI_DO(Botan::BigInt, mp, n, { *bytes = n.bytes(); });
- }
-
-int botan_block_cipher_init(botan_block_cipher_t* bc, const char* bc_name)
- {
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- if(bc == nullptr || bc_name == nullptr || *bc_name == 0)
- return BOTAN_FFI_ERROR_NULL_POINTER;
-
- *bc = nullptr;
-
- std::unique_ptr<Botan::BlockCipher> cipher(Botan::BlockCipher::create(bc_name));
- if(cipher == nullptr)
- return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
-
- *bc = new botan_block_cipher_struct(cipher.release());
- return BOTAN_FFI_SUCCESS;
- });
- }
-
-/**
-* Destroy a block cipher object
-*/
-int botan_block_cipher_destroy(botan_block_cipher_t bc)
- {
- return BOTAN_FFI_CHECKED_DELETE(bc);
- }
-
-int botan_block_cipher_clear(botan_block_cipher_t bc)
- {
- return BOTAN_FFI_DO(Botan::BlockCipher, bc, b, { b.clear(); });
- }
-
-/**
-* Set the key for a block cipher instance
-*/
-int botan_block_cipher_set_key(botan_block_cipher_t bc,
- const uint8_t key[], size_t len)
- {
- return BOTAN_FFI_DO(Botan::BlockCipher, bc, b, { b.set_key(key, len); });
- }
-
-/**
-* Return the positive block size of this block cipher, or negative to
-* indicate an error
-*/
-int botan_block_cipher_block_size(botan_block_cipher_t bc)
- {
- return BOTAN_FFI_DO(Botan::BlockCipher, bc, b, { return b.block_size(); });
- }
-
-int botan_block_cipher_encrypt_blocks(botan_block_cipher_t bc,
- const uint8_t in[],
- uint8_t out[],
- size_t blocks)
- {
- return BOTAN_FFI_DO(Botan::BlockCipher, bc, b, { b.encrypt_n(in, out, blocks); });
- }
-
-int botan_block_cipher_decrypt_blocks(botan_block_cipher_t bc,
- const uint8_t in[],
- uint8_t out[],
- size_t blocks)
- {
- return BOTAN_FFI_DO(Botan::BlockCipher, bc, b, { b.decrypt_n(in, out, blocks); });
- }
-
-int botan_hash_init(botan_hash_t* hash, const char* hash_name, uint32_t flags)
- {
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- if(hash == nullptr || hash_name == nullptr || *hash_name == 0)
- return BOTAN_FFI_ERROR_NULL_POINTER;
- if(flags != 0)
- return BOTAN_FFI_ERROR_BAD_FLAG;
-
- std::unique_ptr<Botan::HashFunction> h = Botan::HashFunction::create(hash_name);
- if(h == nullptr)
- return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
-
- *hash = new botan_hash_struct(h.release());
- return BOTAN_FFI_SUCCESS;
- });
- }
-
-int botan_hash_destroy(botan_hash_t hash)
- {
- return BOTAN_FFI_CHECKED_DELETE(hash);
- }
-
-int botan_hash_output_length(botan_hash_t hash, size_t* out)
- {
- return BOTAN_FFI_DO(Botan::HashFunction, hash, h, { *out = h.output_length(); });
- }
-
-int botan_hash_block_size(botan_hash_t hash, size_t* out)
- {
- return BOTAN_FFI_DO(Botan::HashFunction, hash, h, { *out = h.hash_block_size(); });
- }
-
-int botan_hash_clear(botan_hash_t hash)
- {
- return BOTAN_FFI_DO(Botan::HashFunction, hash, h, { h.clear(); });
- }
-
-int botan_hash_update(botan_hash_t hash, const uint8_t* buf, size_t len)
- {
- return BOTAN_FFI_DO(Botan::HashFunction, hash, h, { h.update(buf, len); });
- }
-
-int botan_hash_final(botan_hash_t hash, uint8_t out[])
- {
- return BOTAN_FFI_DO(Botan::HashFunction, hash, h, { h.final(out); });
- }
-
-int botan_hash_copy_state(botan_hash_t* dest, const botan_hash_t source)
- {
- return BOTAN_FFI_DO(Botan::HashFunction, source, src, {
- *dest = new botan_hash_struct(src.copy_state().release()); });
- }
-
-int botan_mac_init(botan_mac_t* mac, const char* mac_name, uint32_t flags)
- {
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- if(!mac || !mac_name || flags != 0)
- return BOTAN_FFI_ERROR_NULL_POINTER;
-
- std::unique_ptr<Botan::MessageAuthenticationCode> m =
- Botan::MessageAuthenticationCode::create(mac_name);
-
- if(m == nullptr)
- return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
-
- *mac = new botan_mac_struct(m.release());
- return BOTAN_FFI_SUCCESS;
- });
- }
-
-int botan_mac_destroy(botan_mac_t mac)
- {
- return BOTAN_FFI_CHECKED_DELETE(mac);
- }
-
-int botan_mac_set_key(botan_mac_t mac, const uint8_t* key, size_t key_len)
- {
- return BOTAN_FFI_DO(Botan::MessageAuthenticationCode, mac, m, { m.set_key(key, key_len); });
- }
-
-int botan_mac_output_length(botan_mac_t mac, size_t* out)
- {
- return BOTAN_FFI_DO(Botan::MessageAuthenticationCode, mac, m, { *out = m.output_length(); });
- }
-
-int botan_mac_clear(botan_mac_t mac)
- {
- return BOTAN_FFI_DO(Botan::MessageAuthenticationCode, mac, m, { m.clear(); });
- }
-
-int botan_mac_update(botan_mac_t mac, const uint8_t* buf, size_t len)
- {
- return BOTAN_FFI_DO(Botan::MessageAuthenticationCode, mac, m, { m.update(buf, len); });
- }
-
-int botan_mac_final(botan_mac_t mac, uint8_t out[])
- {
- return BOTAN_FFI_DO(Botan::MessageAuthenticationCode, mac, m, { m.final(out); });
- }
-
-int botan_cipher_init(botan_cipher_t* cipher, const char* cipher_name, uint32_t flags)
- {
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- const bool encrypt_p = ((flags & BOTAN_CIPHER_INIT_FLAG_MASK_DIRECTION) == BOTAN_CIPHER_INIT_FLAG_ENCRYPT);
- const Botan::Cipher_Dir dir = encrypt_p ? Botan::ENCRYPTION : Botan::DECRYPTION;
- std::unique_ptr<Botan::Cipher_Mode> mode(Botan::get_cipher_mode(cipher_name, dir));
- if(!mode)
- return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
- *cipher = new botan_cipher_struct(mode.release());
- return BOTAN_FFI_SUCCESS;
- });
- }
-
-int botan_cipher_destroy(botan_cipher_t cipher)
- {
- return BOTAN_FFI_CHECKED_DELETE(cipher);
- }
-
-int botan_cipher_clear(botan_cipher_t cipher)
- {
- return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { c.clear(); });
- }
-
-int botan_cipher_query_keylen(botan_cipher_t cipher,
- size_t* out_minimum_keylength,
- size_t* out_maximum_keylength)
- {
- return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, {
- *out_minimum_keylength = c.key_spec().minimum_keylength();
- *out_maximum_keylength = c.key_spec().maximum_keylength();
- });
- }
-
-int botan_cipher_set_key(botan_cipher_t cipher,
- const uint8_t* key, size_t key_len)
- {
- return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { c.set_key(key, key_len); });
- }
-
-int botan_cipher_start(botan_cipher_t cipher_obj,
- const uint8_t* nonce, size_t nonce_len)
- {
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- Botan::Cipher_Mode& cipher = safe_get(cipher_obj);
- cipher.start(nonce, nonce_len);
- cipher_obj->m_buf.reserve(cipher.update_granularity());
- return BOTAN_FFI_SUCCESS;
- });
- }
-
-int botan_cipher_update(botan_cipher_t cipher_obj,
- uint32_t flags,
- uint8_t output_ptr[],
- size_t orig_output_size,
- size_t* output_written,
- const uint8_t input_ptr[],
- size_t orig_input_size,
- size_t* input_consumed)
- {
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
-
- size_t input_size = orig_input_size;
- size_t output_size = orig_output_size;
- const uint8_t* input = input_ptr;
- uint8_t* output = output_ptr;
-
- using namespace Botan;
- Cipher_Mode& cipher = safe_get(cipher_obj);
- secure_vector<uint8_t>& mbuf = cipher_obj->m_buf;
-
- const bool final_input = (flags & BOTAN_CIPHER_UPDATE_FLAG_FINAL);
-
- if(final_input)
- {
- mbuf.assign(input, input + input_size);
- *input_consumed = input_size;
- *output_written = 0;
-
- try
- {
- cipher.finish(mbuf);
- }
- catch(Integrity_Failure& e)
- {
- return BOTAN_FFI_ERROR_BAD_MAC;
- }
-
- *output_written = mbuf.size();
-
- if(mbuf.size() <= output_size)
- {
- copy_mem(output, mbuf.data(), mbuf.size());
- mbuf.clear();
- return BOTAN_FFI_SUCCESS;
- }
-
- return -1;
- }
-
- if(input_size == 0)
- {
- // Currently must take entire buffer in this case
- *output_written = mbuf.size();
- if(output_size >= mbuf.size())
- {
- copy_mem(output, mbuf.data(), mbuf.size());
- mbuf.clear();
- return BOTAN_FFI_SUCCESS;
- }
-
- return -1;
- }
-
- const size_t ud = cipher.update_granularity();
- BOTAN_ASSERT(cipher.update_granularity() > cipher.minimum_final_size(), "logic error");
-
- mbuf.resize(ud);
- size_t taken = 0, written = 0;
-
- while(input_size >= ud && output_size >= ud)
- {
- copy_mem(mbuf.data(), input, ud);
- cipher.update(mbuf);
-
- input_size -= ud;
- copy_mem(output, mbuf.data(), ud);
- input += ud;
- taken += ud;
-
- output_size -= ud;
- output += ud;
- written += ud;
- }
-
- *output_written = written;
- *input_consumed = taken;
-
- return BOTAN_FFI_SUCCESS;
- });
- }
-
-int botan_cipher_set_associated_data(botan_cipher_t cipher,
- const uint8_t* ad,
- size_t ad_len)
- {
- return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, {
- if(Botan::AEAD_Mode* aead = dynamic_cast<Botan::AEAD_Mode*>(&c))
- {
- aead->set_associated_data(ad, ad_len);
- return BOTAN_FFI_SUCCESS;
- }
- return BOTAN_FFI_ERROR_BAD_PARAMETER;
- });
- }
-
-int botan_cipher_valid_nonce_length(botan_cipher_t cipher, size_t nl)
- {
- return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { return c.valid_nonce_length(nl) ? 1 : 0; });
- }
-
-int botan_cipher_get_default_nonce_length(botan_cipher_t cipher, size_t* nl)
- {
- return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { *nl = c.default_nonce_length(); });
- }
-
-int botan_cipher_get_update_granularity(botan_cipher_t cipher, size_t* ug)
- {
- return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { *ug = c.update_granularity(); });
- }
-
-int botan_cipher_get_tag_length(botan_cipher_t cipher, size_t* tl)
- {
- return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { *tl = c.tag_size(); });
- }
-
-int botan_pbkdf(const char* pbkdf_algo, uint8_t out[], size_t out_len,
- const char* pass, const uint8_t salt[], size_t salt_len,
- size_t iterations)
- {
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- std::unique_ptr<Botan::PBKDF> pbkdf(Botan::get_pbkdf(pbkdf_algo));
- pbkdf->pbkdf_iterations(out, out_len, pass, salt, salt_len, iterations);
- return BOTAN_FFI_SUCCESS;
- });
- }
-
-int botan_pbkdf_timed(const char* pbkdf_algo,
- uint8_t out[], size_t out_len,
- const char* password,
- const uint8_t salt[], size_t salt_len,
- size_t ms_to_run,
- size_t* iterations_used)
- {
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- std::unique_ptr<Botan::PBKDF> pbkdf(Botan::get_pbkdf(pbkdf_algo));
- pbkdf->pbkdf_timed(out, out_len, password, salt, salt_len,
- std::chrono::milliseconds(ms_to_run),
- *iterations_used);
- return BOTAN_FFI_SUCCESS;
- });
- }
-
-int botan_kdf(const char* kdf_algo,
- uint8_t out[], size_t out_len,
- const uint8_t secret[], size_t secret_len,
- const uint8_t salt[], size_t salt_len,
- const uint8_t label[], size_t label_len)
- {
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- std::unique_ptr<Botan::KDF> kdf(Botan::get_kdf(kdf_algo));
- kdf->kdf(out, out_len, secret, secret_len, salt, salt_len, label, label_len);
- return BOTAN_FFI_SUCCESS;
- });
- }
-
-int botan_bcrypt_generate(uint8_t* out, size_t* out_len,
- const char* pass,
- botan_rng_t rng_obj, size_t wf,
- uint32_t flags)
- {
-#if defined(BOTAN_HAS_BCRYPT)
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- BOTAN_ASSERT_ARG_NON_NULL(out);
- BOTAN_ASSERT_ARG_NON_NULL(out_len);
- BOTAN_ASSERT_ARG_NON_NULL(pass);
-
- if(flags != 0)
- return BOTAN_FFI_ERROR_BAD_FLAG;
-
- if(wf < 2 || wf > 30)
- throw FFI_Error("Bad bcrypt work factor " + std::to_string(wf));
-
- Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
- const std::string bcrypt = Botan::generate_bcrypt(pass, rng, wf);
- return write_str_output(out, out_len, bcrypt);
- });
-#else
- return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
-#endif
- }
-
-int botan_bcrypt_is_valid(const char* pass, const char* hash)
- {
-#if defined(BOTAN_HAS_BCRYPT)
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- return Botan::check_bcrypt(pass, hash) ? 0 : 1;
- });
-#else
- return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
-#endif
- }
-
-int botan_privkey_create(botan_privkey_t* key_obj,
- const char* algo_name,
- const char* algo_params,
- botan_rng_t rng_obj)
- {
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- if(key_obj == nullptr)
- return BOTAN_FFI_ERROR_NULL_POINTER;
-
- *key_obj = nullptr;
- if(rng_obj == nullptr)
- return BOTAN_FFI_ERROR_NULL_POINTER;
-
- Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
- std::unique_ptr<Botan::Private_Key> key(
- Botan::create_private_key(algo_name ? algo_name : "RSA",
- rng,
- algo_params ? algo_params : ""));
-
- if(key)
- {
- *key_obj = new botan_privkey_struct(key.release());
- return BOTAN_FFI_SUCCESS;
- }
- else
- {
- return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
- }
- });
- }
-
-int botan_privkey_create_rsa(botan_privkey_t* key_obj, botan_rng_t rng_obj, size_t n_bits)
- {
-#if defined(BOTAN_HAS_RSA)
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- if(key_obj == nullptr || rng_obj == nullptr)
- return BOTAN_FFI_ERROR_NULL_POINTER;
- if(n_bits < 1024 || n_bits > 16*1024)
- return BOTAN_FFI_ERROR_BAD_PARAMETER;
-
- *key_obj = nullptr;
-
- Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
- std::unique_ptr<Botan::Private_Key> key(new Botan::RSA_PrivateKey(rng, n_bits));
- *key_obj = new botan_privkey_struct(key.release());
- return BOTAN_FFI_SUCCESS;
- });
-#else
- return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
-#endif
- }
-
-int botan_privkey_create_ecdsa(botan_privkey_t* key_obj, botan_rng_t rng_obj, const char* param_str)
- {
-#if defined(BOTAN_HAS_ECDSA)
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- if(key_obj == nullptr || rng_obj == nullptr || param_str == nullptr || *param_str == 0)
- return BOTAN_FFI_ERROR_NULL_POINTER;
-
- *key_obj = nullptr;
-
- Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
- Botan::EC_Group grp(param_str);
- std::unique_ptr<Botan::Private_Key> key(new Botan::ECDSA_PrivateKey(rng, grp));
- *key_obj = new botan_privkey_struct(key.release());
- return BOTAN_FFI_SUCCESS;
- });
-#else
- 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)
- {
-#if defined(BOTAN_HAS_MCELIECE)
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- if(key_obj == nullptr || rng_obj == nullptr || n == 0 || t == 0)
- return BOTAN_FFI_ERROR_NULL_POINTER;
-
- *key_obj = nullptr;
-
- Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
- std::unique_ptr<Botan::Private_Key> key(new Botan::McEliece_PrivateKey(rng, n, t));
- *key_obj = new botan_privkey_struct(key.release());
- return BOTAN_FFI_SUCCESS;
- });
-#else
- return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
-#endif
- }
-
-int botan_privkey_create_ecdh(botan_privkey_t* key_obj, botan_rng_t rng_obj, const char* param_str)
- {
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- if(key_obj == nullptr || rng_obj == nullptr || param_str == nullptr || *param_str == 0)
- return BOTAN_FFI_ERROR_NULL_POINTER;
-
- *key_obj = nullptr;
-
- const std::string params(param_str);
-
-#if defined(BOTAN_HAS_CURVE_25519)
- if(params == "curve25519")
- {
- std::unique_ptr<Botan::Private_Key> key(new Botan::Curve25519_PrivateKey(safe_get(rng_obj)));
- *key_obj = new botan_privkey_struct(key.release());
- return BOTAN_FFI_SUCCESS;
- }
-#endif
-
-#if defined(BOTAN_HAS_ECDH)
- Botan::EC_Group grp(params);
- std::unique_ptr<Botan::Private_Key> key(new Botan::ECDH_PrivateKey(safe_get(rng_obj), grp));
- *key_obj = new botan_privkey_struct(key.release());
- return BOTAN_FFI_SUCCESS;
-#endif
-
- return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
- });
- }
-
-int botan_privkey_load(botan_privkey_t* key, botan_rng_t rng_obj,
- const uint8_t bits[], size_t len,
- const char* password)
- {
- *key = nullptr;
-
- if(password == nullptr)
- password = "";
-
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- Botan::DataSource_Memory src(bits, len);
-
- Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
-
- std::unique_ptr<Botan::PKCS8_PrivateKey> pkcs8(
- Botan::PKCS8::load_key(src, rng, static_cast<std::string>(password)));
-
- if(pkcs8)
- {
- *key = new botan_privkey_struct(pkcs8.release());
- return BOTAN_FFI_SUCCESS;
- }
- return BOTAN_FFI_ERROR_UNKNOWN_ERROR;
- });
- }
-
-int botan_pubkey_load(botan_pubkey_t* key,
- const uint8_t bits[], size_t bits_len)
- {
- *key = nullptr;
-
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- Botan::DataSource_Memory src(bits, bits_len);
- std::unique_ptr<Botan::Public_Key> pubkey(Botan::X509::load_key(src));
-
- if(pubkey == nullptr)
- return BOTAN_FFI_ERROR_UNKNOWN_ERROR;
-
- *key = new botan_pubkey_struct(pubkey.release());
- return BOTAN_FFI_SUCCESS;
- });
- }
-
-int botan_privkey_load_rsa(botan_privkey_t* key,
- botan_mp_t rsa_p, botan_mp_t rsa_q, botan_mp_t rsa_e)
- {
-#if defined(BOTAN_HAS_RSA)
- *key = nullptr;
-
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- *key = new botan_privkey_struct(new Botan::RSA_PrivateKey(safe_get(rsa_p),
- safe_get(rsa_q),
- safe_get(rsa_e)));
- return BOTAN_FFI_SUCCESS;
- });
-#else
- BOTAN_UNUSED(key, rsa_p, rsa_q, rsa_e);
- return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
-#endif
- }
-
-int botan_pubkey_load_rsa(botan_pubkey_t* key,
- botan_mp_t n, botan_mp_t e)
- {
-#if defined(BOTAN_HAS_RSA)
- *key = nullptr;
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- *key = new botan_pubkey_struct(new Botan::RSA_PublicKey(safe_get(n), safe_get(e)));
- return BOTAN_FFI_SUCCESS;
- });
-#else
- BOTAN_UNUSED(key, n, e);
- return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
-#endif
- }
-
-int botan_privkey_load_dsa(botan_privkey_t* key,
- botan_mp_t p, botan_mp_t q, botan_mp_t g, botan_mp_t x)
- {
-#if defined(BOTAN_HAS_DSA)
- *key = nullptr;
-
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- Botan::Null_RNG null_rng;
- Botan::DL_Group group(safe_get(p), safe_get(q), safe_get(g));
- *key = new botan_privkey_struct(new Botan::DSA_PrivateKey(null_rng, group, safe_get(x)));
- return BOTAN_FFI_SUCCESS;
- });
-#else
- BOTAN_UNUSED(key, p, q, g, x);
- return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
-#endif
- }
-
-int botan_pubkey_load_dsa(botan_pubkey_t* key,
- botan_mp_t p, botan_mp_t q, botan_mp_t g, botan_mp_t y)
- {
-#if defined(BOTAN_HAS_DSA)
- *key = nullptr;
-
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- Botan::DL_Group group(safe_get(p), safe_get(q), safe_get(g));
- *key = new botan_pubkey_struct(new Botan::DSA_PublicKey(group, safe_get(y)));
- return BOTAN_FFI_SUCCESS;
- });
-#else
- BOTAN_UNUSED(key, p, q, g, y);
- return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
-#endif
- }
-
-int botan_pubkey_load_elgamal(botan_pubkey_t* key,
- botan_mp_t p, botan_mp_t g, botan_mp_t y)
- {
-#if defined(BOTAN_HAS_ELGAMAL)
- *key = nullptr;
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- Botan::DL_Group group(safe_get(p), safe_get(g));
- *key = new botan_pubkey_struct(new Botan::ElGamal_PublicKey(group, safe_get(y)));
- return BOTAN_FFI_SUCCESS;
- });
-#else
- BOTAN_UNUSED(key, p, g, y);
- return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
-#endif
- }
-
-int botan_privkey_load_elgamal(botan_privkey_t* key,
- botan_mp_t p, botan_mp_t g, botan_mp_t x)
- {
-#if defined(BOTAN_HAS_ELGAMAL)
- *key = nullptr;
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- Botan::Null_RNG null_rng;
- Botan::DL_Group group(safe_get(p), safe_get(g));
- *key = new botan_privkey_struct(new Botan::ElGamal_PrivateKey(null_rng, group, safe_get(x)));
- return BOTAN_FFI_SUCCESS;
- });
-#else
- BOTAN_UNUSED(key, p, g, x);
- return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
-#endif
- }
-
-int botan_privkey_load_ed25519(botan_privkey_t* key,
- const uint8_t privkey[32])
- {
-#if defined(BOTAN_HAS_ED25519)
- *key = nullptr;
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- const Botan::secure_vector<uint8_t> privkey_vec(privkey, privkey + 32);
- *key = new botan_privkey_struct(new Botan::Ed25519_PrivateKey(privkey_vec));
- return BOTAN_FFI_SUCCESS;
- });
-#else
- BOTAN_UNUSED(key, privkey);
- return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
-#endif
- }
-
-int botan_pubkey_load_ed25519(botan_pubkey_t* key,
- const uint8_t pubkey[32])
- {
-#if defined(BOTAN_HAS_ED25519)
- *key = nullptr;
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- const std::vector<uint8_t> pubkey_vec(pubkey, pubkey + 32);
- *key = new botan_pubkey_struct(new Botan::Ed25519_PublicKey(pubkey_vec));
- return BOTAN_FFI_SUCCESS;
- });
-#else
- BOTAN_UNUSED(key, pubkey);
- return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
-#endif
- }
-
-int botan_privkey_ed25519_get_privkey(botan_privkey_t key,
- uint8_t output[64])
- {
-#if defined(BOTAN_HAS_ED25519)
- return BOTAN_FFI_DO(Botan::Private_Key, key, k, {
- if(Botan::Ed25519_PrivateKey* ed = dynamic_cast<Botan::Ed25519_PrivateKey*>(&k))
- {
- const Botan::secure_vector<uint8_t>& key = ed->get_private_key();
- if(key.size() != 64)
- return BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE;
- Botan::copy_mem(output, key.data(), 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_ed25519_get_pubkey(botan_pubkey_t key,
- uint8_t output[32])
- {
-#if defined(BOTAN_HAS_ED25519)
- return BOTAN_FFI_DO(Botan::Public_Key, key, k, {
- if(Botan::Ed25519_PublicKey* ed = dynamic_cast<Botan::Ed25519_PublicKey*>(&k))
- {
- const std::vector<uint8_t>& key = ed->get_public_key();
- if(key.size() != 32)
- return BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE;
- Botan::copy_mem(output, key.data(), 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_load_ecdsa(botan_pubkey_t* key,
- const botan_mp_t public_x,
- const botan_mp_t public_y,
- const char* curve_name)
- {
-#if defined(BOTAN_HAS_ECDSA)
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- std::unique_ptr<Botan::ECDSA_PublicKey> p_key;
-
- int rc = pubkey_load_ec(p_key, safe_get(public_x), safe_get(public_y), curve_name);
- if(rc == BOTAN_FFI_SUCCESS)
- *key = new botan_pubkey_struct(p_key.release());
-
- return rc;
- });
-#else
- BOTAN_UNUSED(key, public_x, public_y, curve_name);
- return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
-#endif
- }
-
-int botan_pubkey_load_sm2(botan_pubkey_t* key,
- const botan_mp_t public_x,
- const botan_mp_t public_y,
- const char* curve_name)
- {
-#if defined(BOTAN_HAS_SM2)
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- std::unique_ptr<Botan::SM2_Signature_PublicKey> p_key;
- if(!pubkey_load_ec(p_key, safe_get(public_x), safe_get(public_y), curve_name))
- {
- *key = new botan_pubkey_struct(p_key.release());
- return BOTAN_FFI_SUCCESS;
- }
- return BOTAN_FFI_ERROR_UNKNOWN_ERROR;
- });
-#else
- BOTAN_UNUSED(key, public_x, public_y, curve_name);
- return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
-#endif
- }
-
-int botan_pubkey_load_ecdh(botan_pubkey_t* key,
- const botan_mp_t public_x,
- const botan_mp_t public_y,
- const char* curve_name)
- {
-#if defined(BOTAN_HAS_ECDH)
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- std::unique_ptr<Botan::ECDH_PublicKey> p_key;
- int rc = pubkey_load_ec(p_key, safe_get(public_x), safe_get(public_y), curve_name);
-
- if(rc == BOTAN_FFI_SUCCESS)
- *key = new botan_pubkey_struct(p_key.release());
- return rc;
- });
-#else
- BOTAN_UNUSED(key, public_x, public_y, curve_name);
- return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
-#endif
- }
-
-int botan_privkey_load_ecdsa(botan_privkey_t* key,
- const botan_mp_t scalar,
- const char* curve_name)
- {
-#if defined(BOTAN_HAS_ECDSA)
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- std::unique_ptr<Botan::ECDSA_PrivateKey> p_key;
- int rc = privkey_load_ec(p_key, safe_get(scalar), curve_name);
- if(rc == BOTAN_FFI_SUCCESS)
- *key = new botan_privkey_struct(p_key.release());
- return rc;
- });
-#else
- BOTAN_UNUSED(key, scalar, curve_name);
- return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
-#endif
- }
-
-int botan_privkey_load_sm2(botan_privkey_t* key,
- const botan_mp_t scalar,
- const char* curve_name)
- {
-#if defined(BOTAN_HAS_SM2)
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- std::unique_ptr<Botan::SM2_Signature_PrivateKey> p_key;
- int rc = privkey_load_ec(p_key, safe_get(scalar), curve_name);
-
- if(rc == BOTAN_FFI_SUCCESS)
- *key = new botan_privkey_struct(p_key.release());
- return rc;
- });
-#else
- BOTAN_UNUSED(key, scalar, curve_name);
- return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
-#endif
- }
-
-int botan_privkey_load_ecdh(botan_privkey_t* key,
- const botan_mp_t scalar,
- const char* curve_name)
- {
-#if defined(BOTAN_HAS_ECDH)
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- std::unique_ptr<Botan::ECDH_PrivateKey> p_key;
- int rc = privkey_load_ec(p_key, safe_get(scalar), curve_name);
- if(rc == BOTAN_FFI_SUCCESS)
- *key = new botan_privkey_struct(p_key.release());
- return rc;
- });
-#else
- BOTAN_UNUSED(key, scalar, curve_name);
- return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
-#endif
- }
-
-int botan_pubkey_get_field(botan_mp_t output,
- botan_pubkey_t key,
- const char* field_name_cstr)
- {
- if(field_name_cstr == nullptr)
- return BOTAN_FFI_ERROR_NULL_POINTER;
-
- const std::string field_name(field_name_cstr);
-
- return BOTAN_FFI_DO(Botan::Public_Key, key, k, {
- safe_get(output) = pubkey_get_field(k, field_name);
- });
- }
-
-int botan_privkey_get_field(botan_mp_t output,
- botan_privkey_t key,
- const char* field_name_cstr)
- {
- if(field_name_cstr == nullptr)
- return BOTAN_FFI_ERROR_NULL_POINTER;
-
- const std::string field_name(field_name_cstr);
-
- return BOTAN_FFI_DO(Botan::Private_Key, key, k, {
- safe_get(output) = privkey_get_field(k, field_name);
- });
- }
-
-int botan_privkey_rsa_get_p(botan_mp_t p, botan_privkey_t key)
- {
- return botan_privkey_get_field(p, key, "p");
- }
-
-int botan_privkey_rsa_get_q(botan_mp_t q, botan_privkey_t key)
- {
- return botan_privkey_get_field(q, key, "q");
- }
-
-int botan_privkey_rsa_get_n(botan_mp_t n, botan_privkey_t key)
- {
- return botan_privkey_get_field(n, key, "n");
- }
-
-int botan_privkey_rsa_get_e(botan_mp_t e, botan_privkey_t key)
- {
- return botan_privkey_get_field(e, key, "e");
- }
-
-int botan_privkey_rsa_get_d(botan_mp_t d, botan_privkey_t key)
- {
- return botan_privkey_get_field(d, key, "d");
- }
-
-int botan_pubkey_rsa_get_e(botan_mp_t e, botan_pubkey_t key)
- {
- return botan_pubkey_get_field(e, key, "e");
- }
-
-int botan_pubkey_rsa_get_n(botan_mp_t n, botan_pubkey_t key)
- {
- return botan_pubkey_get_field(n, key, "n");
- }
-
-int botan_privkey_dsa_get_x(botan_mp_t x, botan_privkey_t key)
- {
- return botan_privkey_get_field(x, key, "x");
- }
-
-int botan_pubkey_dsa_get_p(botan_mp_t p, botan_pubkey_t key)
- {
- return botan_pubkey_get_field(p, key, "p");
- }
-int botan_pubkey_dsa_get_q(botan_mp_t q, botan_pubkey_t key)
- {
- return botan_pubkey_get_field(q, key, "q");
- }
-int botan_pubkey_dsa_get_g(botan_mp_t g, botan_pubkey_t key)
- {
- return botan_pubkey_get_field(g, key, "g");
- }
-int botan_pubkey_dsa_get_y(botan_mp_t y, botan_pubkey_t key)
- {
- return botan_pubkey_get_field(y, key, "y");
- }
-
-int botan_privkey_destroy(botan_privkey_t key)
- {
- return BOTAN_FFI_CHECKED_DELETE(key);
- }
-
-int botan_pubkey_destroy(botan_pubkey_t key)
- {
- return BOTAN_FFI_CHECKED_DELETE(key);
- }
-
-int botan_privkey_export_pubkey(botan_pubkey_t* pubout, botan_privkey_t key_obj)
- {
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- std::unique_ptr<Botan::Public_Key>
- pubkey(Botan::X509::load_key(Botan::X509::BER_encode(safe_get(key_obj))));
-
- *pubout = new botan_pubkey_struct(pubkey.release());
- return BOTAN_FFI_SUCCESS;
- });
- }
-
-int botan_pubkey_algo_name(botan_pubkey_t key, char out[], size_t* out_len)
- {
- return BOTAN_FFI_DO(Botan::Public_Key, key, k, { return write_str_output(out, out_len, k.algo_name()); });
- }
-
-int botan_pubkey_check_key(botan_pubkey_t key, botan_rng_t rng, uint32_t flags)
- {
- const bool strong = (flags & BOTAN_CHECK_KEY_EXPENSIVE_TESTS);
-
- return BOTAN_FFI_DO(Botan::Public_Key, key, k,
- { return (k.check_key(safe_get(rng), strong) == true) ? 0 : -1; });
- }
-
-int botan_privkey_check_key(botan_privkey_t key, botan_rng_t rng, uint32_t flags)
- {
- const bool strong = (flags & BOTAN_CHECK_KEY_EXPENSIVE_TESTS);
- return BOTAN_FFI_DO(Botan::Private_Key, key, k,
- { return (k.check_key(safe_get(rng), strong) == true) ? 0 : -1; });
- }
-
-int botan_pubkey_export(botan_pubkey_t key, uint8_t out[], size_t* out_len, uint32_t flags)
- {
- return BOTAN_FFI_DO(Botan::Public_Key, key, k, {
- if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER)
- return write_vec_output(out, out_len, Botan::X509::BER_encode(k));
- else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM)
- return write_str_output(out, out_len, Botan::X509::PEM_encode(k));
- else
- return BOTAN_FFI_ERROR_BAD_FLAG;
- });
- }
-
-int botan_privkey_export(botan_privkey_t key, uint8_t out[], size_t* out_len, uint32_t flags)
- {
- return BOTAN_FFI_DO(Botan::Private_Key, key, k, {
- if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER)
- return write_vec_output(out, out_len, Botan::PKCS8::BER_encode(k));
- else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM)
- return write_str_output(out, out_len, Botan::PKCS8::PEM_encode(k));
- else
- return BOTAN_FFI_ERROR_BAD_FLAG;
- });
- }
-
-int botan_privkey_export_encrypted(botan_privkey_t key,
- uint8_t out[], size_t* out_len,
- botan_rng_t rng_obj,
- const char* pass,
- const char* /*ignored - pbe*/,
- uint32_t flags)
- {
- return botan_privkey_export_encrypted_pbkdf_iter(key, out, out_len, rng_obj, pass, 100000, nullptr, nullptr, flags);
- }
-
-int botan_privkey_export_encrypted_pbkdf_msec(botan_privkey_t key,
- uint8_t out[], size_t* out_len,
- botan_rng_t rng_obj,
- const char* pass,
- uint32_t pbkdf_msec,
- size_t* pbkdf_iters_out,
- const char* maybe_cipher,
- const char* maybe_pbkdf_hash,
- uint32_t flags)
- {
- return BOTAN_FFI_DO(Botan::Private_Key, key, k, {
- const std::chrono::milliseconds pbkdf_time(pbkdf_msec);
- Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
-
- std::string cipher;
- if(maybe_cipher)
- {
- cipher = maybe_cipher;
- }
-
- std::string pbkdf_hash;
- if(maybe_pbkdf_hash)
- {
- pbkdf_hash = maybe_pbkdf_hash;
- }
-
- if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER)
- {
- return write_vec_output(out, out_len,
- Botan::PKCS8::BER_encode_encrypted_pbkdf_msec(k, rng, pass, pbkdf_time, pbkdf_iters_out, cipher, pbkdf_hash));
- }
- else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM)
- {
- return write_str_output(out, out_len,
- Botan::PKCS8::PEM_encode_encrypted_pbkdf_msec(k, rng, pass, pbkdf_time, pbkdf_iters_out, cipher, pbkdf_hash));
- }
- else
- {
- return -2;
- }
- });
- }
-
-int botan_privkey_export_encrypted_pbkdf_iter(botan_privkey_t key,
- uint8_t out[], size_t* out_len,
- botan_rng_t rng_obj,
- const char* pass,
- size_t pbkdf_iter,
- const char* maybe_cipher,
- const char* maybe_pbkdf_hash,
- uint32_t flags)
- {
- return BOTAN_FFI_DO(Botan::Private_Key, key, k, {
- Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
-
- std::string cipher;
- if(maybe_cipher)
- {
- cipher = maybe_cipher;
- }
-
- std::string pbkdf_hash;
- if(maybe_pbkdf_hash)
- {
- pbkdf_hash = maybe_pbkdf_hash;
- }
-
- if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER)
- {
- return write_vec_output(out, out_len,
- Botan::PKCS8::BER_encode_encrypted_pbkdf_iter(k, rng, pass, pbkdf_iter, cipher, pbkdf_hash));
- }
- else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM)
- {
- return write_str_output(out, out_len,
- Botan::PKCS8::PEM_encode_encrypted_pbkdf_iter(k, rng, pass, pbkdf_iter, cipher, pbkdf_hash));
- }
- else
- {
- return -2;
- }
- });
- }
-
-int botan_pubkey_estimated_strength(botan_pubkey_t key, size_t* estimate)
- {
- return BOTAN_FFI_DO(Botan::Public_Key, key, k, { *estimate = k.estimated_strength(); });
- }
-
-int botan_pubkey_fingerprint(botan_pubkey_t key, const char* hash_fn,
- uint8_t out[], size_t* out_len)
- {
- return BOTAN_FFI_DO(Botan::Public_Key, key, k, {
- std::unique_ptr<Botan::HashFunction> h(Botan::HashFunction::create(hash_fn));
- return write_vec_output(out, out_len, h->process(k.public_key_bits()));
- });
- }
-
-int botan_pk_op_encrypt_create(botan_pk_op_encrypt_t* op,
- botan_pubkey_t key_obj,
- const char* padding,
- uint32_t flags)
- {
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- BOTAN_ASSERT_NONNULL(op);
-
- *op = nullptr;
-
- if(flags != 0)
- return BOTAN_FFI_ERROR_BAD_FLAG;
-
- std::unique_ptr<Botan::PK_Encryptor> pk(new Botan::PK_Encryptor_EME(safe_get(key_obj), Botan::system_rng(), padding));
- *op = new botan_pk_op_encrypt_struct(pk.release());
- return BOTAN_FFI_SUCCESS;
- });
- }
-
-int botan_pk_op_encrypt_destroy(botan_pk_op_encrypt_t op)
- {
- return BOTAN_FFI_CHECKED_DELETE(op);
- }
-
-int botan_pk_op_encrypt(botan_pk_op_encrypt_t op,
- botan_rng_t rng_obj,
- uint8_t out[], size_t* out_len,
- const uint8_t plaintext[], size_t plaintext_len)
- {
- return BOTAN_FFI_DO(Botan::PK_Encryptor, op, o, {
- return write_vec_output(out, out_len, o.encrypt(plaintext, plaintext_len, safe_get(rng_obj)));
- });
- }
-
-/*
-* Public Key Decryption
-*/
-int botan_pk_op_decrypt_create(botan_pk_op_decrypt_t* op,
- botan_privkey_t key_obj,
- const char* padding,
- uint32_t flags)
- {
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- BOTAN_ASSERT_NONNULL(op);
-
- *op = nullptr;
-
- if(flags != 0)
- return BOTAN_FFI_ERROR_BAD_FLAG;
-
- std::unique_ptr<Botan::PK_Decryptor> pk(new Botan::PK_Decryptor_EME(safe_get(key_obj), Botan::system_rng(), padding));
- *op = new botan_pk_op_decrypt_struct(pk.release());
- return BOTAN_FFI_SUCCESS;
- });
- }
-
-int botan_pk_op_decrypt_destroy(botan_pk_op_decrypt_t op)
- {
- return BOTAN_FFI_CHECKED_DELETE(op);
- }
-
-int botan_pk_op_decrypt(botan_pk_op_decrypt_t op,
- uint8_t out[], size_t* out_len,
- const uint8_t ciphertext[], size_t ciphertext_len)
- {
- return BOTAN_FFI_DO(Botan::PK_Decryptor, op, o, {
- return write_vec_output(out, out_len, o.decrypt(ciphertext, ciphertext_len));
- });
- }
-
-/*
-* Signature Generation
-*/
-int botan_pk_op_sign_create(botan_pk_op_sign_t* op,
- botan_privkey_t key_obj,
- const char* hash,
- uint32_t flags)
- {
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- BOTAN_ASSERT_NONNULL(op);
-
- *op = nullptr;
-
- if(flags != 0)
- return BOTAN_FFI_ERROR_BAD_FLAG;
-
- std::unique_ptr<Botan::PK_Signer> pk(new Botan::PK_Signer(safe_get(key_obj),Botan::system_rng(), hash));
- *op = new botan_pk_op_sign_struct(pk.release());
- return BOTAN_FFI_SUCCESS;
- });
- }
-
-int botan_pk_op_sign_destroy(botan_pk_op_sign_t op)
- {
- return BOTAN_FFI_CHECKED_DELETE(op);
- }
-
-int botan_pk_op_sign_update(botan_pk_op_sign_t op, const uint8_t in[], size_t in_len)
- {
- return BOTAN_FFI_DO(Botan::PK_Signer, op, o, { o.update(in, in_len); });
- }
-
-int botan_pk_op_sign_finish(botan_pk_op_sign_t op, botan_rng_t rng_obj, uint8_t out[], size_t* out_len)
- {
- return BOTAN_FFI_DO(Botan::PK_Signer, op, o, {
- return write_vec_output(out, out_len, o.signature(safe_get(rng_obj)));
- });
- }
-
-int botan_pk_op_verify_create(botan_pk_op_verify_t* op,
- botan_pubkey_t key_obj,
- const char* hash,
- uint32_t flags)
- {
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- BOTAN_ASSERT_NONNULL(op);
-
- if(flags != 0)
- return BOTAN_FFI_ERROR_BAD_FLAG;
-
- std::unique_ptr<Botan::PK_Verifier> pk(new Botan::PK_Verifier(safe_get(key_obj), hash));
- *op = new botan_pk_op_verify_struct(pk.release());
- return BOTAN_FFI_SUCCESS;
- });
- }
-
-int botan_pk_op_verify_destroy(botan_pk_op_verify_t op)
- {
- return BOTAN_FFI_CHECKED_DELETE(op);
- }
-
-int botan_pk_op_verify_update(botan_pk_op_verify_t op, const uint8_t in[], size_t in_len)
- {
- return BOTAN_FFI_DO(Botan::PK_Verifier, op, o, { o.update(in, in_len); });
- }
-
-int botan_pk_op_verify_finish(botan_pk_op_verify_t op, const uint8_t sig[], size_t sig_len)
- {
- return BOTAN_FFI_DO(Botan::PK_Verifier, op, o, {
- const bool legit = o.check_signature(sig, sig_len);
-
- if(legit)
- return BOTAN_FFI_SUCCESS;
- else
- return BOTAN_FFI_ERROR_INVALID_INPUT;
- });
- }
-
-int botan_pk_op_key_agreement_create(botan_pk_op_ka_t* op,
- botan_privkey_t key_obj,
- const char* kdf,
- uint32_t flags)
- {
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- BOTAN_ASSERT_NONNULL(op);
-
- *op = nullptr;
-
- if(flags != 0)
- return BOTAN_FFI_ERROR_BAD_FLAG;
-
- std::unique_ptr<Botan::PK_Key_Agreement> pk(new Botan::PK_Key_Agreement(safe_get(key_obj), Botan::system_rng(), kdf));
- *op = new botan_pk_op_ka_struct(pk.release());
- return BOTAN_FFI_SUCCESS;
- });
- }
-
-int botan_pk_op_key_agreement_destroy(botan_pk_op_ka_t op)
- {
- return BOTAN_FFI_CHECKED_DELETE(op);
- }
-
-int botan_pk_op_key_agreement_export_public(botan_privkey_t key,
- uint8_t out[], size_t* out_len)
- {
- return BOTAN_FFI_DO(Botan::Private_Key, key, k, {
- if(auto kak = dynamic_cast<const Botan::PK_Key_Agreement_Key*>(&k))
- return write_vec_output(out, out_len, kak->public_value());
- return BOTAN_FFI_ERROR_BAD_FLAG;
- });
- }
-
-int botan_pk_op_key_agreement(botan_pk_op_ka_t op,
- uint8_t out[], size_t* out_len,
- const uint8_t other_key[], size_t other_key_len,
- const uint8_t salt[], size_t salt_len)
- {
- return BOTAN_FFI_DO(Botan::PK_Key_Agreement, op, o, {
- auto k = o.derive_key(*out_len, other_key, other_key_len, salt, salt_len).bits_of();
- return write_vec_output(out, out_len, k);
- });
- }
-
-int botan_x509_cert_load_file(botan_x509_cert_t* cert_obj, const char* cert_path)
- {
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- if(!cert_obj || !cert_path)
- return BOTAN_FFI_ERROR_NULL_POINTER;
-
-#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
- std::unique_ptr<Botan::X509_Certificate> c(new Botan::X509_Certificate(cert_path));
- *cert_obj = new botan_x509_cert_struct(c.release());
- return BOTAN_FFI_SUCCESS;
-#else
- return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
-#endif
- });
- }
-
-int botan_x509_cert_load(botan_x509_cert_t* cert_obj, const uint8_t cert_bits[], size_t cert_bits_len)
- {
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- if(!cert_obj || !cert_bits)
- return BOTAN_FFI_ERROR_NULL_POINTER;
-
- Botan::DataSource_Memory bits(cert_bits, cert_bits_len);
-
- std::unique_ptr<Botan::X509_Certificate> c(new Botan::X509_Certificate(bits));
- *cert_obj = new botan_x509_cert_struct(c.release());
- return BOTAN_FFI_SUCCESS;
- });
- }
-
-int botan_x509_cert_destroy(botan_x509_cert_t cert)
- {
- return BOTAN_FFI_CHECKED_DELETE(cert);
- }
-
-int botan_x509_cert_get_time_starts(botan_x509_cert_t cert, char out[], size_t* out_len)
- {
- return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_str_output(out, out_len, c.start_time()); });
- }
-
-int botan_x509_cert_get_time_expires(botan_x509_cert_t cert, char out[], size_t* out_len)
- {
- return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_str_output(out, out_len, c.end_time()); });
- }
-
-int botan_x509_cert_get_serial_number(botan_x509_cert_t cert, uint8_t out[], size_t* out_len)
- {
- return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_vec_output(out, out_len, c.serial_number()); });
- }
-
-int botan_x509_cert_get_fingerprint(botan_x509_cert_t cert, const char* hash, uint8_t out[], size_t* out_len)
- {
- return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_str_output(out, out_len, c.fingerprint(hash)); });
- }
-
-int botan_x509_cert_get_authority_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len)
- {
- return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_vec_output(out, out_len, c.authority_key_id()); });
- }
-
-int botan_x509_cert_get_subject_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len)
- {
- return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_vec_output(out, out_len, c.subject_key_id()); });
- }
-
-int botan_x509_cert_get_public_key_bits(botan_x509_cert_t cert, uint8_t out[], size_t* out_len)
- {
- return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_vec_output(out, out_len, c.subject_public_key_bits()); });
- }
-
-
-/*
-int botan_x509_cert_path_verify(botan_x509_cert_t cert, const char* dir)
-{
-}
-*/
-
-int botan_x509_cert_get_public_key(botan_x509_cert_t cert, botan_pubkey_t* key)
- {
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- if(key == nullptr)
- return BOTAN_FFI_ERROR_NULL_POINTER;
-
- *key = nullptr;
-
-#if defined(BOTAN_HAS_RSA)
- std::unique_ptr<Botan::Public_Key> publicKey(safe_get(cert).subject_public_key());
- *key = new botan_pubkey_struct(publicKey.release());
- return BOTAN_FFI_SUCCESS;
-#else
- return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
-#endif
- });
- }
-
-int botan_x509_cert_get_issuer_dn(botan_x509_cert_t cert,
- const char* key, size_t index,
- uint8_t out[], size_t* out_len)
- {
- return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_str_output(out, out_len, c.issuer_info(key).at(index)); });
- }
-
-int botan_x509_cert_get_subject_dn(botan_x509_cert_t cert,
- const char* key, size_t index,
- uint8_t out[], size_t* out_len)
- {
- return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_str_output(out, out_len, c.subject_info(key).at(index)); });
- }
-
-int botan_x509_cert_to_string(botan_x509_cert_t cert, char out[], size_t* out_len)
- {
- return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_str_output(out, out_len, c.to_string()); });
- }
-
-int botan_x509_cert_allowed_usage(botan_x509_cert_t cert, unsigned int key_usage)
- {
- return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, {
- const Botan::Key_Constraints k = static_cast<Botan::Key_Constraints>(key_usage);
- if(c.allowed_usage(k))
- return BOTAN_FFI_SUCCESS;
- return 1;
- });
- }
-
-int botan_pkcs_hash_id(const char* hash_name, uint8_t pkcs_id[], size_t* pkcs_id_len)
- {
-#if defined(BOTAN_HAS_HASH_ID)
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- const std::vector<uint8_t> hash_id = Botan::pkcs_hash_id(hash_name);
- return write_output(pkcs_id, pkcs_id_len, hash_id.data(), hash_id.size());
- });
-#else
- return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
-#endif
- }
-
-int botan_mceies_decrypt(botan_privkey_t mce_key_obj,
- const char* aead,
- const uint8_t ct[], size_t ct_len,
- const uint8_t ad[], size_t ad_len,
- uint8_t out[], size_t* out_len)
- {
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- Botan::Private_Key& key = safe_get(mce_key_obj);
-
-#if defined(BOTAN_HAS_MCELIECE) && defined(BOTAN_HAS_MCEIES)
- Botan::McEliece_PrivateKey* mce = dynamic_cast<Botan::McEliece_PrivateKey*>(&key);
- if(!mce)
- return BOTAN_FFI_ERROR_BAD_PARAMETER;
-
- const Botan::secure_vector<uint8_t> pt = mceies_decrypt(*mce, ct, ct_len, ad, ad_len, aead);
- return write_vec_output(out, out_len, pt);
-#else
- return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
-#endif
- });
- }
-
-int botan_mceies_encrypt(botan_pubkey_t mce_key_obj,
- botan_rng_t rng_obj,
- const char* aead,
- const uint8_t pt[], size_t pt_len,
- const uint8_t ad[], size_t ad_len,
- uint8_t out[], size_t* out_len)
- {
- return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
- Botan::Public_Key& key = safe_get(mce_key_obj);
- Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
-
-#if defined(BOTAN_HAS_MCELIECE) && defined(BOTAN_HAS_MCEIES)
- Botan::McEliece_PublicKey* mce = dynamic_cast<Botan::McEliece_PublicKey*>(&key);
- if(!mce)
- return BOTAN_FFI_ERROR_BAD_PARAMETER;
-
- Botan::secure_vector<uint8_t> ct = mceies_encrypt(*mce, pt, pt_len, ad, ad_len, rng, aead);
- return write_vec_output(out, out_len, ct);
-#else
- return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
-#endif
- });
- }
-
-int botan_key_wrap3394( uint8_t key[], size_t key_len,
- uint8_t kek[], size_t kek_len,
- uint8_t wrapped_key[], size_t *wrapped_key_len)
-{
-#if defined(BOTAN_HAS_RFC3394_KEYWRAP)
- try
- {
- const Botan::SymmetricKey kek_sym(kek, kek_len);
- const Botan::secure_vector<uint8_t> key_pt(key, key + key_len);
- const Botan::secure_vector<uint8_t> key_ct = Botan::rfc3394_keywrap(key_pt, kek_sym);
- return write_vec_output(wrapped_key, wrapped_key_len, key_ct);
- }
- catch(std::exception &e)
- {
- return ffi_error_exception_thrown(e.what());
- }
-#else
- return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
-#endif
-}
-
-int botan_key_unwrap3394( uint8_t wrapped_key[], size_t wrapped_key_len,
- uint8_t kek[], size_t kek_len,
- uint8_t key[], size_t *key_len)
-{
-#if defined(BOTAN_HAS_RFC3394_KEYWRAP)
- try
- {
- const Botan::SymmetricKey kek_sym(kek, kek_len);
- const Botan::secure_vector<uint8_t> key_ct(wrapped_key, wrapped_key + wrapped_key_len);
- const Botan::secure_vector<uint8_t> key_pt = Botan::rfc3394_keyunwrap(key_ct, kek_sym);
- return write_vec_output(key, key_len, key_pt);
- }
- catch(std::exception &e)
- {
- return ffi_error_exception_thrown(e.what());
- }
-#else
- return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
-#endif
-}
-
-/*
-int botan_tls_channel_init_client(botan_tls_channel_t* channel,
- botan_tls_channel_output_fn output_fn,
- botan_tls_channel_data_cb data_cb,
- botan_tls_channel_alert_cb alert_cb,
- botan_tls_channel_session_established session_cb,
- const char* server_name)
- {
-
- }
-*/
-
}
diff --git a/src/lib/ffi/ffi.h b/src/lib/ffi/ffi.h
index e56ad5629..45cce37d2 100644
--- a/src/lib/ffi/ffi.h
+++ b/src/lib/ffi/ffi.h
@@ -873,22 +873,22 @@ BOTAN_DLL int botan_pubkey_ed25519_get_pubkey(botan_pubkey_t key,
* Algorithm specific key operations: ECDSA and ECDH
*/
BOTAN_DLL int botan_privkey_load_ecdsa(botan_privkey_t* key,
- const botan_mp_t scalar,
- const char* curve_name);
+ const botan_mp_t scalar,
+ const char* curve_name);
BOTAN_DLL int botan_pubkey_load_ecdsa(botan_pubkey_t* key,
- const botan_mp_t public_x,
- const botan_mp_t public_y,
- const char* curve_name);
+ const botan_mp_t public_x,
+ const botan_mp_t public_y,
+ const char* curve_name);
BOTAN_DLL int botan_pubkey_load_ecdh(botan_pubkey_t* key,
- const botan_mp_t public_x,
- const botan_mp_t public_y,
- const char* curve_name);
+ const botan_mp_t public_x,
+ const botan_mp_t public_y,
+ const char* curve_name);
BOTAN_DLL int botan_privkey_load_ecdh(botan_privkey_t* key,
- const botan_mp_t scalar,
- const char* curve_name);
+ const botan_mp_t scalar,
+ const char* curve_name);
BOTAN_DLL int botan_pubkey_load_sm2(botan_pubkey_t* key,
const botan_mp_t public_x,
@@ -1023,9 +1023,6 @@ BOTAN_DLL int botan_x509_cert_get_serial_number(botan_x509_cert_t cert, uint8_t
BOTAN_DLL int botan_x509_cert_get_authority_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len);
BOTAN_DLL int botan_x509_cert_get_subject_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len);
-BOTAN_DLL int botan_x509_cert_path_verify(botan_x509_cert_t cert,
- const char* ca_dir);
-
BOTAN_DLL int botan_x509_cert_get_public_key_bits(botan_x509_cert_t cert,
uint8_t out[], size_t* out_len);
diff --git a/src/lib/ffi/ffi_block.cpp b/src/lib/ffi/ffi_block.cpp
new file mode 100644
index 000000000..96a352877
--- /dev/null
+++ b/src/lib/ffi/ffi_block.cpp
@@ -0,0 +1,81 @@
+/*
+* (C) 2015,2017 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/ffi.h>
+#include <botan/internal/ffi_util.h>
+#include <botan/block_cipher.h>
+
+extern "C" {
+
+using namespace Botan_FFI;
+
+BOTAN_FFI_DECLARE_STRUCT(botan_block_cipher_struct, Botan::BlockCipher, 0x64C29716);
+
+int botan_block_cipher_init(botan_block_cipher_t* bc, const char* bc_name)
+ {
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ if(bc == nullptr || bc_name == nullptr || *bc_name == 0)
+ return BOTAN_FFI_ERROR_NULL_POINTER;
+
+ *bc = nullptr;
+
+ std::unique_ptr<Botan::BlockCipher> cipher(Botan::BlockCipher::create(bc_name));
+ if(cipher == nullptr)
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+
+ *bc = new botan_block_cipher_struct(cipher.release());
+ return BOTAN_FFI_SUCCESS;
+ });
+ }
+
+/**
+* Destroy a block cipher object
+*/
+int botan_block_cipher_destroy(botan_block_cipher_t bc)
+ {
+ return BOTAN_FFI_CHECKED_DELETE(bc);
+ }
+
+int botan_block_cipher_clear(botan_block_cipher_t bc)
+ {
+ return BOTAN_FFI_DO(Botan::BlockCipher, bc, b, { b.clear(); });
+ }
+
+/**
+* Set the key for a block cipher instance
+*/
+int botan_block_cipher_set_key(botan_block_cipher_t bc,
+ const uint8_t key[], size_t len)
+ {
+ return BOTAN_FFI_DO(Botan::BlockCipher, bc, b, { b.set_key(key, len); });
+ }
+
+/**
+* Return the positive block size of this block cipher, or negative to
+* indicate an error
+*/
+int botan_block_cipher_block_size(botan_block_cipher_t bc)
+ {
+ return BOTAN_FFI_DO(Botan::BlockCipher, bc, b, { return b.block_size(); });
+ }
+
+int botan_block_cipher_encrypt_blocks(botan_block_cipher_t bc,
+ const uint8_t in[],
+ uint8_t out[],
+ size_t blocks)
+ {
+ return BOTAN_FFI_DO(Botan::BlockCipher, bc, b, { b.encrypt_n(in, out, blocks); });
+ }
+
+int botan_block_cipher_decrypt_blocks(botan_block_cipher_t bc,
+ const uint8_t in[],
+ uint8_t out[],
+ size_t blocks)
+ {
+ return BOTAN_FFI_DO(Botan::BlockCipher, bc, b, { b.decrypt_n(in, out, blocks); });
+ }
+
+}
diff --git a/src/lib/ffi/ffi_cert.cpp b/src/lib/ffi/ffi_cert.cpp
new file mode 100644
index 000000000..2ac9c69af
--- /dev/null
+++ b/src/lib/ffi/ffi_cert.cpp
@@ -0,0 +1,136 @@
+/*
+* (C) 2015,2017 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/ffi.h>
+#include <botan/internal/ffi_util.h>
+#include <botan/internal/ffi_pkey.h>
+#include <botan/x509cert.h>
+#include <botan/data_src.h>
+
+extern "C" {
+
+using namespace Botan_FFI;
+
+BOTAN_FFI_DECLARE_STRUCT(botan_x509_cert_struct, Botan::X509_Certificate, 0x8F628937);
+
+int botan_x509_cert_load_file(botan_x509_cert_t* cert_obj, const char* cert_path)
+ {
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ if(!cert_obj || !cert_path)
+ return BOTAN_FFI_ERROR_NULL_POINTER;
+
+#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
+ std::unique_ptr<Botan::X509_Certificate> c(new Botan::X509_Certificate(cert_path));
+ *cert_obj = new botan_x509_cert_struct(c.release());
+ return BOTAN_FFI_SUCCESS;
+#else
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+#endif
+ });
+ }
+
+int botan_x509_cert_load(botan_x509_cert_t* cert_obj, const uint8_t cert_bits[], size_t cert_bits_len)
+ {
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ if(!cert_obj || !cert_bits)
+ return BOTAN_FFI_ERROR_NULL_POINTER;
+
+ Botan::DataSource_Memory bits(cert_bits, cert_bits_len);
+
+ std::unique_ptr<Botan::X509_Certificate> c(new Botan::X509_Certificate(bits));
+ *cert_obj = new botan_x509_cert_struct(c.release());
+ return BOTAN_FFI_SUCCESS;
+ });
+ }
+
+int botan_x509_cert_get_public_key(botan_x509_cert_t cert, botan_pubkey_t* key)
+ {
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ if(key == nullptr)
+ return BOTAN_FFI_ERROR_NULL_POINTER;
+
+ *key = nullptr;
+
+#if defined(BOTAN_HAS_RSA)
+ std::unique_ptr<Botan::Public_Key> publicKey(safe_get(cert).subject_public_key());
+ *key = new botan_pubkey_struct(publicKey.release());
+ return BOTAN_FFI_SUCCESS;
+#else
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+#endif
+ });
+ }
+
+int botan_x509_cert_get_issuer_dn(botan_x509_cert_t cert,
+ const char* key, size_t index,
+ uint8_t out[], size_t* out_len)
+ {
+ return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_str_output(out, out_len, c.issuer_info(key).at(index)); });
+ }
+
+int botan_x509_cert_get_subject_dn(botan_x509_cert_t cert,
+ const char* key, size_t index,
+ uint8_t out[], size_t* out_len)
+ {
+ return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_str_output(out, out_len, c.subject_info(key).at(index)); });
+ }
+
+int botan_x509_cert_to_string(botan_x509_cert_t cert, char out[], size_t* out_len)
+ {
+ return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_str_output(out, out_len, c.to_string()); });
+ }
+
+int botan_x509_cert_allowed_usage(botan_x509_cert_t cert, unsigned int key_usage)
+ {
+ return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, {
+ const Botan::Key_Constraints k = static_cast<Botan::Key_Constraints>(key_usage);
+ if(c.allowed_usage(k))
+ return BOTAN_FFI_SUCCESS;
+ return 1;
+ });
+ }
+
+int botan_x509_cert_destroy(botan_x509_cert_t cert)
+ {
+ return BOTAN_FFI_CHECKED_DELETE(cert);
+ }
+
+int botan_x509_cert_get_time_starts(botan_x509_cert_t cert, char out[], size_t* out_len)
+ {
+ return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_str_output(out, out_len, c.start_time()); });
+ }
+
+int botan_x509_cert_get_time_expires(botan_x509_cert_t cert, char out[], size_t* out_len)
+ {
+ return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_str_output(out, out_len, c.end_time()); });
+ }
+
+int botan_x509_cert_get_serial_number(botan_x509_cert_t cert, uint8_t out[], size_t* out_len)
+ {
+ return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_vec_output(out, out_len, c.serial_number()); });
+ }
+
+int botan_x509_cert_get_fingerprint(botan_x509_cert_t cert, const char* hash, uint8_t out[], size_t* out_len)
+ {
+ return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_str_output(out, out_len, c.fingerprint(hash)); });
+ }
+
+int botan_x509_cert_get_authority_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len)
+ {
+ return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_vec_output(out, out_len, c.authority_key_id()); });
+ }
+
+int botan_x509_cert_get_subject_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len)
+ {
+ return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_vec_output(out, out_len, c.subject_key_id()); });
+ }
+
+int botan_x509_cert_get_public_key_bits(botan_x509_cert_t cert, uint8_t out[], size_t* out_len)
+ {
+ return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_vec_output(out, out_len, c.subject_public_key_bits()); });
+ }
+
+}
diff --git a/src/lib/ffi/ffi_cipher.cpp b/src/lib/ffi/ffi_cipher.cpp
new file mode 100644
index 000000000..6bb45dec8
--- /dev/null
+++ b/src/lib/ffi/ffi_cipher.cpp
@@ -0,0 +1,196 @@
+/*
+* (C) 2015,2017 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/ffi.h>
+#include <botan/internal/ffi_util.h>
+#include <botan/aead.h>
+
+extern "C" {
+
+using namespace Botan_FFI;
+
+struct botan_cipher_struct : public botan_struct<Botan::Cipher_Mode, 0xB4A2BF9C>
+ {
+ explicit botan_cipher_struct(Botan::Cipher_Mode* x) : botan_struct(x) {}
+ Botan::secure_vector<uint8_t> m_buf;
+ };
+
+int botan_cipher_init(botan_cipher_t* cipher, const char* cipher_name, uint32_t flags)
+ {
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ const bool encrypt_p = ((flags & BOTAN_CIPHER_INIT_FLAG_MASK_DIRECTION) == BOTAN_CIPHER_INIT_FLAG_ENCRYPT);
+ const Botan::Cipher_Dir dir = encrypt_p ? Botan::ENCRYPTION : Botan::DECRYPTION;
+ std::unique_ptr<Botan::Cipher_Mode> mode(Botan::get_cipher_mode(cipher_name, dir));
+ if(!mode)
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+ *cipher = new botan_cipher_struct(mode.release());
+ return BOTAN_FFI_SUCCESS;
+ });
+ }
+
+int botan_cipher_destroy(botan_cipher_t cipher)
+ {
+ return BOTAN_FFI_CHECKED_DELETE(cipher);
+ }
+
+int botan_cipher_clear(botan_cipher_t cipher)
+ {
+ return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { c.clear(); });
+ }
+
+int botan_cipher_query_keylen(botan_cipher_t cipher,
+ size_t* out_minimum_keylength,
+ size_t* out_maximum_keylength)
+ {
+ return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, {
+ *out_minimum_keylength = c.key_spec().minimum_keylength();
+ *out_maximum_keylength = c.key_spec().maximum_keylength();
+ });
+ }
+
+int botan_cipher_set_key(botan_cipher_t cipher,
+ const uint8_t* key, size_t key_len)
+ {
+ return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { c.set_key(key, key_len); });
+ }
+
+int botan_cipher_start(botan_cipher_t cipher_obj,
+ const uint8_t* nonce, size_t nonce_len)
+ {
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ Botan::Cipher_Mode& cipher = safe_get(cipher_obj);
+ cipher.start(nonce, nonce_len);
+ cipher_obj->m_buf.reserve(cipher.update_granularity());
+ return BOTAN_FFI_SUCCESS;
+ });
+ }
+
+int botan_cipher_update(botan_cipher_t cipher_obj,
+ uint32_t flags,
+ uint8_t output_ptr[],
+ size_t orig_output_size,
+ size_t* output_written,
+ const uint8_t input_ptr[],
+ size_t orig_input_size,
+ size_t* input_consumed)
+ {
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+
+ size_t input_size = orig_input_size;
+ size_t output_size = orig_output_size;
+ const uint8_t* input = input_ptr;
+ uint8_t* output = output_ptr;
+
+ using namespace Botan;
+ Cipher_Mode& cipher = safe_get(cipher_obj);
+ secure_vector<uint8_t>& mbuf = cipher_obj->m_buf;
+
+ const bool final_input = (flags & BOTAN_CIPHER_UPDATE_FLAG_FINAL);
+
+ if(final_input)
+ {
+ mbuf.assign(input, input + input_size);
+ *input_consumed = input_size;
+ *output_written = 0;
+
+ try
+ {
+ cipher.finish(mbuf);
+ }
+ catch(Integrity_Failure& e)
+ {
+ return BOTAN_FFI_ERROR_BAD_MAC;
+ }
+
+ *output_written = mbuf.size();
+
+ if(mbuf.size() <= output_size)
+ {
+ copy_mem(output, mbuf.data(), mbuf.size());
+ mbuf.clear();
+ return BOTAN_FFI_SUCCESS;
+ }
+
+ return -1;
+ }
+
+ if(input_size == 0)
+ {
+ // Currently must take entire buffer in this case
+ *output_written = mbuf.size();
+ if(output_size >= mbuf.size())
+ {
+ copy_mem(output, mbuf.data(), mbuf.size());
+ mbuf.clear();
+ return BOTAN_FFI_SUCCESS;
+ }
+
+ return -1;
+ }
+
+ const size_t ud = cipher.update_granularity();
+ BOTAN_ASSERT(cipher.update_granularity() > cipher.minimum_final_size(), "logic error");
+
+ mbuf.resize(ud);
+ size_t taken = 0, written = 0;
+
+ while(input_size >= ud && output_size >= ud)
+ {
+ copy_mem(mbuf.data(), input, ud);
+ cipher.update(mbuf);
+
+ input_size -= ud;
+ copy_mem(output, mbuf.data(), ud);
+ input += ud;
+ taken += ud;
+
+ output_size -= ud;
+ output += ud;
+ written += ud;
+ }
+
+ *output_written = written;
+ *input_consumed = taken;
+
+ return BOTAN_FFI_SUCCESS;
+ });
+ }
+
+int botan_cipher_set_associated_data(botan_cipher_t cipher,
+ const uint8_t* ad,
+ size_t ad_len)
+ {
+ return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, {
+ if(Botan::AEAD_Mode* aead = dynamic_cast<Botan::AEAD_Mode*>(&c))
+ {
+ aead->set_associated_data(ad, ad_len);
+ return BOTAN_FFI_SUCCESS;
+ }
+ return BOTAN_FFI_ERROR_BAD_PARAMETER;
+ });
+ }
+
+int botan_cipher_valid_nonce_length(botan_cipher_t cipher, size_t nl)
+ {
+ return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { return c.valid_nonce_length(nl) ? 1 : 0; });
+ }
+
+int botan_cipher_get_default_nonce_length(botan_cipher_t cipher, size_t* nl)
+ {
+ return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { *nl = c.default_nonce_length(); });
+ }
+
+int botan_cipher_get_update_granularity(botan_cipher_t cipher, size_t* ug)
+ {
+ return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { *ug = c.update_granularity(); });
+ }
+
+int botan_cipher_get_tag_length(botan_cipher_t cipher, size_t* tl)
+ {
+ return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { *tl = c.tag_size(); });
+ }
+
+}
diff --git a/src/lib/ffi/ffi_hash.cpp b/src/lib/ffi/ffi_hash.cpp
new file mode 100644
index 000000000..58fb1d38f
--- /dev/null
+++ b/src/lib/ffi/ffi_hash.cpp
@@ -0,0 +1,70 @@
+/*
+* (C) 2015,2017 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/ffi.h>
+#include <botan/internal/ffi_util.h>
+#include <botan/hash.h>
+
+extern "C" {
+
+using namespace Botan_FFI;
+
+BOTAN_FFI_DECLARE_STRUCT(botan_hash_struct, Botan::HashFunction, 0x1F0A4F84);
+
+int botan_hash_init(botan_hash_t* hash, const char* hash_name, uint32_t flags)
+ {
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ if(hash == nullptr || hash_name == nullptr || *hash_name == 0)
+ return BOTAN_FFI_ERROR_NULL_POINTER;
+ if(flags != 0)
+ return BOTAN_FFI_ERROR_BAD_FLAG;
+
+ std::unique_ptr<Botan::HashFunction> h = Botan::HashFunction::create(hash_name);
+ if(h == nullptr)
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+
+ *hash = new botan_hash_struct(h.release());
+ return BOTAN_FFI_SUCCESS;
+ });
+ }
+
+int botan_hash_destroy(botan_hash_t hash)
+ {
+ return BOTAN_FFI_CHECKED_DELETE(hash);
+ }
+
+int botan_hash_output_length(botan_hash_t hash, size_t* out)
+ {
+ return BOTAN_FFI_DO(Botan::HashFunction, hash, h, { *out = h.output_length(); });
+ }
+
+int botan_hash_block_size(botan_hash_t hash, size_t* out)
+ {
+ return BOTAN_FFI_DO(Botan::HashFunction, hash, h, { *out = h.hash_block_size(); });
+ }
+
+int botan_hash_clear(botan_hash_t hash)
+ {
+ return BOTAN_FFI_DO(Botan::HashFunction, hash, h, { h.clear(); });
+ }
+
+int botan_hash_update(botan_hash_t hash, const uint8_t* buf, size_t len)
+ {
+ return BOTAN_FFI_DO(Botan::HashFunction, hash, h, { h.update(buf, len); });
+ }
+
+int botan_hash_final(botan_hash_t hash, uint8_t out[])
+ {
+ return BOTAN_FFI_DO(Botan::HashFunction, hash, h, { h.final(out); });
+ }
+
+int botan_hash_copy_state(botan_hash_t* dest, const botan_hash_t source)
+ {
+ return BOTAN_FFI_DO(Botan::HashFunction, source, src, {
+ *dest = new botan_hash_struct(src.copy_state().release()); });
+ }
+
+}
diff --git a/src/lib/ffi/ffi_kdf.cpp b/src/lib/ffi/ffi_kdf.cpp
new file mode 100644
index 000000000..058c4c655
--- /dev/null
+++ b/src/lib/ffi/ffi_kdf.cpp
@@ -0,0 +1,98 @@
+/*
+* (C) 2015,2017 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/ffi.h>
+#include <botan/internal/ffi_util.h>
+#include <botan/internal/ffi_rng.h>
+#include <botan/pbkdf.h>
+#include <botan/kdf.h>
+
+#if defined(BOTAN_HAS_BCRYPT)
+ #include <botan/bcrypt.h>
+#endif
+
+extern "C" {
+
+using namespace Botan_FFI;
+
+int botan_pbkdf(const char* pbkdf_algo, uint8_t out[], size_t out_len,
+ const char* pass, const uint8_t salt[], size_t salt_len,
+ size_t iterations)
+ {
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ std::unique_ptr<Botan::PBKDF> pbkdf(Botan::get_pbkdf(pbkdf_algo));
+ pbkdf->pbkdf_iterations(out, out_len, pass, salt, salt_len, iterations);
+ return BOTAN_FFI_SUCCESS;
+ });
+ }
+
+int botan_pbkdf_timed(const char* pbkdf_algo,
+ uint8_t out[], size_t out_len,
+ const char* password,
+ const uint8_t salt[], size_t salt_len,
+ size_t ms_to_run,
+ size_t* iterations_used)
+ {
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ std::unique_ptr<Botan::PBKDF> pbkdf(Botan::get_pbkdf(pbkdf_algo));
+ pbkdf->pbkdf_timed(out, out_len, password, salt, salt_len,
+ std::chrono::milliseconds(ms_to_run),
+ *iterations_used);
+ return BOTAN_FFI_SUCCESS;
+ });
+ }
+
+int botan_kdf(const char* kdf_algo,
+ uint8_t out[], size_t out_len,
+ const uint8_t secret[], size_t secret_len,
+ const uint8_t salt[], size_t salt_len,
+ const uint8_t label[], size_t label_len)
+ {
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ std::unique_ptr<Botan::KDF> kdf(Botan::get_kdf(kdf_algo));
+ kdf->kdf(out, out_len, secret, secret_len, salt, salt_len, label, label_len);
+ return BOTAN_FFI_SUCCESS;
+ });
+ }
+
+int botan_bcrypt_generate(uint8_t* out, size_t* out_len,
+ const char* pass,
+ botan_rng_t rng_obj, size_t wf,
+ uint32_t flags)
+ {
+#if defined(BOTAN_HAS_BCRYPT)
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ BOTAN_ASSERT_ARG_NON_NULL(out);
+ BOTAN_ASSERT_ARG_NON_NULL(out_len);
+ BOTAN_ASSERT_ARG_NON_NULL(pass);
+
+ if(flags != 0)
+ return BOTAN_FFI_ERROR_BAD_FLAG;
+
+ if(wf < 2 || wf > 30)
+ throw FFI_Error("Bad bcrypt work factor " + std::to_string(wf));
+
+ Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
+ const std::string bcrypt = Botan::generate_bcrypt(pass, rng, wf);
+ return write_str_output(out, out_len, bcrypt);
+ });
+#else
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+#endif
+ }
+
+int botan_bcrypt_is_valid(const char* pass, const char* hash)
+ {
+#if defined(BOTAN_HAS_BCRYPT)
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ return Botan::check_bcrypt(pass, hash) ? 0 : 1;
+ });
+#else
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+#endif
+ }
+
+}
diff --git a/src/lib/ffi/ffi_keywrap.cpp b/src/lib/ffi/ffi_keywrap.cpp
new file mode 100644
index 000000000..d881140d6
--- /dev/null
+++ b/src/lib/ffi/ffi_keywrap.cpp
@@ -0,0 +1,50 @@
+/*
+* (C) 2017 Ribose Inc
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/ffi.h>
+#include <botan/internal/ffi_util.h>
+
+#if defined(BOTAN_HAS_RFC3394_KEYWRAP)
+ #include <botan/rfc3394.h>
+#endif
+
+extern "C" {
+
+using namespace Botan_FFI;
+
+int botan_key_wrap3394(uint8_t key[], size_t key_len,
+ uint8_t kek[], size_t kek_len,
+ uint8_t wrapped_key[], size_t* wrapped_key_len)
+ {
+#if defined(BOTAN_HAS_RFC3394_KEYWRAP)
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ const Botan::SymmetricKey kek_sym(kek, kek_len);
+ const Botan::secure_vector<uint8_t> key_pt(key, key + key_len);
+ const Botan::secure_vector<uint8_t> key_ct = Botan::rfc3394_keywrap(key_pt, kek_sym);
+ return write_vec_output(wrapped_key, wrapped_key_len, key_ct);
+ });
+#else
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+#endif
+ }
+
+int botan_key_unwrap3394(uint8_t wrapped_key[], size_t wrapped_key_len,
+ uint8_t kek[], size_t kek_len,
+ uint8_t key[], size_t* key_len)
+ {
+#if defined(BOTAN_HAS_RFC3394_KEYWRAP)
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ const Botan::SymmetricKey kek_sym(kek, kek_len);
+ const Botan::secure_vector<uint8_t> key_ct(wrapped_key, wrapped_key + wrapped_key_len);
+ const Botan::secure_vector<uint8_t> key_pt = Botan::rfc3394_keyunwrap(key_ct, kek_sym);
+ return write_vec_output(key, key_len, key_pt);
+ });
+#else
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+#endif
+ }
+
+}
diff --git a/src/lib/ffi/ffi_mac.cpp b/src/lib/ffi/ffi_mac.cpp
new file mode 100644
index 000000000..b3237592f
--- /dev/null
+++ b/src/lib/ffi/ffi_mac.cpp
@@ -0,0 +1,64 @@
+/*
+* (C) 2015,2017 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/ffi.h>
+#include <botan/internal/ffi_util.h>
+#include <botan/mac.h>
+
+extern "C" {
+
+using namespace Botan_FFI;
+
+BOTAN_FFI_DECLARE_STRUCT(botan_mac_struct, Botan::MessageAuthenticationCode, 0xA06E8FC1);
+
+int botan_mac_init(botan_mac_t* mac, const char* mac_name, uint32_t flags)
+ {
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ if(!mac || !mac_name || flags != 0)
+ return BOTAN_FFI_ERROR_NULL_POINTER;
+
+ std::unique_ptr<Botan::MessageAuthenticationCode> m =
+ Botan::MessageAuthenticationCode::create(mac_name);
+
+ if(m == nullptr)
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+
+ *mac = new botan_mac_struct(m.release());
+ return BOTAN_FFI_SUCCESS;
+ });
+ }
+
+int botan_mac_destroy(botan_mac_t mac)
+ {
+ return BOTAN_FFI_CHECKED_DELETE(mac);
+ }
+
+int botan_mac_set_key(botan_mac_t mac, const uint8_t* key, size_t key_len)
+ {
+ return BOTAN_FFI_DO(Botan::MessageAuthenticationCode, mac, m, { m.set_key(key, key_len); });
+ }
+
+int botan_mac_output_length(botan_mac_t mac, size_t* out)
+ {
+ return BOTAN_FFI_DO(Botan::MessageAuthenticationCode, mac, m, { *out = m.output_length(); });
+ }
+
+int botan_mac_clear(botan_mac_t mac)
+ {
+ return BOTAN_FFI_DO(Botan::MessageAuthenticationCode, mac, m, { m.clear(); });
+ }
+
+int botan_mac_update(botan_mac_t mac, const uint8_t* buf, size_t len)
+ {
+ return BOTAN_FFI_DO(Botan::MessageAuthenticationCode, mac, m, { m.update(buf, len); });
+ }
+
+int botan_mac_final(botan_mac_t mac, uint8_t out[])
+ {
+ return BOTAN_FFI_DO(Botan::MessageAuthenticationCode, mac, m, { m.final(out); });
+ }
+
+}
diff --git a/src/lib/ffi/ffi_mp.cpp b/src/lib/ffi/ffi_mp.cpp
new file mode 100644
index 000000000..00ad786ab
--- /dev/null
+++ b/src/lib/ffi/ffi_mp.cpp
@@ -0,0 +1,280 @@
+/*
+* (C) 2015,2017 Jack Lloyd
+* (C) 2017 Ribose Inc
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/ffi.h>
+#include <botan/internal/ffi_util.h>
+#include <botan/internal/ffi_rng.h>
+#include <botan/internal/ffi_mp.h>
+#include <botan/reducer.h>
+#include <botan/numthry.h>
+#include <botan/divide.h>
+
+extern "C" {
+
+using namespace Botan_FFI;
+
+int botan_mp_init(botan_mp_t* mp_out)
+ {
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ BOTAN_ASSERT_ARG_NON_NULL(mp_out);
+
+ *mp_out = new botan_mp_struct(new Botan::BigInt);
+ return BOTAN_FFI_SUCCESS;
+ });
+ }
+
+int botan_mp_clear(botan_mp_t mp)
+ {
+ return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { bn.clear(); });
+ }
+
+int botan_mp_set_from_int(botan_mp_t mp, int initial_value)
+ {
+ return BOTAN_FFI_DO(Botan::BigInt, mp, bn, {
+ if(initial_value >= 0)
+ {
+ bn = Botan::BigInt(static_cast<uint64_t>(initial_value));
+ }
+ else
+ {
+ bn = Botan::BigInt(static_cast<uint64_t>(-initial_value));
+ bn.flip_sign();
+ }
+ });
+ }
+
+int botan_mp_set_from_str(botan_mp_t mp, const char* str)
+ {
+ return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { bn = Botan::BigInt(str); });
+ }
+
+int botan_mp_set_from_radix_str(botan_mp_t mp, const char* str, size_t radix)
+ {
+ return BOTAN_FFI_DO(Botan::BigInt, mp, bn, {
+ Botan::BigInt::Base base;
+ if(radix == 10)
+ base = Botan::BigInt::Decimal;
+ else if(radix == 16)
+ base = Botan::BigInt::Hexadecimal;
+ else
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+
+ const uint8_t* bytes = reinterpret_cast<const uint8_t*>(str);
+ const size_t len = strlen(str);
+
+ bn = Botan::BigInt::decode(bytes, len, base);
+ });
+ }
+
+int botan_mp_set_from_mp(botan_mp_t dest, const botan_mp_t source)
+ {
+ return BOTAN_FFI_DO(Botan::BigInt, dest, bn, { bn = safe_get(source); });
+ }
+
+int botan_mp_is_negative(const botan_mp_t mp)
+ {
+ return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { return bn.is_negative() ? 1 : 0; });
+ }
+
+int botan_mp_is_positive(const botan_mp_t mp)
+ {
+ return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { return bn.is_positive() ? 1 : 0; });
+ }
+
+int botan_mp_flip_sign(botan_mp_t mp)
+ {
+ return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { bn.flip_sign(); });
+ }
+
+int botan_mp_from_bin(botan_mp_t mp, const uint8_t bin[], size_t bin_len)
+ {
+ return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { bn.binary_decode(bin, bin_len); });
+ }
+
+int botan_mp_to_hex(const botan_mp_t mp, char* out)
+ {
+ return BOTAN_FFI_DO(Botan::BigInt, mp, bn, {
+ std::vector<uint8_t> hex = Botan::BigInt::encode(bn, Botan::BigInt::Hexadecimal);
+ std::memcpy(out, hex.data(), hex.size());
+ out[hex.size()] = 0; // null terminate
+ });
+ }
+
+int botan_mp_to_str(const botan_mp_t mp, uint8_t digit_base, char* out, size_t* out_len)
+ {
+ return BOTAN_FFI_DO(Botan::BigInt, mp, bn, {
+ Botan::BigInt::Base base;
+ if(digit_base == 0 || digit_base == 10)
+ base = Botan::BigInt::Decimal;
+ else if(digit_base == 16)
+ base = Botan::BigInt::Hexadecimal;
+ else
+ throw FFI_Error("botan_mp_to_str invalid digit base");
+
+ std::vector<uint8_t> hex = Botan::BigInt::encode(bn, base);
+ hex.push_back(0); // null terminator
+ return write_str_output(out, out_len, hex);
+ });
+ }
+
+int botan_mp_to_bin(const botan_mp_t mp, uint8_t vec[])
+ {
+ return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { bn.binary_encode(vec); });
+ }
+
+int botan_mp_to_uint32(const botan_mp_t mp, uint32_t* val)
+ {
+ if(val == nullptr) {
+ return BOTAN_FFI_ERROR_NULL_POINTER;
+ }
+ return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { *val = bn.to_u32bit(); });
+ }
+
+int botan_mp_destroy(botan_mp_t mp)
+ {
+ return BOTAN_FFI_CHECKED_DELETE(mp);
+ }
+
+int botan_mp_add(botan_mp_t result, const botan_mp_t x, const botan_mp_t y)
+ {
+ return BOTAN_FFI_DO(Botan::BigInt, result, res, { res = safe_get(x) + safe_get(y); });
+ }
+
+int botan_mp_sub(botan_mp_t result, const botan_mp_t x, const botan_mp_t y)
+ {
+ return BOTAN_FFI_DO(Botan::BigInt, result, res, { res = safe_get(x) - safe_get(y); });
+ }
+
+int botan_mp_mul(botan_mp_t result, const botan_mp_t x, const botan_mp_t y)
+ {
+ return BOTAN_FFI_DO(Botan::BigInt, result, res, { res = safe_get(x) * safe_get(y); });
+ }
+
+int botan_mp_div(botan_mp_t quotient,
+ botan_mp_t remainder,
+ const botan_mp_t x, const botan_mp_t y)
+ {
+ return BOTAN_FFI_DO(Botan::BigInt, quotient, q, {
+ Botan::BigInt r;
+ Botan::divide(safe_get(x), safe_get(y), q, r);
+ safe_get(remainder) = r;
+ });
+ }
+
+int botan_mp_equal(const botan_mp_t x_w, const botan_mp_t y_w)
+ {
+ return BOTAN_FFI_DO(Botan::BigInt, x_w, x, { return x == safe_get(y_w); });
+ }
+
+int botan_mp_is_zero(const botan_mp_t mp)
+ {
+ return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { return bn.is_zero(); });
+ }
+
+int botan_mp_is_odd(const botan_mp_t mp)
+ {
+ return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { return bn.is_odd(); });
+ }
+
+int botan_mp_is_even(const botan_mp_t mp)
+ {
+ return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { return bn.is_even(); });
+ }
+
+int botan_mp_cmp(int* result, const botan_mp_t x_w, const botan_mp_t y_w)
+ {
+ return BOTAN_FFI_DO(Botan::BigInt, x_w, x, { *result = x.cmp(safe_get(y_w)); });
+ }
+
+int botan_mp_swap(botan_mp_t x_w, botan_mp_t y_w)
+ {
+ return BOTAN_FFI_DO(Botan::BigInt, x_w, x, { x.swap(safe_get(y_w)); });
+ }
+
+// Return (base^exponent) % modulus
+int botan_mp_powmod(botan_mp_t out, const botan_mp_t base, const botan_mp_t exponent, const botan_mp_t modulus)
+ {
+ return BOTAN_FFI_DO(Botan::BigInt, out, o,
+ { o = Botan::power_mod(safe_get(base), safe_get(exponent), safe_get(modulus)); });
+ }
+
+int botan_mp_lshift(botan_mp_t out, const botan_mp_t in, size_t shift)
+ {
+ return BOTAN_FFI_DO(Botan::BigInt, out, o, { o = safe_get(in) << shift; });
+ }
+
+int botan_mp_rshift(botan_mp_t out, const botan_mp_t in, size_t shift)
+ {
+ return BOTAN_FFI_DO(Botan::BigInt, out, o, { o = safe_get(in) >> shift; });
+ }
+
+int botan_mp_mod_inverse(botan_mp_t out, const botan_mp_t in, const botan_mp_t modulus)
+ {
+ return BOTAN_FFI_DO(Botan::BigInt, out, o, { o = Botan::inverse_mod(safe_get(in), safe_get(modulus)); });
+ }
+
+int botan_mp_mod_mul(botan_mp_t out, const botan_mp_t x, const botan_mp_t y, const botan_mp_t modulus)
+ {
+ return BOTAN_FFI_DO(Botan::BigInt, out, o, {
+ Botan::Modular_Reducer reducer(safe_get(modulus));
+ o = reducer.multiply(safe_get(x), safe_get(y));
+ });
+ }
+
+int botan_mp_rand_bits(botan_mp_t rand_out, botan_rng_t rng, size_t bits)
+ {
+ return BOTAN_FFI_DO(Botan::RandomNumberGenerator, rng, r, {
+ safe_get(rand_out).randomize(r, bits); });
+ }
+
+int botan_mp_rand_range(botan_mp_t rand_out,
+ botan_rng_t rng,
+ const botan_mp_t lower,
+ const botan_mp_t upper)
+ {
+ return BOTAN_FFI_DO(Botan::RandomNumberGenerator, rng, r, {
+ safe_get(rand_out) = Botan::BigInt::random_integer(r, safe_get(lower), safe_get(upper)); });
+ }
+
+int botan_mp_gcd(botan_mp_t out, const botan_mp_t x, const botan_mp_t y)
+ {
+ return BOTAN_FFI_DO(Botan::BigInt, out, o, {
+ o = Botan::gcd(safe_get(x), safe_get(y)); });
+ }
+
+int botan_mp_is_prime(const botan_mp_t mp, botan_rng_t rng, size_t test_prob)
+ {
+ return BOTAN_FFI_DO(Botan::BigInt, mp, n,
+ { return (Botan::is_prime(n, safe_get(rng), test_prob)) ? 1 : 0; });
+ }
+
+int botan_mp_get_bit(const botan_mp_t mp, size_t bit)
+ {
+ return BOTAN_FFI_DO(Botan::BigInt, mp, n, { return (n.get_bit(bit)); });
+ }
+
+int botan_mp_set_bit(botan_mp_t mp, size_t bit)
+ {
+ return BOTAN_FFI_DO(Botan::BigInt, mp, n, { n.set_bit(bit); });
+ }
+
+int botan_mp_clear_bit(botan_mp_t mp, size_t bit)
+ {
+ return BOTAN_FFI_DO(Botan::BigInt, mp, n, { n.clear_bit(bit); });
+ }
+
+int botan_mp_num_bits(const botan_mp_t mp, size_t* bits)
+ {
+ return BOTAN_FFI_DO(Botan::BigInt, mp, n, { *bits = n.bits(); });
+ }
+
+int botan_mp_num_bytes(const botan_mp_t mp, size_t* bytes)
+ {
+ return BOTAN_FFI_DO(Botan::BigInt, mp, n, { *bytes = n.bytes(); });
+ }
+
+}
diff --git a/src/lib/ffi/ffi_mp.h b/src/lib/ffi/ffi_mp.h
new file mode 100644
index 000000000..fb2e2dee5
--- /dev/null
+++ b/src/lib/ffi/ffi_mp.h
@@ -0,0 +1,21 @@
+/*
+* (C) 2017 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_FFI_MP_H__
+#define BOTAN_FFI_MP_H__
+
+#include <botan/bigint.h>
+#include <botan/internal/ffi_util.h>
+
+extern "C" {
+
+using namespace Botan_FFI;
+
+BOTAN_FFI_DECLARE_STRUCT(botan_mp_struct, Botan::BigInt, 0xC828B9D2);
+
+}
+
+#endif
diff --git a/src/lib/ffi/ffi_pk_op.cpp b/src/lib/ffi/ffi_pk_op.cpp
new file mode 100644
index 000000000..d0ac8e3c7
--- /dev/null
+++ b/src/lib/ffi/ffi_pk_op.cpp
@@ -0,0 +1,216 @@
+/*
+* (C) 2015,2017 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/ffi.h>
+#include <botan/internal/ffi_util.h>
+#include <botan/internal/ffi_pkey.h>
+#include <botan/internal/ffi_rng.h>
+#include <botan/pubkey.h>
+
+extern "C" {
+
+using namespace Botan_FFI;
+
+BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_encrypt_struct, Botan::PK_Encryptor, 0x891F3FC3);
+BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_decrypt_struct, Botan::PK_Decryptor, 0x912F3C37);
+BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_sign_struct, Botan::PK_Signer, 0x1AF0C39F);
+BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_verify_struct, Botan::PK_Verifier, 0x2B91F936);
+BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_ka_struct, Botan::PK_Key_Agreement, 0x2939CAB1);
+
+int botan_pk_op_encrypt_create(botan_pk_op_encrypt_t* op,
+ botan_pubkey_t key_obj,
+ const char* padding,
+ uint32_t flags)
+ {
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ BOTAN_ASSERT_NONNULL(op);
+
+ *op = nullptr;
+
+ if(flags != 0)
+ return BOTAN_FFI_ERROR_BAD_FLAG;
+
+ std::unique_ptr<Botan::PK_Encryptor> pk(new Botan::PK_Encryptor_EME(safe_get(key_obj), Botan::system_rng(), padding));
+ *op = new botan_pk_op_encrypt_struct(pk.release());
+ return BOTAN_FFI_SUCCESS;
+ });
+ }
+
+int botan_pk_op_encrypt_destroy(botan_pk_op_encrypt_t op)
+ {
+ return BOTAN_FFI_CHECKED_DELETE(op);
+ }
+
+int botan_pk_op_encrypt(botan_pk_op_encrypt_t op,
+ botan_rng_t rng_obj,
+ uint8_t out[], size_t* out_len,
+ const uint8_t plaintext[], size_t plaintext_len)
+ {
+ return BOTAN_FFI_DO(Botan::PK_Encryptor, op, o, {
+ return write_vec_output(out, out_len, o.encrypt(plaintext, plaintext_len, safe_get(rng_obj)));
+ });
+ }
+
+/*
+* Public Key Decryption
+*/
+int botan_pk_op_decrypt_create(botan_pk_op_decrypt_t* op,
+ botan_privkey_t key_obj,
+ const char* padding,
+ uint32_t flags)
+ {
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ BOTAN_ASSERT_NONNULL(op);
+
+ *op = nullptr;
+
+ if(flags != 0)
+ return BOTAN_FFI_ERROR_BAD_FLAG;
+
+ std::unique_ptr<Botan::PK_Decryptor> pk(new Botan::PK_Decryptor_EME(safe_get(key_obj), Botan::system_rng(), padding));
+ *op = new botan_pk_op_decrypt_struct(pk.release());
+ return BOTAN_FFI_SUCCESS;
+ });
+ }
+
+int botan_pk_op_decrypt_destroy(botan_pk_op_decrypt_t op)
+ {
+ return BOTAN_FFI_CHECKED_DELETE(op);
+ }
+
+int botan_pk_op_decrypt(botan_pk_op_decrypt_t op,
+ uint8_t out[], size_t* out_len,
+ const uint8_t ciphertext[], size_t ciphertext_len)
+ {
+ return BOTAN_FFI_DO(Botan::PK_Decryptor, op, o, {
+ return write_vec_output(out, out_len, o.decrypt(ciphertext, ciphertext_len));
+ });
+ }
+
+/*
+* Signature Generation
+*/
+int botan_pk_op_sign_create(botan_pk_op_sign_t* op,
+ botan_privkey_t key_obj,
+ const char* hash,
+ uint32_t flags)
+ {
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ BOTAN_ASSERT_NONNULL(op);
+
+ *op = nullptr;
+
+ if(flags != 0)
+ return BOTAN_FFI_ERROR_BAD_FLAG;
+
+ std::unique_ptr<Botan::PK_Signer> pk(new Botan::PK_Signer(safe_get(key_obj),Botan::system_rng(), hash));
+ *op = new botan_pk_op_sign_struct(pk.release());
+ return BOTAN_FFI_SUCCESS;
+ });
+ }
+
+int botan_pk_op_sign_destroy(botan_pk_op_sign_t op)
+ {
+ return BOTAN_FFI_CHECKED_DELETE(op);
+ }
+
+int botan_pk_op_sign_update(botan_pk_op_sign_t op, const uint8_t in[], size_t in_len)
+ {
+ return BOTAN_FFI_DO(Botan::PK_Signer, op, o, { o.update(in, in_len); });
+ }
+
+int botan_pk_op_sign_finish(botan_pk_op_sign_t op, botan_rng_t rng_obj, uint8_t out[], size_t* out_len)
+ {
+ return BOTAN_FFI_DO(Botan::PK_Signer, op, o, {
+ return write_vec_output(out, out_len, o.signature(safe_get(rng_obj)));
+ });
+ }
+
+int botan_pk_op_verify_create(botan_pk_op_verify_t* op,
+ botan_pubkey_t key_obj,
+ const char* hash,
+ uint32_t flags)
+ {
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ BOTAN_ASSERT_NONNULL(op);
+
+ if(flags != 0)
+ return BOTAN_FFI_ERROR_BAD_FLAG;
+
+ std::unique_ptr<Botan::PK_Verifier> pk(new Botan::PK_Verifier(safe_get(key_obj), hash));
+ *op = new botan_pk_op_verify_struct(pk.release());
+ return BOTAN_FFI_SUCCESS;
+ });
+ }
+
+int botan_pk_op_verify_destroy(botan_pk_op_verify_t op)
+ {
+ return BOTAN_FFI_CHECKED_DELETE(op);
+ }
+
+int botan_pk_op_verify_update(botan_pk_op_verify_t op, const uint8_t in[], size_t in_len)
+ {
+ return BOTAN_FFI_DO(Botan::PK_Verifier, op, o, { o.update(in, in_len); });
+ }
+
+int botan_pk_op_verify_finish(botan_pk_op_verify_t op, const uint8_t sig[], size_t sig_len)
+ {
+ return BOTAN_FFI_DO(Botan::PK_Verifier, op, o, {
+ const bool legit = o.check_signature(sig, sig_len);
+
+ if(legit)
+ return BOTAN_FFI_SUCCESS;
+ else
+ return BOTAN_FFI_ERROR_INVALID_INPUT;
+ });
+ }
+
+int botan_pk_op_key_agreement_create(botan_pk_op_ka_t* op,
+ botan_privkey_t key_obj,
+ const char* kdf,
+ uint32_t flags)
+ {
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ BOTAN_ASSERT_NONNULL(op);
+
+ *op = nullptr;
+
+ if(flags != 0)
+ return BOTAN_FFI_ERROR_BAD_FLAG;
+
+ std::unique_ptr<Botan::PK_Key_Agreement> pk(new Botan::PK_Key_Agreement(safe_get(key_obj), Botan::system_rng(), kdf));
+ *op = new botan_pk_op_ka_struct(pk.release());
+ return BOTAN_FFI_SUCCESS;
+ });
+ }
+
+int botan_pk_op_key_agreement_destroy(botan_pk_op_ka_t op)
+ {
+ return BOTAN_FFI_CHECKED_DELETE(op);
+ }
+
+int botan_pk_op_key_agreement_export_public(botan_privkey_t key,
+ uint8_t out[], size_t* out_len)
+ {
+ return BOTAN_FFI_DO(Botan::Private_Key, key, k, {
+ if(auto kak = dynamic_cast<const Botan::PK_Key_Agreement_Key*>(&k))
+ return write_vec_output(out, out_len, kak->public_value());
+ return BOTAN_FFI_ERROR_BAD_FLAG;
+ });
+ }
+
+int botan_pk_op_key_agreement(botan_pk_op_ka_t op,
+ uint8_t out[], size_t* out_len,
+ const uint8_t other_key[], size_t other_key_len,
+ const uint8_t salt[], size_t salt_len)
+ {
+ return BOTAN_FFI_DO(Botan::PK_Key_Agreement, op, o, {
+ auto k = o.derive_key(*out_len, other_key, other_key_len, salt, salt_len).bits_of();
+ return write_vec_output(out, out_len, k);
+ });
+ }
+
+}
diff --git a/src/lib/ffi/ffi_pkey.cpp b/src/lib/ffi/ffi_pkey.cpp
new file mode 100644
index 000000000..1577118b1
--- /dev/null
+++ b/src/lib/ffi/ffi_pkey.cpp
@@ -0,0 +1,263 @@
+/*
+* (C) 2015,2017 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/ffi.h>
+#include <botan/internal/ffi_util.h>
+#include <botan/internal/ffi_pkey.h>
+#include <botan/internal/ffi_rng.h>
+#include <botan/hash.h>
+#include <botan/pkcs8.h>
+#include <botan/x509_key.h>
+#include <botan/pk_algs.h>
+
+#if defined(BOTAN_HAS_HASH_ID)
+ #include <botan/hash_id.h>
+#endif
+
+extern "C" {
+
+int botan_privkey_create(botan_privkey_t* key_obj,
+ const char* algo_name,
+ const char* algo_params,
+ botan_rng_t rng_obj)
+ {
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ if(key_obj == nullptr)
+ return BOTAN_FFI_ERROR_NULL_POINTER;
+
+ *key_obj = nullptr;
+ if(rng_obj == nullptr)
+ return BOTAN_FFI_ERROR_NULL_POINTER;
+
+ Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
+ std::unique_ptr<Botan::Private_Key> key(
+ Botan::create_private_key(algo_name ? algo_name : "RSA",
+ rng,
+ algo_params ? algo_params : ""));
+
+ if(key)
+ {
+ *key_obj = new botan_privkey_struct(key.release());
+ return BOTAN_FFI_SUCCESS;
+ }
+ else
+ {
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+ }
+ });
+ }
+
+int botan_privkey_load(botan_privkey_t* key, botan_rng_t rng_obj,
+ const uint8_t bits[], size_t len,
+ const char* password)
+ {
+ *key = nullptr;
+
+ if(password == nullptr)
+ password = "";
+
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ Botan::DataSource_Memory src(bits, len);
+
+ Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
+
+ std::unique_ptr<Botan::PKCS8_PrivateKey> pkcs8(
+ Botan::PKCS8::load_key(src, rng, static_cast<std::string>(password)));
+
+ if(pkcs8)
+ {
+ *key = new botan_privkey_struct(pkcs8.release());
+ return BOTAN_FFI_SUCCESS;
+ }
+ return BOTAN_FFI_ERROR_UNKNOWN_ERROR;
+ });
+ }
+
+int botan_privkey_destroy(botan_privkey_t key)
+ {
+ return BOTAN_FFI_CHECKED_DELETE(key);
+ }
+
+int botan_pubkey_load(botan_pubkey_t* key,
+ const uint8_t bits[], size_t bits_len)
+ {
+ *key = nullptr;
+
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ Botan::DataSource_Memory src(bits, bits_len);
+ std::unique_ptr<Botan::Public_Key> pubkey(Botan::X509::load_key(src));
+
+ if(pubkey == nullptr)
+ return BOTAN_FFI_ERROR_UNKNOWN_ERROR;
+
+ *key = new botan_pubkey_struct(pubkey.release());
+ return BOTAN_FFI_SUCCESS;
+ });
+ }
+
+int botan_pubkey_destroy(botan_pubkey_t key)
+ {
+ return BOTAN_FFI_CHECKED_DELETE(key);
+ }
+
+int botan_privkey_export_pubkey(botan_pubkey_t* pubout, botan_privkey_t key_obj)
+ {
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ std::unique_ptr<Botan::Public_Key>
+ pubkey(Botan::X509::load_key(Botan::X509::BER_encode(safe_get(key_obj))));
+
+ *pubout = new botan_pubkey_struct(pubkey.release());
+ return BOTAN_FFI_SUCCESS;
+ });
+ }
+
+int botan_pubkey_algo_name(botan_pubkey_t key, char out[], size_t* out_len)
+ {
+ return BOTAN_FFI_DO(Botan::Public_Key, key, k, { return write_str_output(out, out_len, k.algo_name()); });
+ }
+
+int botan_pubkey_check_key(botan_pubkey_t key, botan_rng_t rng, uint32_t flags)
+ {
+ const bool strong = (flags & BOTAN_CHECK_KEY_EXPENSIVE_TESTS);
+
+ return BOTAN_FFI_DO(Botan::Public_Key, key, k,
+ { return (k.check_key(safe_get(rng), strong) == true) ? 0 : -1; });
+ }
+
+int botan_privkey_check_key(botan_privkey_t key, botan_rng_t rng, uint32_t flags)
+ {
+ const bool strong = (flags & BOTAN_CHECK_KEY_EXPENSIVE_TESTS);
+ return BOTAN_FFI_DO(Botan::Private_Key, key, k,
+ { return (k.check_key(safe_get(rng), strong) == true) ? 0 : -1; });
+ }
+
+int botan_pubkey_export(botan_pubkey_t key, uint8_t out[], size_t* out_len, uint32_t flags)
+ {
+ return BOTAN_FFI_DO(Botan::Public_Key, key, k, {
+ if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER)
+ return write_vec_output(out, out_len, Botan::X509::BER_encode(k));
+ else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM)
+ return write_str_output(out, out_len, Botan::X509::PEM_encode(k));
+ else
+ return BOTAN_FFI_ERROR_BAD_FLAG;
+ });
+ }
+
+int botan_privkey_export(botan_privkey_t key, uint8_t out[], size_t* out_len, uint32_t flags)
+ {
+ return BOTAN_FFI_DO(Botan::Private_Key, key, k, {
+ if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER)
+ return write_vec_output(out, out_len, Botan::PKCS8::BER_encode(k));
+ else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM)
+ return write_str_output(out, out_len, Botan::PKCS8::PEM_encode(k));
+ else
+ return BOTAN_FFI_ERROR_BAD_FLAG;
+ });
+ }
+
+int botan_privkey_export_encrypted(botan_privkey_t key,
+ uint8_t out[], size_t* out_len,
+ botan_rng_t rng_obj,
+ const char* pass,
+ const char* /*ignored - pbe*/,
+ uint32_t flags)
+ {
+ return botan_privkey_export_encrypted_pbkdf_iter(key, out, out_len, rng_obj, pass, 100000, nullptr, nullptr, flags);
+ }
+
+int botan_privkey_export_encrypted_pbkdf_msec(botan_privkey_t key,
+ uint8_t out[], size_t* out_len,
+ botan_rng_t rng_obj,
+ const char* pass,
+ uint32_t pbkdf_msec,
+ size_t* pbkdf_iters_out,
+ const char* maybe_cipher,
+ const char* maybe_pbkdf_hash,
+ uint32_t flags)
+ {
+ return BOTAN_FFI_DO(Botan::Private_Key, key, k, {
+ const std::chrono::milliseconds pbkdf_time(pbkdf_msec);
+ Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
+
+ const std::string cipher = (maybe_cipher ? maybe_cipher : "");
+ const std::string pbkdf_hash = (maybe_pbkdf_hash ? maybe_pbkdf_hash : "");
+
+ if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER)
+ {
+ return write_vec_output(out, out_len,
+ Botan::PKCS8::BER_encode_encrypted_pbkdf_msec(k, rng, pass, pbkdf_time, pbkdf_iters_out, cipher, pbkdf_hash));
+ }
+ else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM)
+ {
+ return write_str_output(out, out_len,
+ Botan::PKCS8::PEM_encode_encrypted_pbkdf_msec(k, rng, pass, pbkdf_time, pbkdf_iters_out, cipher, pbkdf_hash));
+ }
+ else
+ {
+ return -2;
+ }
+ });
+ }
+
+int botan_privkey_export_encrypted_pbkdf_iter(botan_privkey_t key,
+ uint8_t out[], size_t* out_len,
+ botan_rng_t rng_obj,
+ const char* pass,
+ size_t pbkdf_iter,
+ const char* maybe_cipher,
+ const char* maybe_pbkdf_hash,
+ uint32_t flags)
+ {
+ return BOTAN_FFI_DO(Botan::Private_Key, key, k, {
+ Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
+
+ const std::string cipher = (maybe_cipher ? maybe_cipher : "");
+ const std::string pbkdf_hash = (maybe_pbkdf_hash ? maybe_pbkdf_hash : "");
+
+ if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER)
+ {
+ return write_vec_output(out, out_len,
+ Botan::PKCS8::BER_encode_encrypted_pbkdf_iter(k, rng, pass, pbkdf_iter, cipher, pbkdf_hash));
+ }
+ else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM)
+ {
+ return write_str_output(out, out_len,
+ Botan::PKCS8::PEM_encode_encrypted_pbkdf_iter(k, rng, pass, pbkdf_iter, cipher, pbkdf_hash));
+ }
+ else
+ {
+ return -2;
+ }
+ });
+ }
+
+int botan_pubkey_estimated_strength(botan_pubkey_t key, size_t* estimate)
+ {
+ return BOTAN_FFI_DO(Botan::Public_Key, key, k, { *estimate = k.estimated_strength(); });
+ }
+
+int botan_pubkey_fingerprint(botan_pubkey_t key, const char* hash_fn,
+ uint8_t out[], size_t* out_len)
+ {
+ return BOTAN_FFI_DO(Botan::Public_Key, key, k, {
+ std::unique_ptr<Botan::HashFunction> h(Botan::HashFunction::create(hash_fn));
+ return write_vec_output(out, out_len, h->process(k.public_key_bits()));
+ });
+ }
+
+int botan_pkcs_hash_id(const char* hash_name, uint8_t pkcs_id[], size_t* pkcs_id_len)
+ {
+#if defined(BOTAN_HAS_HASH_ID)
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ const std::vector<uint8_t> hash_id = Botan::pkcs_hash_id(hash_name);
+ return write_output(pkcs_id, pkcs_id_len, hash_id.data(), hash_id.size());
+ });
+#else
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+#endif
+ }
+
+}
diff --git a/src/lib/ffi/ffi_pkey.h b/src/lib/ffi/ffi_pkey.h
new file mode 100644
index 000000000..536e5fc29
--- /dev/null
+++ b/src/lib/ffi/ffi_pkey.h
@@ -0,0 +1,22 @@
+/*
+* (C) 2017 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_FFI_PKEY_H__
+#define BOTAN_FFI_PKEY_H__
+
+#include <botan/pk_keys.h>
+#include <botan/internal/ffi_util.h>
+
+extern "C" {
+
+using namespace Botan_FFI;
+
+BOTAN_FFI_DECLARE_STRUCT(botan_pubkey_struct, Botan::Public_Key, 0x2C286519);
+BOTAN_FFI_DECLARE_STRUCT(botan_privkey_struct, Botan::Private_Key, 0x7F96385E);
+
+}
+
+#endif
diff --git a/src/lib/ffi/ffi_pkey_algs.cpp b/src/lib/ffi/ffi_pkey_algs.cpp
new file mode 100644
index 000000000..8cb9b785e
--- /dev/null
+++ b/src/lib/ffi/ffi_pkey_algs.cpp
@@ -0,0 +1,757 @@
+/*
+* (C) 2015,2017 Jack Lloyd
+* (C) 2017 Ribose Inc
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/ffi.h>
+#include <botan/internal/ffi_util.h>
+#include <botan/internal/ffi_pkey.h>
+#include <botan/internal/ffi_rng.h>
+#include <botan/internal/ffi_mp.h>
+
+#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO)
+ #include <botan/ecc_key.h>
+#endif
+
+#if defined(BOTAN_HAS_DL_PUBLIC_KEY_FAMILY)
+ #include <botan/dl_algo.h>
+#endif
+
+#if defined(BOTAN_HAS_RSA)
+ #include <botan/rsa.h>
+#endif
+
+#if defined(BOTAN_HAS_ELGAMAL)
+ #include <botan/elgamal.h>
+#endif
+
+#if defined(BOTAN_HAS_DSA)
+ #include <botan/dsa.h>
+#endif
+
+#if defined(BOTAN_HAS_ECDSA)
+ #include <botan/ecdsa.h>
+#endif
+
+#if defined(BOTAN_HAS_SM2)
+ #include <botan/sm2.h>
+#endif
+
+#if defined(BOTAN_HAS_ECDH)
+ #include <botan/ecdh.h>
+#endif
+
+#if defined(BOTAN_HAS_CURVE_25519)
+ #include <botan/curve25519.h>
+#endif
+
+#if defined(BOTAN_HAS_ED25519)
+ #include <botan/ed25519.h>
+#endif
+
+#if defined(BOTAN_HAS_MCELIECE)
+ #include <botan/mceliece.h>
+#endif
+
+#if defined(BOTAN_HAS_MCEIES)
+ #include <botan/mceies.h>
+#endif
+
+namespace {
+
+#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO)
+
+// These are always called within an existing try/catch block
+
+template<class ECPrivateKey_t>
+int privkey_load_ec(std::unique_ptr<ECPrivateKey_t>& key,
+ const Botan::BigInt& scalar,
+ const char* curve_name)
+ {
+ if(curve_name == nullptr)
+ return BOTAN_FFI_ERROR_NULL_POINTER;
+
+ Botan::Null_RNG null_rng;
+ Botan::EC_Group grp(curve_name);
+ key.reset(new ECPrivateKey_t(null_rng, grp, scalar));
+ return BOTAN_FFI_SUCCESS;
+ }
+
+template<class ECPublicKey_t>
+int pubkey_load_ec(std::unique_ptr<ECPublicKey_t>& key,
+ const Botan::BigInt& public_x,
+ const Botan::BigInt& public_y,
+ const char* curve_name)
+ {
+ if(curve_name == nullptr)
+ return BOTAN_FFI_ERROR_NULL_POINTER;
+
+ Botan::Null_RNG null_rng;
+ Botan::EC_Group grp(curve_name);
+ Botan::PointGFp uncompressed_point(grp.get_curve(), public_x, public_y);
+ key.reset(new ECPublicKey_t(grp, uncompressed_point));
+ return BOTAN_FFI_SUCCESS;
+ }
+
+#endif
+
+Botan::BigInt pubkey_get_field(const Botan::Public_Key& key,
+ const std::string& field)
+ {
+ // Maybe this should be `return key.get_integer_field(field_name)`?
+
+#if defined(BOTAN_HAS_RSA)
+ if(const Botan::RSA_PublicKey* rsa = dynamic_cast<const Botan::RSA_PublicKey*>(&key))
+ {
+ if(field == "n")
+ return rsa->get_n();
+ else if(field == "e")
+ return rsa->get_e();
+ else
+ throw Botan::Exception("Field not supported");
+ }
+#endif
+
+#if defined(BOTAN_HAS_DL_PUBLIC_KEY_FAMILY)
+ // Handles DSA, ElGamal, etc
+ if(const Botan::DL_Scheme_PublicKey* dl = dynamic_cast<const Botan::DL_Scheme_PublicKey*>(&key))
+ {
+ if(field == "p")
+ return dl->group_p();
+ else if(field == "q")
+ return dl->group_q();
+ else if(field == "g")
+ return dl->group_g();
+ else if(field == "y")
+ return dl->get_y();
+ else
+ throw Botan::Exception("Field not supported");
+ }
+#endif
+
+#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO)
+ if(const Botan::EC_PublicKey* ecc = dynamic_cast<const Botan::EC_PublicKey*>(&key))
+ {
+ if(field == "public_x")
+ return ecc->public_point().get_affine_x();
+ else if(field == "public_y")
+ return ecc->public_point().get_affine_y();
+ else if(field == "base_x")
+ return ecc->domain().get_base_point().get_affine_x();
+ else if(field == "base_y")
+ return ecc->domain().get_base_point().get_affine_y();
+ else if(field == "p")
+ return ecc->domain().get_curve().get_p();
+ else if(field == "a")
+ return ecc->domain().get_curve().get_a();
+ else if(field == "b")
+ return ecc->domain().get_curve().get_b();
+ else if(field == "cofactor")
+ return ecc->domain().get_cofactor();
+ else if(field == "order")
+ return ecc->domain().get_order();
+ else
+ throw Botan::Exception("Field not supported");
+ }
+#endif
+
+ // Some other algorithm type not supported by this function
+ throw Botan::Exception("Unsupported algorithm type for botan_pubkey_get_field");
+ }
+
+Botan::BigInt privkey_get_field(const Botan::Private_Key& key,
+ const std::string& field)
+ {
+ //return key.get_integer_field(field);
+
+#if defined(BOTAN_HAS_RSA)
+
+ if(const Botan::RSA_PrivateKey* rsa = dynamic_cast<const Botan::RSA_PrivateKey*>(&key))
+ {
+ if(field == "p")
+ return rsa->get_p();
+ else if(field == "q")
+ return rsa->get_q();
+ else if(field == "d")
+ return rsa->get_d();
+ else if(field == "c")
+ return rsa->get_c();
+ else if(field == "d1")
+ return rsa->get_d1();
+ else if(field == "d2")
+ return rsa->get_d2();
+ else
+ return pubkey_get_field(key, field);
+ }
+#endif
+
+#if defined(BOTAN_HAS_DL_PUBLIC_KEY_FAMILY)
+ // Handles DSA, ElGamal, etc
+ if(const Botan::DL_Scheme_PrivateKey* dl = dynamic_cast<const Botan::DL_Scheme_PrivateKey*>(&key))
+ {
+ if(field == "x")
+ return dl->get_x();
+ else
+ return pubkey_get_field(key, field);
+ }
+#endif
+
+#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO)
+ if(const Botan::EC_PrivateKey* ecc = dynamic_cast<const Botan::EC_PrivateKey*>(&key))
+ {
+ if(field == "x")
+ return ecc->private_value();
+ else
+ return pubkey_get_field(key, field);
+ }
+#endif
+
+ // Some other algorithm type not supported by this function
+ throw Botan::Exception("Unsupported algorithm type for botan_privkey_get_field");
+ }
+
+}
+
+extern "C" {
+
+using namespace Botan_FFI;
+
+int botan_pubkey_get_field(botan_mp_t output,
+ botan_pubkey_t key,
+ const char* field_name_cstr)
+ {
+ if(field_name_cstr == nullptr)
+ return BOTAN_FFI_ERROR_NULL_POINTER;
+
+ const std::string field_name(field_name_cstr);
+
+ return BOTAN_FFI_DO(Botan::Public_Key, key, k, {
+ safe_get(output) = pubkey_get_field(k, field_name);
+ });
+ }
+
+int botan_privkey_get_field(botan_mp_t output,
+ botan_privkey_t key,
+ const char* field_name_cstr)
+ {
+ if(field_name_cstr == nullptr)
+ return BOTAN_FFI_ERROR_NULL_POINTER;
+
+ const std::string field_name(field_name_cstr);
+
+ return BOTAN_FFI_DO(Botan::Private_Key, key, k, {
+ safe_get(output) = privkey_get_field(k, field_name);
+ });
+ }
+
+/* RSA specific operations */
+
+int botan_privkey_create_rsa(botan_privkey_t* key_obj, botan_rng_t rng_obj, size_t n_bits)
+ {
+#if defined(BOTAN_HAS_RSA)
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ if(key_obj == nullptr || rng_obj == nullptr)
+ return BOTAN_FFI_ERROR_NULL_POINTER;
+ if(n_bits < 1024 || n_bits > 16*1024)
+ return BOTAN_FFI_ERROR_BAD_PARAMETER;
+
+ *key_obj = nullptr;
+
+ Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
+ std::unique_ptr<Botan::Private_Key> key(new Botan::RSA_PrivateKey(rng, n_bits));
+ *key_obj = new botan_privkey_struct(key.release());
+ return BOTAN_FFI_SUCCESS;
+ });
+#else
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+#endif
+ }
+
+int botan_privkey_load_rsa(botan_privkey_t* key,
+ botan_mp_t rsa_p, botan_mp_t rsa_q, botan_mp_t rsa_e)
+ {
+#if defined(BOTAN_HAS_RSA)
+ *key = nullptr;
+
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ *key = new botan_privkey_struct(new Botan::RSA_PrivateKey(safe_get(rsa_p),
+ safe_get(rsa_q),
+ safe_get(rsa_e)));
+ return BOTAN_FFI_SUCCESS;
+ });
+#else
+ BOTAN_UNUSED(key, rsa_p, rsa_q, rsa_e);
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+#endif
+ }
+
+int botan_pubkey_load_rsa(botan_pubkey_t* key,
+ botan_mp_t n, botan_mp_t e)
+ {
+#if defined(BOTAN_HAS_RSA)
+ *key = nullptr;
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ *key = new botan_pubkey_struct(new Botan::RSA_PublicKey(safe_get(n), safe_get(e)));
+ return BOTAN_FFI_SUCCESS;
+ });
+#else
+ BOTAN_UNUSED(key, n, e);
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+#endif
+ }
+
+int botan_privkey_rsa_get_p(botan_mp_t p, botan_privkey_t key)
+ {
+ return botan_privkey_get_field(p, key, "p");
+ }
+
+int botan_privkey_rsa_get_q(botan_mp_t q, botan_privkey_t key)
+ {
+ return botan_privkey_get_field(q, key, "q");
+ }
+
+int botan_privkey_rsa_get_n(botan_mp_t n, botan_privkey_t key)
+ {
+ return botan_privkey_get_field(n, key, "n");
+ }
+
+int botan_privkey_rsa_get_e(botan_mp_t e, botan_privkey_t key)
+ {
+ return botan_privkey_get_field(e, key, "e");
+ }
+
+int botan_privkey_rsa_get_d(botan_mp_t d, botan_privkey_t key)
+ {
+ return botan_privkey_get_field(d, key, "d");
+ }
+
+int botan_pubkey_rsa_get_e(botan_mp_t e, botan_pubkey_t key)
+ {
+ return botan_pubkey_get_field(e, key, "e");
+ }
+
+int botan_pubkey_rsa_get_n(botan_mp_t n, botan_pubkey_t key)
+ {
+ return botan_pubkey_get_field(n, key, "n");
+ }
+
+/* DSA specific operations */
+
+int botan_privkey_load_dsa(botan_privkey_t* key,
+ botan_mp_t p, botan_mp_t q, botan_mp_t g, botan_mp_t x)
+ {
+#if defined(BOTAN_HAS_DSA)
+ *key = nullptr;
+
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ Botan::Null_RNG null_rng;
+ Botan::DL_Group group(safe_get(p), safe_get(q), safe_get(g));
+ *key = new botan_privkey_struct(new Botan::DSA_PrivateKey(null_rng, group, safe_get(x)));
+ return BOTAN_FFI_SUCCESS;
+ });
+#else
+ BOTAN_UNUSED(key, p, q, g, x);
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+#endif
+ }
+
+int botan_pubkey_load_dsa(botan_pubkey_t* key,
+ botan_mp_t p, botan_mp_t q, botan_mp_t g, botan_mp_t y)
+ {
+#if defined(BOTAN_HAS_DSA)
+ *key = nullptr;
+
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ Botan::DL_Group group(safe_get(p), safe_get(q), safe_get(g));
+ *key = new botan_pubkey_struct(new Botan::DSA_PublicKey(group, safe_get(y)));
+ return BOTAN_FFI_SUCCESS;
+ });
+#else
+ BOTAN_UNUSED(key, p, q, g, y);
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+#endif
+ }
+
+int botan_privkey_dsa_get_x(botan_mp_t x, botan_privkey_t key)
+ {
+ return botan_privkey_get_field(x, key, "x");
+ }
+
+int botan_pubkey_dsa_get_p(botan_mp_t p, botan_pubkey_t key)
+ {
+ return botan_pubkey_get_field(p, key, "p");
+ }
+
+int botan_pubkey_dsa_get_q(botan_mp_t q, botan_pubkey_t key)
+ {
+ return botan_pubkey_get_field(q, key, "q");
+ }
+
+int botan_pubkey_dsa_get_g(botan_mp_t g, botan_pubkey_t key)
+ {
+ return botan_pubkey_get_field(g, key, "g");
+ }
+
+int botan_pubkey_dsa_get_y(botan_mp_t y, botan_pubkey_t key)
+ {
+ return botan_pubkey_get_field(y, key, "y");
+ }
+
+int botan_privkey_create_ecdsa(botan_privkey_t* key_obj, botan_rng_t rng_obj, const char* param_str)
+ {
+#if defined(BOTAN_HAS_ECDSA)
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ if(key_obj == nullptr || rng_obj == nullptr || param_str == nullptr || *param_str == 0)
+ return BOTAN_FFI_ERROR_NULL_POINTER;
+
+ *key_obj = nullptr;
+
+ Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
+ Botan::EC_Group grp(param_str);
+ std::unique_ptr<Botan::Private_Key> key(new Botan::ECDSA_PrivateKey(rng, grp));
+ *key_obj = new botan_privkey_struct(key.release());
+ return BOTAN_FFI_SUCCESS;
+ });
+#else
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+#endif
+ }
+
+/* ECDSA specific operations */
+
+int botan_pubkey_load_ecdsa(botan_pubkey_t* key,
+ const botan_mp_t public_x,
+ const botan_mp_t public_y,
+ const char* curve_name)
+ {
+#if defined(BOTAN_HAS_ECDSA)
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ std::unique_ptr<Botan::ECDSA_PublicKey> p_key;
+
+ int rc = pubkey_load_ec(p_key, safe_get(public_x), safe_get(public_y), curve_name);
+ if(rc == BOTAN_FFI_SUCCESS)
+ *key = new botan_pubkey_struct(p_key.release());
+
+ return rc;
+ });
+#else
+ BOTAN_UNUSED(key, public_x, public_y, curve_name);
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+#endif
+ }
+
+int botan_privkey_load_ecdsa(botan_privkey_t* key,
+ const botan_mp_t scalar,
+ const char* curve_name)
+ {
+#if defined(BOTAN_HAS_ECDSA)
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ std::unique_ptr<Botan::ECDSA_PrivateKey> p_key;
+ int rc = privkey_load_ec(p_key, safe_get(scalar), curve_name);
+ if(rc == BOTAN_FFI_SUCCESS)
+ *key = new botan_privkey_struct(p_key.release());
+ return rc;
+ });
+#else
+ BOTAN_UNUSED(key, scalar, curve_name);
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+#endif
+ }
+
+/* ElGamal specific operations */
+
+int botan_pubkey_load_elgamal(botan_pubkey_t* key,
+ botan_mp_t p, botan_mp_t g, botan_mp_t y)
+ {
+#if defined(BOTAN_HAS_ELGAMAL)
+ *key = nullptr;
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ Botan::DL_Group group(safe_get(p), safe_get(g));
+ *key = new botan_pubkey_struct(new Botan::ElGamal_PublicKey(group, safe_get(y)));
+ return BOTAN_FFI_SUCCESS;
+ });
+#else
+ BOTAN_UNUSED(key, p, g, y);
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+#endif
+ }
+
+int botan_privkey_load_elgamal(botan_privkey_t* key,
+ botan_mp_t p, botan_mp_t g, botan_mp_t x)
+ {
+#if defined(BOTAN_HAS_ELGAMAL)
+ *key = nullptr;
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ Botan::Null_RNG null_rng;
+ Botan::DL_Group group(safe_get(p), safe_get(g));
+ *key = new botan_privkey_struct(new Botan::ElGamal_PrivateKey(null_rng, group, safe_get(x)));
+ return BOTAN_FFI_SUCCESS;
+ });
+#else
+ BOTAN_UNUSED(key, p, g, x);
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+#endif
+ }
+
+/* ECDH + x25519 specific operations */
+
+int botan_privkey_create_ecdh(botan_privkey_t* key_obj, botan_rng_t rng_obj, const char* param_str)
+ {
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ if(key_obj == nullptr || rng_obj == nullptr || param_str == nullptr || *param_str == 0)
+ return BOTAN_FFI_ERROR_NULL_POINTER;
+
+ *key_obj = nullptr;
+
+ const std::string params(param_str);
+
+#if defined(BOTAN_HAS_CURVE_25519)
+ if(params == "curve25519")
+ {
+ std::unique_ptr<Botan::Private_Key> key(new Botan::Curve25519_PrivateKey(safe_get(rng_obj)));
+ *key_obj = new botan_privkey_struct(key.release());
+ return BOTAN_FFI_SUCCESS;
+ }
+#endif
+
+#if defined(BOTAN_HAS_ECDH)
+ Botan::EC_Group grp(params);
+ std::unique_ptr<Botan::Private_Key> key(new Botan::ECDH_PrivateKey(safe_get(rng_obj), grp));
+ *key_obj = new botan_privkey_struct(key.release());
+ return BOTAN_FFI_SUCCESS;
+#endif
+
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+ });
+ }
+
+int botan_pubkey_load_ecdh(botan_pubkey_t* key,
+ const botan_mp_t public_x,
+ const botan_mp_t public_y,
+ const char* curve_name)
+ {
+#if defined(BOTAN_HAS_ECDH)
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ std::unique_ptr<Botan::ECDH_PublicKey> p_key;
+ int rc = pubkey_load_ec(p_key, safe_get(public_x), safe_get(public_y), curve_name);
+
+ if(rc == BOTAN_FFI_SUCCESS)
+ *key = new botan_pubkey_struct(p_key.release());
+ return rc;
+ });
+#else
+ BOTAN_UNUSED(key, public_x, public_y, curve_name);
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+#endif
+ }
+
+int botan_privkey_load_ecdh(botan_privkey_t* key,
+ const botan_mp_t scalar,
+ const char* curve_name)
+ {
+#if defined(BOTAN_HAS_ECDH)
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ std::unique_ptr<Botan::ECDH_PrivateKey> p_key;
+ int rc = privkey_load_ec(p_key, safe_get(scalar), curve_name);
+ if(rc == BOTAN_FFI_SUCCESS)
+ *key = new botan_privkey_struct(p_key.release());
+ return rc;
+ });
+#else
+ BOTAN_UNUSED(key, scalar, curve_name);
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+#endif
+ }
+
+/* SM2 specific operations */
+
+int botan_pubkey_load_sm2(botan_pubkey_t* key,
+ const botan_mp_t public_x,
+ const botan_mp_t public_y,
+ const char* curve_name)
+ {
+#if defined(BOTAN_HAS_SM2)
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ std::unique_ptr<Botan::SM2_Signature_PublicKey> p_key;
+ if(!pubkey_load_ec(p_key, safe_get(public_x), safe_get(public_y), curve_name))
+ {
+ *key = new botan_pubkey_struct(p_key.release());
+ return BOTAN_FFI_SUCCESS;
+ }
+ return BOTAN_FFI_ERROR_UNKNOWN_ERROR;
+ });
+#else
+ BOTAN_UNUSED(key, public_x, public_y, curve_name);
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+#endif
+ }
+
+int botan_privkey_load_sm2(botan_privkey_t* key,
+ const botan_mp_t scalar,
+ const char* curve_name)
+ {
+#if defined(BOTAN_HAS_SM2)
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ std::unique_ptr<Botan::SM2_Signature_PrivateKey> p_key;
+ int rc = privkey_load_ec(p_key, safe_get(scalar), curve_name);
+
+ if(rc == BOTAN_FFI_SUCCESS)
+ *key = new botan_privkey_struct(p_key.release());
+ return rc;
+ });
+#else
+ BOTAN_UNUSED(key, scalar, curve_name);
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+#endif
+ }
+
+/* Ed25519 specific operations */
+
+int botan_privkey_load_ed25519(botan_privkey_t* key,
+ const uint8_t privkey[32])
+ {
+#if defined(BOTAN_HAS_ED25519)
+ *key = nullptr;
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ const Botan::secure_vector<uint8_t> privkey_vec(privkey, privkey + 32);
+ *key = new botan_privkey_struct(new Botan::Ed25519_PrivateKey(privkey_vec));
+ return BOTAN_FFI_SUCCESS;
+ });
+#else
+ BOTAN_UNUSED(key, privkey);
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+#endif
+ }
+
+int botan_pubkey_load_ed25519(botan_pubkey_t* key,
+ const uint8_t pubkey[32])
+ {
+#if defined(BOTAN_HAS_ED25519)
+ *key = nullptr;
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ const std::vector<uint8_t> pubkey_vec(pubkey, pubkey + 32);
+ *key = new botan_pubkey_struct(new Botan::Ed25519_PublicKey(pubkey_vec));
+ return BOTAN_FFI_SUCCESS;
+ });
+#else
+ BOTAN_UNUSED(key, pubkey);
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+#endif
+ }
+
+int botan_privkey_ed25519_get_privkey(botan_privkey_t key,
+ uint8_t output[64])
+ {
+#if defined(BOTAN_HAS_ED25519)
+ return BOTAN_FFI_DO(Botan::Private_Key, key, k, {
+ if(Botan::Ed25519_PrivateKey* ed = dynamic_cast<Botan::Ed25519_PrivateKey*>(&k))
+ {
+ const Botan::secure_vector<uint8_t>& key = ed->get_private_key();
+ if(key.size() != 64)
+ return BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE;
+ Botan::copy_mem(output, key.data(), 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_ed25519_get_pubkey(botan_pubkey_t key,
+ uint8_t output[32])
+ {
+#if defined(BOTAN_HAS_ED25519)
+ return BOTAN_FFI_DO(Botan::Public_Key, key, k, {
+ if(Botan::Ed25519_PublicKey* ed = dynamic_cast<Botan::Ed25519_PublicKey*>(&k))
+ {
+ const std::vector<uint8_t>& key = ed->get_public_key();
+ if(key.size() != 32)
+ return BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE;
+ Botan::copy_mem(output, key.data(), 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)
+ {
+#if defined(BOTAN_HAS_MCELIECE)
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ if(key_obj == nullptr || rng_obj == nullptr || n == 0 || t == 0)
+ return BOTAN_FFI_ERROR_NULL_POINTER;
+
+ *key_obj = nullptr;
+
+ Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
+ std::unique_ptr<Botan::Private_Key> key(new Botan::McEliece_PrivateKey(rng, n, t));
+ *key_obj = new botan_privkey_struct(key.release());
+ return BOTAN_FFI_SUCCESS;
+ });
+#else
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+#endif
+ }
+
+int botan_mceies_decrypt(botan_privkey_t mce_key_obj,
+ const char* aead,
+ const uint8_t ct[], size_t ct_len,
+ const uint8_t ad[], size_t ad_len,
+ uint8_t out[], size_t* out_len)
+ {
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ Botan::Private_Key& key = safe_get(mce_key_obj);
+
+#if defined(BOTAN_HAS_MCELIECE) && defined(BOTAN_HAS_MCEIES)
+ Botan::McEliece_PrivateKey* mce = dynamic_cast<Botan::McEliece_PrivateKey*>(&key);
+ if(!mce)
+ return BOTAN_FFI_ERROR_BAD_PARAMETER;
+
+ const Botan::secure_vector<uint8_t> pt = mceies_decrypt(*mce, ct, ct_len, ad, ad_len, aead);
+ return write_vec_output(out, out_len, pt);
+#else
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+#endif
+ });
+ }
+
+int botan_mceies_encrypt(botan_pubkey_t mce_key_obj,
+ botan_rng_t rng_obj,
+ const char* aead,
+ const uint8_t pt[], size_t pt_len,
+ const uint8_t ad[], size_t ad_len,
+ uint8_t out[], size_t* out_len)
+ {
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ Botan::Public_Key& key = safe_get(mce_key_obj);
+ Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
+
+#if defined(BOTAN_HAS_MCELIECE) && defined(BOTAN_HAS_MCEIES)
+ Botan::McEliece_PublicKey* mce = dynamic_cast<Botan::McEliece_PublicKey*>(&key);
+ if(!mce)
+ return BOTAN_FFI_ERROR_BAD_PARAMETER;
+
+ Botan::secure_vector<uint8_t> ct = mceies_encrypt(*mce, pt, pt_len, ad, ad_len, rng, aead);
+ return write_vec_output(out, out_len, ct);
+#else
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+#endif
+ });
+ }
+
+}
diff --git a/src/lib/ffi/ffi_rng.cpp b/src/lib/ffi/ffi_rng.cpp
new file mode 100644
index 000000000..68b4aaf64
--- /dev/null
+++ b/src/lib/ffi/ffi_rng.cpp
@@ -0,0 +1,53 @@
+/*
+* (C) 2015,2017 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/ffi.h>
+#include <botan/internal/ffi_util.h>
+#include <botan/internal/ffi_rng.h>
+#include <botan/system_rng.h>
+#include <botan/auto_rng.h>
+
+extern "C" {
+
+using namespace Botan_FFI;
+
+int botan_rng_init(botan_rng_t* rng_out, const char* rng_type)
+ {
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ BOTAN_ASSERT_ARG_NON_NULL(rng_out);
+
+ const std::string rng_type_s(rng_type ? rng_type : "system");
+
+ std::unique_ptr<Botan::RandomNumberGenerator> rng;
+
+ if(rng_type_s == "system")
+ rng.reset(new Botan::System_RNG);
+ else if(rng_type_s == "user")
+ rng.reset(new Botan::AutoSeeded_RNG);
+ else
+ return BOTAN_FFI_ERROR_BAD_PARAMETER;
+
+ *rng_out = new botan_rng_struct(rng.release());
+ return BOTAN_FFI_SUCCESS;
+ });
+ }
+
+int botan_rng_destroy(botan_rng_t rng)
+ {
+ return BOTAN_FFI_CHECKED_DELETE(rng);
+ }
+
+int botan_rng_get(botan_rng_t rng, uint8_t* out, size_t out_len)
+ {
+ return BOTAN_FFI_DO(Botan::RandomNumberGenerator, rng, r, { r.randomize(out, out_len); });
+ }
+
+int botan_rng_reseed(botan_rng_t rng, size_t bits)
+ {
+ return BOTAN_FFI_DO(Botan::RandomNumberGenerator, rng, r, { r.reseed_from_rng(Botan::system_rng(), bits); });
+ }
+
+}
diff --git a/src/lib/ffi/ffi_rng.h b/src/lib/ffi/ffi_rng.h
new file mode 100644
index 000000000..73060eab7
--- /dev/null
+++ b/src/lib/ffi/ffi_rng.h
@@ -0,0 +1,21 @@
+/*
+* (C) 2017 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_FFI_RNG_H__
+#define BOTAN_FFI_RNG_H__
+
+#include <botan/rng.h>
+#include <botan/internal/ffi_util.h>
+
+extern "C" {
+
+using namespace Botan_FFI;
+
+BOTAN_FFI_DECLARE_STRUCT(botan_rng_struct, Botan::RandomNumberGenerator, 0x4901F9C1);
+
+}
+
+#endif
diff --git a/src/lib/ffi/ffi_util.h b/src/lib/ffi/ffi_util.h
new file mode 100644
index 000000000..919efdd75
--- /dev/null
+++ b/src/lib/ffi/ffi_util.h
@@ -0,0 +1,197 @@
+/*
+* (C) 2015,2017 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_FFI_UTILS_H__
+#define BOTAN_FFI_UTILS_H__
+
+#include <cstdint>
+#include <memory>
+#include <stdexcept>
+#include <botan/exceptn.h>
+#include <botan/mem_ops.h>
+
+namespace Botan_FFI {
+
+#define BOTAN_ASSERT_ARG_NON_NULL(p) \
+ do { if(!p) throw Botan::Invalid_Argument("Argument " #p " is null"); } while(0)
+
+class FFI_Error : public Botan::Exception
+ {
+ public:
+ explicit FFI_Error(const std::string& what) : Exception("FFI error", what) {}
+ };
+
+template<typename T, uint32_t MAGIC>
+struct botan_struct
+ {
+ public:
+ botan_struct(T* obj) : m_magic(MAGIC), m_obj(obj) {}
+ ~botan_struct() { m_magic = 0; m_obj.reset(); }
+
+ bool magic_ok() const { return (m_magic == MAGIC); }
+
+ T* get() const
+ {
+ if(magic_ok() == false)
+ throw FFI_Error("Bad magic " + std::to_string(m_magic) +
+ " in ffi object expected " + std::to_string(MAGIC));
+ return m_obj.get();
+ }
+ private:
+ uint32_t m_magic = 0;
+ std::unique_ptr<T> m_obj;
+ };
+
+#define BOTAN_FFI_DECLARE_STRUCT(NAME, TYPE, MAGIC) \
+ struct NAME : public botan_struct<TYPE, MAGIC> { explicit NAME(TYPE* x) : botan_struct(x) {} }
+
+// Declared in ffi.cpp
+int ffi_error_exception_thrown(const char* func_name, const char* exn);
+
+template<typename T, uint32_t M>
+T& safe_get(botan_struct<T,M>* p)
+ {
+ if(!p)
+ throw FFI_Error("Null pointer argument");
+ if(T* t = p->get())
+ return *t;
+ throw FFI_Error("Invalid object pointer");
+ }
+
+template<typename T, uint32_t M>
+const T& safe_get(const botan_struct<T,M>* p)
+ {
+ if(!p)
+ throw FFI_Error("Null pointer argument");
+ if(const T* t = p->get())
+ return *t;
+ throw FFI_Error("Invalid object pointer");
+ }
+
+template<typename Thunk>
+int ffi_guard_thunk(const char* func_name, Thunk thunk)
+ {
+ try
+ {
+ return thunk();
+ }
+ catch(std::bad_alloc)
+ {
+ return ffi_error_exception_thrown(func_name, "bad_alloc");
+ }
+ catch(std::exception& e)
+ {
+ return ffi_error_exception_thrown(func_name, e.what());
+ }
+ catch(...)
+ {
+ return ffi_error_exception_thrown(func_name, "unknown exception");
+ }
+
+ return BOTAN_FFI_ERROR_UNKNOWN_ERROR;
+ }
+
+template<typename T, uint32_t M, typename F>
+int apply_fn(botan_struct<T, M>* o, const char* func_name, F func)
+ {
+ try
+ {
+ if(!o)
+ throw FFI_Error("Null object to " + std::string(func_name));
+ if(T* t = o->get())
+ return func(*t);
+ }
+ catch(std::bad_alloc)
+ {
+ return ffi_error_exception_thrown(func_name, "bad_alloc");
+ }
+ catch(std::exception& e)
+ {
+ return ffi_error_exception_thrown(func_name, e.what());
+ }
+ catch(...)
+ {
+ return ffi_error_exception_thrown(func_name, "unknown exception");
+ }
+
+ return BOTAN_FFI_ERROR_UNKNOWN_ERROR;
+ }
+
+#define BOTAN_FFI_DO(T, obj, param, block) \
+ apply_fn(obj, BOTAN_CURRENT_FUNCTION, \
+ [=](T& param) -> int { do { block } while(0); return BOTAN_FFI_SUCCESS; })
+
+template<typename T, uint32_t M>
+int ffi_delete_object(botan_struct<T, M>* obj, const char* func_name)
+ {
+ try
+ {
+ if(obj == nullptr)
+ return BOTAN_FFI_SUCCESS; // ignore delete of null objects
+
+ if(obj->magic_ok() == false)
+ return BOTAN_FFI_ERROR_INVALID_INPUT;
+
+ delete obj;
+ return BOTAN_FFI_SUCCESS;
+ }
+ catch(std::exception& e)
+ {
+ return ffi_error_exception_thrown(func_name, e.what());
+ }
+ catch(...)
+ {
+ return ffi_error_exception_thrown(func_name, "unknown exception");
+ }
+ }
+
+#define BOTAN_FFI_CHECKED_DELETE(o) ffi_delete_object(o, BOTAN_CURRENT_FUNCTION)
+
+inline int write_output(uint8_t out[], size_t* out_len, const uint8_t buf[], size_t buf_len)
+ {
+ const size_t avail = *out_len;
+ *out_len = buf_len;
+
+ if(avail >= buf_len)
+ {
+ Botan::copy_mem(out, buf, buf_len);
+ return BOTAN_FFI_SUCCESS;
+ }
+ else
+ {
+ Botan::clear_mem(out, avail);
+ return BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE;
+ }
+ }
+
+template<typename Alloc>
+int write_vec_output(uint8_t out[], size_t* out_len, const std::vector<uint8_t, Alloc>& buf)
+ {
+ return write_output(out, out_len, buf.data(), buf.size());
+ }
+
+inline int write_str_output(uint8_t out[], size_t* out_len, const std::string& str)
+ {
+ return write_output(out, out_len,
+ reinterpret_cast<const uint8_t*>(str.c_str()),
+ str.size() + 1);
+ }
+
+inline int write_str_output(char out[], size_t* out_len, const std::string& str)
+ {
+ return write_str_output(reinterpret_cast<uint8_t*>(out), out_len, str);
+ }
+
+inline int write_str_output(char out[], size_t* out_len, const std::vector<uint8_t>& str_vec)
+ {
+ return write_output(reinterpret_cast<uint8_t*>(out), out_len,
+ reinterpret_cast<const uint8_t*>(str_vec.data()),
+ str_vec.size());
+ }
+
+}
+
+#endif
diff --git a/src/lib/ffi/info.txt b/src/lib/ffi/info.txt
index 71b4e6cf9..a28df11b0 100644
--- a/src/lib/ffi/info.txt
+++ b/src/lib/ffi/info.txt
@@ -2,6 +2,17 @@
FFI -> 20170327
</defines>
+<header:internal>
+ffi_mp.h
+ffi_pkey.h
+ffi_rng.h
+ffi_util.h
+</header:internal>
+
+<header:public>
+ffi.h
+</header:public>
+
<requires>
aead
kdf