aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/build-data/makefile/gmake.in2
-rw-r--r--src/build-data/makefile/nmake.in2
-rw-r--r--src/lib/base/buf_comp.h7
-rw-r--r--src/lib/ffi/ffi.cpp1099
-rw-r--r--src/lib/ffi/ffi.h342
-rw-r--r--src/lib/ffi/info.txt12
-rw-r--r--src/lib/kdf/hkdf/hkdf.cpp (renamed from src/lib/misc/hkdf/hkdf.cpp)9
-rw-r--r--src/lib/kdf/hkdf/hkdf.h (renamed from src/lib/misc/hkdf/hkdf.h)1
-rw-r--r--src/lib/kdf/hkdf/info.txt (renamed from src/lib/misc/hkdf/info.txt)0
-rw-r--r--src/lib/misc/pbes2/pbes2.cpp4
-rw-r--r--src/lib/pbkdf/pbkdf2/pbkdf2.cpp2
-rw-r--r--src/lib/pubkey/pubkey.cpp2
-rw-r--r--src/lib/pubkey/pubkey.h3
-rw-r--r--src/lib/tls/tls_exceptn.h6
-rw-r--r--src/python/__init__.py1
-rwxr-xr-xsrc/python/botan.py517
-rw-r--r--src/python/core.cpp230
-rw-r--r--src/python/filter.cpp177
-rw-r--r--src/python/python_botan.h86
-rw-r--r--src/python/rsa.cpp220
-rw-r--r--src/python/x509.cpp88
-rwxr-xr-xsrc/scripts/examples/cipher.py44
-rwxr-xr-xsrc/scripts/examples/cryptobox.py36
-rwxr-xr-xsrc/scripts/examples/nisttest.py61
-rw-r--r--src/scripts/examples/results.vec60
-rwxr-xr-xsrc/scripts/examples/rng_test.py22
-rwxr-xr-xsrc/scripts/examples/rsa.py47
-rw-r--r--src/tests/data/pbkdf/pbkdf2.vec21
28 files changed, 2014 insertions, 1087 deletions
diff --git a/src/build-data/makefile/gmake.in b/src/build-data/makefile/gmake.in
index 86d2d3569..cba9e2939 100644
--- a/src/build-data/makefile/gmake.in
+++ b/src/build-data/makefile/gmake.in
@@ -37,8 +37,6 @@ $(STATIC_LIB): $(LIBOBJS)
$(AR) $(STATIC_LIB) $(LIBOBJS)
$(RANLIB) $(STATIC_LIB)
-%{python_in}
-
# Fake Targets
.PHONY = clean distclean docs website install
diff --git a/src/build-data/makefile/nmake.in b/src/build-data/makefile/nmake.in
index 8359a1eb6..83192b365 100644
--- a/src/build-data/makefile/nmake.in
+++ b/src/build-data/makefile/nmake.in
@@ -48,8 +48,6 @@ $(BOTAN_LIB): $(LIBOBJS)
$(LIB_LINK_CMD) /Fe$(LIBNAME) $(LIBOBJS) $(LIB_LINKS_TO)
!Endif
-%{python_in}
-
# Fake Targets
SPHINX_CONFIG = %{sphinx_config_dir}
diff --git a/src/lib/base/buf_comp.h b/src/lib/base/buf_comp.h
index 5d11fdb73..564da2262 100644
--- a/src/lib/base/buf_comp.h
+++ b/src/lib/base/buf_comp.h
@@ -101,6 +101,13 @@ class BOTAN_DLL Buffered_Computation
return output;
}
+ template<typename Alloc>
+ void final(std::vector<byte, Alloc>& out)
+ {
+ out.resize(output_length());
+ final_result(&out[0]);
+ }
+
/**
* Update and finalize computation. Does the same as calling update()
* and final() consecutively.
diff --git a/src/lib/ffi/ffi.cpp b/src/lib/ffi/ffi.cpp
new file mode 100644
index 000000000..937423c69
--- /dev/null
+++ b/src/lib/ffi/ffi.cpp
@@ -0,0 +1,1099 @@
+/*
+* (C) 2015 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/ffi.h>
+#include <botan/system_rng.h>
+#include <botan/auto_rng.h>
+#include <botan/lookup.h>
+#include <botan/aead.h>
+#include <botan/hash.h>
+#include <botan/mac.h>
+#include <botan/pbkdf.h>
+#include <botan/version.h>
+#include <botan/pubkey.h>
+#include <botan/data_src.h>
+#include <botan/mem_ops.h>
+#include <cstring>
+#include <memory>
+
+#if defined(BOTAN_HAS_RSA)
+ #include <botan/rsa.h>
+#endif
+
+#if defined(BOTAN_HAS_ECDSA)
+ #include <botan/ecdsa.h>
+#endif
+
+#if defined(BOTAN_HAS_ECDH)
+ #include <botan/ecdh.h>
+#endif
+
+#if defined(BOTAN_HAS_BCRYPT)
+ #include <botan/bcrypt.h>
+#endif
+
+namespace {
+
+#define BOTAN_ASSERT_ARG_NON_NULL(p) \
+ do { if(!p) throw std::invalid_argument("Argument " #p " is null"); } while(0)
+
+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(); }
+
+ T* get() const
+ {
+ BOTAN_ASSERT_EQUAL(m_magic, MAGIC, "Bad magic value - memory corruption?");
+ return m_obj.get();
+ }
+ private:
+ uint32_t m_magic = 0;
+ std::unique_ptr<T> m_obj;
+ };
+
+void log_exception(const char* func_name, const char* what)
+ {
+ printf("botan ffi %s: %s\n", func_name, what);
+ }
+
+template<typename T, uint32_t M>
+T& safe_get(botan_struct<T,M>* p)
+ {
+ if(!p)
+ throw std::runtime_error("Null pointer argument");
+ if(T* t = p->get())
+ return *t;
+ throw std::runtime_error("Invalid object pointer");
+ }
+
+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 std::runtime_error("Null object to " + std::string(func_name));
+ if(T* t = o->get())
+ return func(*t);
+ }
+ catch(std::exception& e)
+ {
+ log_exception(func_name, e.what());
+ return -1;
+ }
+ catch(...)
+ {
+ log_exception(func_name, "unknown exception type");
+ return -2;
+ }
+
+ return -1;
+ }
+
+template<typename Alloc>
+int write_output(uint8_t out[], size_t* out_len, const std::vector<uint8_t, Alloc>& buf)
+ {
+ Botan::clear_mem(out, *out_len);
+ const size_t avail = *out_len;
+ *out_len = buf.size();
+ if(avail >= buf.size())
+ {
+ Botan::copy_mem(out, &buf[0], buf.size());
+ return 0;
+ }
+ return -1;
+ }
+
+#define BOTAN_FFI_DO(T, obj, block) apply_fn(obj, BOTAN_CURRENT_FUNCTION, [=](T& obj) { do { block } while(0); return 0; })
+
+}
+
+extern "C" {
+
+struct botan_rng_struct : public botan_struct<Botan::RandomNumberGenerator, 0x4901F9C1>
+ {
+ using botan_struct::botan_struct;
+ };
+
+struct botan_hash_struct : public botan_struct<Botan::HashFunction, 0x1F0A4F84>
+ {
+ using botan_struct::botan_struct;
+ };
+
+struct botan_mac_struct : public botan_struct<Botan::MessageAuthenticationCode, 0xA06E8FC1>
+ {
+ using botan_struct::botan_struct;
+ };
+
+struct botan_cipher_struct : public botan_struct<Botan::Cipher_Mode, 0xB4A2BF9C>
+ {
+ using botan_struct::botan_struct;
+ Botan::secure_vector<uint8_t> m_buf;
+ };
+
+struct botan_pubkey_struct : public botan_struct<Botan::Public_Key, 0x2C286519>
+ {
+ using botan_struct::botan_struct;
+ };
+
+struct botan_privkey_struct : public botan_struct<Botan::Private_Key, 0x7F96385E>
+ {
+ using botan_struct::botan_struct;
+ };
+
+struct botan_pk_op_encrypt_struct : public botan_struct<Botan::PK_Encryptor, 0x891F3FC3>
+ {
+ using botan_struct::botan_struct;
+ };
+
+struct botan_pk_op_decrypt_struct : public botan_struct<Botan::PK_Decryptor, 0x912F3C37>
+ {
+ using botan_struct::botan_struct;
+ };
+
+struct botan_pk_op_sign_struct : public botan_struct<Botan::PK_Signer, 0x1AF0C39F>
+ {
+ using botan_struct::botan_struct;
+ };
+
+struct botan_pk_op_verify_struct : public botan_struct<Botan::PK_Verifier, 0x2B91F936>
+ {
+ using botan_struct::botan_struct;
+ };
+
+struct botan_pk_op_ka_struct : public botan_struct<Botan::PK_Key_Agreement, 0x2939CAB1>
+ {
+ using botan_struct::botan_struct;
+ };
+
+/*
+* Versioning
+*/
+uint32_t botan_ffi_api_version()
+ {
+ return 20150210; // should match value in info.txt
+ }
+
+const char* botan_version_string()
+ {
+ return Botan::version_cstr();
+ }
+
+uint32_t botan_version_major() { return Botan::version_major(); }
+uint32_t botan_version_minor() { return Botan::version_minor(); }
+uint32_t botan_version_patch() { return Botan::version_patch(); }
+uint32_t botan_version_datestamp() { return Botan::version_datestamp(); }
+
+int botan_rng_init(botan_rng_t* rng_out, const char* rng_type)
+ {
+ // Just gives unique_ptr something to delete, really
+ class RNG_Wrapper : public Botan::RandomNumberGenerator
+ {
+ public:
+ RNG_Wrapper(Botan::RandomNumberGenerator& rng) : m_rng(rng) {}
+ void randomize(Botan::byte out[], size_t len) override { m_rng.randomize(out, len); }
+ bool is_seeded() const override { return m_rng.is_seeded(); }
+ void clear() override { m_rng.clear(); }
+ std::string name() const { return m_rng.name(); }
+ void reseed(size_t poll_bits = 256) { m_rng.reseed(poll_bits); }
+ void add_entropy(const Botan::byte in[], size_t len) { m_rng.add_entropy(in, len); }
+ private:
+ Botan::RandomNumberGenerator& m_rng;
+ };
+
+ try
+ {
+ BOTAN_ASSERT_ARG_NON_NULL(rng_out);
+
+ if(rng_type == nullptr || *rng_type == 0)
+ rng_type = "system";
+
+ const std::string rng_type_s(rng_type);
+
+ std::unique_ptr<Botan::RandomNumberGenerator> rng;
+
+ if(rng_type_s == "system")
+ rng.reset(new RNG_Wrapper(Botan::system_rng()));
+ else if(rng_type_s == "user")
+ rng.reset(new Botan::AutoSeeded_RNG);
+
+ if(rng)
+ {
+ *rng_out = new botan_rng_struct(rng.release());
+ return 0;
+ }
+ }
+ catch(std::exception& e)
+ {
+ log_exception(BOTAN_CURRENT_FUNCTION, e.what());
+ }
+ catch(...)
+ {
+ log_exception(BOTAN_CURRENT_FUNCTION, "unknown");
+ }
+
+ return -1;
+ }
+
+int botan_rng_destroy(botan_rng_t rng)
+ {
+ delete rng;
+ return 0;
+ }
+
+int botan_rng_get(botan_rng_t rng, uint8_t* out, size_t out_len)
+ {
+ return BOTAN_FFI_DO(Botan::RandomNumberGenerator, rng, { rng.randomize(out, out_len); });
+ }
+
+int botan_rng_reseed(botan_rng_t rng, size_t bits)
+ {
+ return BOTAN_FFI_DO(Botan::RandomNumberGenerator, rng, { rng.reseed(bits); });
+ }
+
+int botan_hash_init(botan_hash_t* hash, const char* hash_name, uint32_t flags)
+ {
+ try
+ {
+ if(!hash || !hash_name || flags != 0)
+ return -1;
+
+ if(auto h = Botan::get_hash_function(hash_name))
+ {
+ *hash = new botan_hash_struct(h);
+ return 0;
+ }
+ }
+ catch(std::exception& e)
+ {
+ log_exception(BOTAN_CURRENT_FUNCTION, e.what());
+ }
+ catch(...)
+ {
+ log_exception(BOTAN_CURRENT_FUNCTION, "unknown");
+ }
+
+ return -2;
+ }
+
+int botan_hash_destroy(botan_hash_t hash)
+ {
+ delete hash;
+ return 0;
+ }
+
+int botan_hash_output_length(botan_hash_t hash, size_t* out)
+ {
+ return BOTAN_FFI_DO(Botan::HashFunction, hash, { *out = hash.output_length(); });
+ }
+
+int botan_hash_clear(botan_hash_t hash)
+ {
+ return BOTAN_FFI_DO(Botan::HashFunction, hash, { hash.clear(); });
+ }
+
+int botan_hash_update(botan_hash_t hash, const uint8_t* buf, size_t len)
+ {
+ return BOTAN_FFI_DO(Botan::HashFunction, hash, { hash.update(buf, len); });
+ }
+
+int botan_hash_final(botan_hash_t hash, uint8_t out[])
+ {
+ return BOTAN_FFI_DO(Botan::HashFunction, hash, { hash.final(out); });
+ }
+
+int botan_mac_init(botan_mac_t* mac, const char* mac_name, uint32_t flags)
+ {
+ try
+ {
+ if(!mac || !mac_name || flags != 0)
+ return -1;
+
+ if(auto m = Botan::get_mac(mac_name))
+ {
+ *mac = new botan_mac_struct(m);
+ return 0;
+ }
+ }
+ catch(std::exception& e)
+ {
+ log_exception(BOTAN_CURRENT_FUNCTION, e.what());
+ }
+ catch(...)
+ {
+ log_exception(BOTAN_CURRENT_FUNCTION, "unknown");
+ }
+
+ return -2;
+ }
+
+int botan_mac_destroy(botan_mac_t mac)
+ {
+ delete mac;
+ return 0;
+ }
+
+int botan_mac_set_key(botan_mac_t mac, const uint8_t* key, size_t key_len)
+ {
+ return BOTAN_FFI_DO(Botan::MessageAuthenticationCode, mac, { mac.set_key(key, key_len); });
+ }
+
+int botan_mac_output_length(botan_mac_t mac, size_t* out)
+ {
+ return BOTAN_FFI_DO(Botan::MessageAuthenticationCode, mac, { *out = mac.output_length(); });
+ }
+
+int botan_mac_clear(botan_mac_t mac)
+ {
+ return BOTAN_FFI_DO(Botan::MessageAuthenticationCode, mac, { mac.clear(); });
+ }
+
+int botan_mac_update(botan_mac_t mac, const uint8_t* buf, size_t len)
+ {
+ return BOTAN_FFI_DO(Botan::MessageAuthenticationCode, mac, { mac.update(buf, len); });
+ }
+
+int botan_mac_final(botan_mac_t mac, uint8_t out[])
+ {
+ return BOTAN_FFI_DO(Botan::MessageAuthenticationCode, mac, { mac.final(out); });
+ }
+
+int botan_cipher_init(botan_cipher_t* cipher, const char* cipher_name, uint32_t flags)
+ {
+ try
+ {
+ Botan::Cipher_Dir dir = (flags & 0) ? Botan::DECRYPTION : Botan::ENCRYPTION;
+ std::unique_ptr<Botan::Cipher_Mode> mode(Botan::get_cipher_mode(cipher_name, dir));
+ if(!mode)
+ return -1;
+ *cipher = new botan_cipher_struct(mode.release());
+ return 0;
+ }
+ catch(std::exception& e)
+ {
+ log_exception(BOTAN_CURRENT_FUNCTION, e.what());
+ }
+ catch(...)
+ {
+ log_exception(BOTAN_CURRENT_FUNCTION, "unknown");
+ }
+
+ return -1;
+ }
+
+int botan_cipher_destroy(botan_cipher_t cipher)
+ {
+ delete cipher;
+ return 0;
+ }
+
+int botan_cipher_clear(botan_cipher_t cipher)
+ {
+ return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, { cipher.clear(); });
+ }
+
+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, { cipher.set_key(key, key_len); });
+ }
+
+int botan_cipher_start(botan_cipher_t cipher_obj,
+ const uint8_t* nonce, size_t nonce_len)
+ {
+ try
+ {
+ Botan::Cipher_Mode& cipher = safe_get(cipher_obj);
+ BOTAN_ASSERT(cipher.start(nonce, nonce_len).empty(), "Ciphers have no prefix");
+ cipher_obj->m_buf.reserve(cipher.update_granularity());
+ return 0;
+ }
+ catch(std::exception& e)
+ {
+ log_exception(BOTAN_CURRENT_FUNCTION, e.what());
+ }
+
+ return -1;
+ }
+
+int botan_cipher_update(botan_cipher_t cipher_obj,
+ uint32_t flags,
+ uint8_t output[],
+ size_t output_size,
+ size_t* output_written,
+ const uint8_t input[],
+ size_t input_size,
+ size_t* input_consumed)
+ {
+ using namespace Botan;
+
+ try
+ {
+ 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;
+
+ try
+ {
+ cipher.finish(mbuf);
+ }
+ catch(Integrity_Failure& e)
+ {
+ log_exception(BOTAN_CURRENT_FUNCTION, e.what());
+ return -2;
+ }
+
+ *output_written = mbuf.size();
+
+ if(mbuf.size() <= output_size)
+ {
+ copy_mem(output, &mbuf[0], mbuf.size());
+ mbuf.clear();
+ return 0;
+ }
+
+ 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[0], mbuf.size());
+ mbuf.clear();
+ return 0;
+ }
+
+ return -1;
+ }
+
+ const size_t ud = cipher.update_granularity();
+ BOTAN_ASSERT(cipher.update_granularity() > cipher.minimum_final_size(), "logic error");
+
+#if 0
+ // Avoiding double copy:
+ if(Online_Cipher_Mode* ocm = dynamic_cast<Online_Cipher_Mode*>(&cipher))
+ {
+ const size_t taken = round_down(input_size, ud);
+ *input_consumed = taken;
+ *output_size = taken;
+ copy_mem(&output[0], input, taken);
+ ocm->update_in_place(output, taken);
+ return 0;
+ }
+#endif
+
+ mbuf.resize(ud);
+ size_t taken = 0, written = 0;
+
+ while(input_size >= ud && output_size >= ud)
+ {
+ copy_mem(&mbuf[0], input, ud);
+ cipher.update(mbuf);
+
+ input_size -= ud;
+ input += ud;
+ taken += ud;
+
+ output_size -= ud;
+ output += ud;
+ written += ud;
+ }
+
+ *output_written = written;
+ *input_consumed = taken;
+
+ }
+ catch(std::exception& e)
+ {
+ log_exception(BOTAN_CURRENT_FUNCTION, e.what());
+ }
+
+ return -1;
+ }
+
+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, {
+ if(Botan::AEAD_Mode* aead = dynamic_cast<Botan::AEAD_Mode*>(&cipher))
+ {
+ aead->set_associated_data(ad, ad_len);
+ return 0;
+ }
+ return -1;
+ });
+ }
+
+int botan_cipher_valid_nonce_length(botan_cipher_t cipher, size_t nl)
+ {
+ return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, { return cipher.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, { *nl = cipher.default_nonce_length(); });
+ }
+
+int botan_cipher_get_tag_length(botan_cipher_t cipher, size_t* tl)
+ {
+ return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, { *tl = cipher.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)
+ {
+ try
+ {
+ std::unique_ptr<Botan::PBKDF> pbkdf(Botan::get_pbkdf(pbkdf_algo));
+
+ auto r = pbkdf->derive_key(out_len, pass, salt, salt_len, iterations).bits_of();
+
+ if(r.size() != out_len)
+ throw std::runtime_error(std::string(pbkdf_algo) + " produced " +
+ std::to_string(r.size()) + " asked for " +
+ std::to_string(out_len));
+
+ Botan::copy_mem(out, &r[0], out_len);
+ }
+ catch(std::exception& e)
+ {
+ log_exception(BOTAN_CURRENT_FUNCTION, e.what());
+ }
+
+ return -1;
+ }
+
+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)
+ {
+ try
+ {
+ std::unique_ptr<Botan::PBKDF> pbkdf(Botan::get_pbkdf(pbkdf_algo));
+
+ auto r = pbkdf->derive_key(out_len, password, salt, salt_len,
+ std::chrono::milliseconds(ms_to_run),
+ *iterations_used).bits_of();
+
+ if(r.size() != out_len)
+ throw std::runtime_error(std::string(pbkdf_algo) + " produced " +
+ std::to_string(r.size()) + " asked for " +
+ std::to_string(out_len));
+
+ Botan::copy_mem(out, &r[0], out_len);
+ }
+ catch(std::exception& e)
+ {
+ log_exception(BOTAN_CURRENT_FUNCTION, e.what());
+ }
+
+ return -1;
+ }
+
+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)
+ {
+ try
+ {
+ std::unique_ptr<Botan::KDF> kdf(Botan::get_kdf(kdf_algo));
+ auto r = kdf->derive_key(out_len, secret, secret_len, salt, salt_len);
+ if(r.size() != out_len)
+ throw std::runtime_error(std::string(kdf_algo) + " produced " +
+ std::to_string(r.size()) + " asked for " +
+ std::to_string(out_len));
+ Botan::copy_mem(out, &r[0], out_len);
+ }
+ catch(std::exception& e)
+ {
+ log_exception(BOTAN_CURRENT_FUNCTION, e.what());
+ }
+
+ return -1;
+ }
+
+#if defined(BOTAN_HAS_BCRYPT)
+int botan_bcrypt_generate(char* out, size_t out_len, const char* pass,
+ botan_rng_t rng_obj, size_t wf)
+ {
+ try
+ {
+ BOTAN_ASSERT_ARG_NON_NULL(out);
+ BOTAN_ASSERT_ARG_NON_NULL(pass);
+
+ if(wf < 2 || wf > 30)
+ throw std::runtime_error("Bad bcrypt work factor " + std::to_string(wf));
+
+ Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
+
+ std::memset(out, 0, out_len);
+ const std::string c = Botan::generate_bcrypt(pass, rng, wf);
+ if(out_len <= c.size())
+ return ENOMEM;
+ std::memcpy(out, c.c_str(), c.size());
+ return 0;
+ }
+ catch(std::exception& e)
+ {
+ log_exception(BOTAN_CURRENT_FUNCTION, e.what());
+ }
+ catch(...)
+ {
+ log_exception(BOTAN_CURRENT_FUNCTION, "unknown");
+ }
+
+ return -1;
+ }
+
+int botan_bcrypt_is_valid(const char* pass, const char* hash)
+ {
+ try
+ {
+ if(Botan::check_bcrypt(pass, hash))
+ return 0; // success
+ return 1;
+ }
+ catch(std::exception& e)
+ {
+ log_exception(BOTAN_CURRENT_FUNCTION, e.what());
+ }
+ catch(...)
+ {
+ log_exception(BOTAN_CURRENT_FUNCTION, "unknown");
+ }
+
+ return -1;
+ }
+
+#endif
+
+int botan_privkey_create_rsa(botan_privkey_t* key, botan_rng_t rng_obj, size_t n_bits)
+ {
+ try
+ {
+ *key = nullptr;
+
+#if defined(BOTAN_HAS_RSA)
+ Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
+ std::unique_ptr<Botan::RSA_PrivateKey> rsa(new Botan::RSA_PrivateKey(rng, n_bits));
+ *key = new botan_privkey_struct(rsa.release());
+ return 0;
+#endif
+ }
+ catch(std::exception& e)
+ {
+ log_exception(BOTAN_CURRENT_FUNCTION, e.what());
+ }
+
+ return -1;
+ }
+
+
+int botan_privkey_create_ecdsa(botan_privkey_t* key, botan_rng_t rng_obj, const char* params)
+ {
+ try
+ {
+#if defined(BOTAN_HAS_ECDSA)
+ Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
+ Botan::EC_Group grp(params);
+ std::unique_ptr<Botan::ECDSA_PrivateKey> ecdsa(new Botan::ECDSA_PrivateKey(rng, grp));
+ *key = new botan_privkey_struct(ecdsa.release());
+ return 0;
+#endif
+ }
+ catch(std::exception& e)
+ {
+ log_exception(BOTAN_CURRENT_FUNCTION, e.what());
+ }
+
+ return -1;
+ }
+
+int botan_privkey_create_ecdh(botan_privkey_t* key, botan_rng_t rng_obj, const char* params)
+ {
+ try
+ {
+#if defined(BOTAN_HAS_ECDH)
+ Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
+ Botan::EC_Group grp(params);
+ std::unique_ptr<Botan::ECDH_PrivateKey> ecdh(new Botan::ECDH_PrivateKey(rng, grp));
+ *key = new botan_privkey_struct(ecdh.release());
+ return 0;
+#endif
+ }
+ catch(std::exception& e)
+ {
+ log_exception(BOTAN_CURRENT_FUNCTION, e.what());
+ }
+
+ return -1;
+ }
+
+int botan_privkey_load(botan_privkey_t* key, botan_rng_t rng_obj,
+ const uint8_t bits[], size_t len,
+ const char* password)
+ {
+ try
+ {
+ Botan::DataSource_Memory src(bits, len);
+
+ if(password == nullptr)
+ password = "";
+
+ Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
+
+ std::unique_ptr<Botan::PKCS8_PrivateKey> pkcs8;
+ pkcs8.reset(Botan::PKCS8::load_key(src, rng, password));
+
+ if(pkcs8)
+ {
+ *key = new botan_privkey_struct(pkcs8.release());
+ return 0;
+ }
+ }
+ catch(std::exception& e)
+ {
+ log_exception(BOTAN_CURRENT_FUNCTION, e.what());
+ }
+
+ return -1;
+ *key = nullptr;
+ return -1;
+ }
+
+int botan_privkey_destroy(botan_privkey_t key)
+ {
+ delete key;
+ return 0;
+ }
+
+int botan_pubkey_destroy(botan_privkey_t key)
+ {
+ delete key;
+ return 0;
+ }
+
+int botan_privkey_export_pubkey(botan_pubkey_t* pubout, botan_privkey_t key_obj)
+ {
+ try
+ {
+ 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 0;
+ }
+ catch(std::exception& e)
+ {
+ log_exception(BOTAN_CURRENT_FUNCTION, e.what());
+ }
+
+ return -1;
+ }
+
+int botan_pubkey_algo_name(botan_pubkey_t key, char out[], size_t* out_len)
+ {
+ return apply_fn(key, BOTAN_CURRENT_FUNCTION,
+ [out,out_len](Botan::Public_Key& k)
+ {
+ const std::string name = k.algo_name();
+ const size_t avail = *out_len;
+ *out_len = name.size() + 1;
+ if(avail > 1 + name.size())
+ {
+ Botan::copy_mem(out, name.data(), name.size());
+ out[name.size()] = 0;
+ return 0;
+ }
+ return -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, {
+ return write_output(out, out_len, Botan::X509::BER_encode(key));
+ });
+ }
+
+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, {
+ return write_output(out, out_len, Botan::PKCS8::BER_encode(key));
+ });
+ }
+
+int botan_privkey_export_encrypted(botan_privkey_t key,
+ uint8_t out[], size_t* out_len,
+ botan_rng_t rng_obj,
+ const char* passphrase,
+ const char* encryption_algo,
+ uint32_t flags)
+ {
+ return BOTAN_FFI_DO(Botan::Private_Key, key, {
+ auto ber = Botan::PKCS8::BER_encode(key, safe_get(rng_obj), passphrase,
+ std::chrono::milliseconds(300),
+ encryption_algo);
+ return write_output(out, out_len, ber);
+ });
+ }
+
+int botan_pubkey_estimated_strength(botan_pubkey_t key, size_t* estimate)
+ {
+ return BOTAN_FFI_DO(Botan::Public_Key, key, { *estimate = key.estimated_strength(); });
+ }
+
+int botan_pubkey_fingerprint(botan_pubkey_t key, const char* hash_fn,
+ uint8_t out[], size_t* out_len)
+ {
+ return apply_fn(key, BOTAN_CURRENT_FUNCTION,
+ [hash_fn,out,out_len](Botan::Public_Key& k)
+ {
+ std::unique_ptr<Botan::HashFunction> h(Botan::get_hash(hash_fn));
+ auto z = h->process(k.x509_subject_public_key());
+ *out_len = std::min(z.size(), *out_len);
+ Botan::copy_mem(out, &z[0], *out_len);
+ return 0;
+ });
+ *out_len = 0;
+ return -1;
+ }
+
+int botan_pk_op_encrypt_create(botan_pk_op_encrypt_t* op,
+ botan_pubkey_t key_obj,
+ const char* padding,
+ uint32_t flags)
+ {
+ try
+ {
+ BOTAN_ASSERT_NONNULL(op);
+
+ if(flags != 0)
+ return -2;
+
+ std::unique_ptr<Botan::PK_Encryptor> pk(new Botan::PK_Encryptor_EME(safe_get(key_obj), padding));
+ *op = new botan_pk_op_encrypt_struct(pk.release());
+ return 0;
+ }
+ catch(std::exception& e)
+ {
+ log_exception(BOTAN_CURRENT_FUNCTION, e.what());
+ }
+
+ return -1;
+ }
+
+int botan_pk_op_encrypt_destroy(botan_pk_op_encrypt_t op)
+ {
+ delete op;
+ return 0;
+ }
+
+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, {
+ return write_output(out, out_len, op.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)
+ {
+ try
+ {
+ BOTAN_ASSERT_NONNULL(op);
+
+ if(flags != 0)
+ return -2;
+
+ std::unique_ptr<Botan::PK_Decryptor> pk(new Botan::PK_Decryptor_EME(safe_get(key_obj), padding));
+ *op = new botan_pk_op_decrypt_struct(pk.release());
+ return 0;
+ }
+ catch(std::exception& e)
+ {
+ log_exception(BOTAN_CURRENT_FUNCTION, e.what());
+ }
+
+ return -1;
+ }
+
+int botan_pk_op_decrypt_destroy(botan_pk_op_decrypt_t op)
+ {
+ delete op;
+ return 0;
+ }
+
+int botan_pk_op_decrypt(botan_pk_op_decrypt_t op,
+ uint8_t out[], size_t* out_len,
+ uint8_t ciphertext[], size_t ciphertext_len)
+ {
+ return BOTAN_FFI_DO(Botan::PK_Decryptor, op, {
+ return write_output(out, out_len, op.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)
+ {
+ try
+ {
+ BOTAN_ASSERT_NONNULL(op);
+
+ if(flags != 0)
+ return -2;
+
+ std::unique_ptr<Botan::PK_Signer> pk(new Botan::PK_Signer(safe_get(key_obj), hash));
+ *op = new botan_pk_op_sign_struct(pk.release());
+ return 0;
+ }
+ catch(std::exception& e)
+ {
+ log_exception(BOTAN_CURRENT_FUNCTION, e.what());
+ }
+
+ return -1;
+ }
+
+int botan_pk_op_sign_destroy(botan_pk_op_sign_t op)
+ {
+ delete op;
+ return 0;
+ }
+
+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, { op.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, {
+ return write_output(out, out_len, op.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)
+ {
+ try
+ {
+ BOTAN_ASSERT_NONNULL(op);
+
+ if(flags != 0)
+ return -2;
+
+ 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 0;
+ }
+ catch(std::exception& e)
+ {
+ log_exception(BOTAN_CURRENT_FUNCTION, e.what());
+ }
+
+ return -1;
+ }
+
+int botan_pk_op_verify_destroy(botan_pk_op_verify_t op)
+ {
+ delete op;
+ return 0;
+ }
+
+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, { op.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, {
+ const bool legit = op.check_signature(sig, sig_len);
+
+ if(legit)
+ return 0;
+ else
+ return 1;
+ });
+ }
+
+int botan_pk_op_key_agreement_create(botan_pk_op_ka_t* op,
+ botan_privkey_t key_obj,
+ const char* kdf,
+ uint32_t flags)
+ {
+ try
+ {
+ BOTAN_ASSERT_NONNULL(op);
+
+ if(flags != 0)
+ return -2;
+
+ std::unique_ptr<Botan::PK_Key_Agreement> pk(new Botan::PK_Key_Agreement(safe_get(key_obj), kdf));
+ *op = new botan_pk_op_ka_struct(pk.release());
+ return 0;
+ }
+ catch(std::exception& e)
+ {
+ log_exception(BOTAN_CURRENT_FUNCTION, e.what());
+ }
+
+ return -1;
+ }
+
+int botan_pk_op_key_agreement_destroy(botan_pk_op_ka_t op)
+ {
+ delete op;
+ return 0;
+ }
+
+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, {
+ auto k = op.derive_key(*out_len, other_key, other_key_len, salt, salt_len).bits_of();
+ return write_output(out, out_len, k);
+ });
+ }
+
+}
+
diff --git a/src/lib/ffi/ffi.h b/src/lib/ffi/ffi.h
new file mode 100644
index 000000000..cda2c1480
--- /dev/null
+++ b/src/lib/ffi/ffi.h
@@ -0,0 +1,342 @@
+/*
+* (C) 2015 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_FFI_H__
+#define BOTAN_FFI_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <botan/build.h>
+#include <stdint.h>
+#include <stddef.h>
+
+/*
+* TODO:
+* - Better error reporting
+* - User callback for exception logging
+* - Doxygen comments for all functions/params
+* - X.509 certs and PKIX path validation goo
+* - TLS
+*/
+
+/*
+* Versioning
+*/
+BOTAN_DLL uint32_t botan_ffi_api_version();
+
+BOTAN_DLL const char* botan_version_string();
+BOTAN_DLL uint32_t botan_version_major();
+BOTAN_DLL uint32_t botan_version_minor();
+BOTAN_DLL uint32_t botan_version_patch();
+BOTAN_DLL uint32_t botan_version_datestamp();
+
+/*
+* Error handling
+*/
+//const char* botan_error_description(int err);
+
+/*
+* Utility
+*/
+BOTAN_DLL int botan_same_mem(const uint8_t* x, const uint8_t* y, size_t len);
+
+/*
+* RNG
+*/
+typedef struct botan_rng_struct* botan_rng_t;
+
+BOTAN_DLL int botan_rng_init(botan_rng_t* rng, const char* rng_type);
+BOTAN_DLL int botan_rng_destroy(botan_rng_t rng);
+
+BOTAN_DLL int botan_rng_get(botan_rng_t rng, uint8_t* out, size_t out_len);
+BOTAN_DLL int botan_rng_reseed(botan_rng_t rng, size_t bits);
+
+/*
+* Hashing
+*/
+typedef struct botan_hash_struct* botan_hash_t;
+
+BOTAN_DLL int botan_hash_init(botan_hash_t* hash, const char* hash_name, uint32_t flags);
+BOTAN_DLL int botan_hash_destroy(botan_hash_t hash);
+BOTAN_DLL int botan_hash_clear(botan_hash_t hash);
+
+BOTAN_DLL int botan_hash_update(botan_hash_t hash, const uint8_t* in, size_t in_len);
+BOTAN_DLL int botan_hash_final(botan_hash_t hash, uint8_t out[]);
+BOTAN_DLL int botan_hash_output_length(botan_hash_t hash, size_t* output_length);
+
+/*
+* Message Authentication
+*/
+typedef struct botan_mac_struct* botan_mac_t;
+
+BOTAN_DLL int botan_mac_init(botan_mac_t* mac, const char* mac_name, uint32_t flags);
+BOTAN_DLL int botan_mac_destroy(botan_mac_t mac);
+BOTAN_DLL int botan_mac_clear(botan_mac_t hash);
+
+BOTAN_DLL int botan_mac_set_key(botan_mac_t mac, const uint8_t* key, size_t key_len);
+BOTAN_DLL int botan_mac_update(botan_mac_t mac, const uint8_t* buf, size_t len);
+BOTAN_DLL int botan_mac_final(botan_mac_t mac, uint8_t out[]);
+BOTAN_DLL int botan_mac_output_length(botan_mac_t mac, size_t* output_length);
+
+/*
+* Cipher modes
+*/
+typedef struct botan_cipher_struct* botan_cipher_t;
+
+BOTAN_DLL int botan_cipher_init(botan_cipher_t* cipher, const char* name, uint32_t flags);
+BOTAN_DLL int botan_cipher_destroy(botan_cipher_t cipher);
+BOTAN_DLL int botan_cipher_clear(botan_cipher_t hash);
+
+BOTAN_DLL int botan_cipher_valid_nonce_length(botan_cipher_t cipher, size_t nl);
+BOTAN_DLL int botan_cipher_get_tag_length(botan_cipher_t cipher, size_t* tag_size);
+BOTAN_DLL int botan_cipher_get_default_nonce_length(botan_cipher_t cipher, size_t* nl);
+
+BOTAN_DLL int botan_cipher_set_key(botan_cipher_t cipher,
+ const uint8_t* key, size_t key_len);
+
+BOTAN_DLL int botan_cipher_set_associated_data(botan_cipher_t cipher,
+ const uint8_t* ad, size_t ad_len);
+
+BOTAN_DLL int botan_cipher_start(botan_cipher_t cipher,
+ const uint8_t* nonce, size_t nonce_len);
+
+#define BOTAN_CIPHER_UPDATE_FLAG_FINAL (1U << 0)
+
+BOTAN_DLL int botan_cipher_update(botan_cipher_t cipher,
+ uint32_t flags,
+ uint8_t output[],
+ size_t output_size,
+ size_t* output_written,
+ const uint8_t input_bytes[],
+ size_t input_size,
+ size_t* input_consumed);
+
+
+/*
+* PBKDF
+*/
+BOTAN_DLL int botan_pbkdf(const char* pbkdf_algo,
+ uint8_t out[], size_t out_len,
+ const char* password,
+ const uint8_t salt[], size_t salt_len,
+ size_t iterations);
+
+BOTAN_DLL 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 milliseconds_to_run,
+ size_t* out_iterations_used);
+
+/*
+* KDF
+*/
+BOTAN_DLL 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);
+
+/*
+* Bcrypt
+*/
+#if defined(BOTAN_HAS_BCRYPT)
+
+BOTAN_DLL int botan_bcrypt_generate(char* out, size_t out_len,
+ const char* pass,
+ botan_rng_t rng,
+ size_t work_factor);
+
+/**
+* Returns 0 if if this password/hash combination is valid
+* Returns 1 if the combination is not valid
+* Returns -1 on error
+*/
+BOTAN_DLL int botan_bcrypt_is_valid(const char* pass, const char* hash);
+
+#endif
+
+/*
+* Public/private key creation, import, ...
+*/
+typedef struct botan_pubkey_struct* botan_pubkey_t;
+typedef struct botan_privkey_struct* botan_privkey_t;
+
+BOTAN_DLL int botan_privkey_create_rsa(botan_privkey_t* key, botan_rng_t rng, size_t n_bits);
+//BOTAN_DLL int botan_privkey_create_dsa(botan_privkey_t* key, botan_rng_t rng, size_t p_bits, size_t q_bits);
+//BOTAN_DLL int botan_privkey_create_dh(botan_privkey_t* key, botan_rng_t rng, size_t p_bits);
+BOTAN_DLL int botan_privkey_create_ecdsa(botan_privkey_t* key, botan_rng_t rng, const char* params);
+BOTAN_DLL int botan_privkey_create_ecdh(botan_privkey_t* key, botan_rng_t rng, const char* params);
+//BOTAN_DLL int botan_privkey_create_mceliece(botan_privkey_t* key, botan_rng_t rng, size_t n, size_t t);
+
+/*
+* Input currently assumed to be PKCS #8 structure;
+*/
+BOTAN_DLL int botan_privkey_load(botan_privkey_t* key, botan_rng_t rng,
+ const uint8_t bits[], size_t len,
+ const char* password);
+BOTAN_DLL int botan_pubkey_load(botan_privkey_t* key,
+ const uint8_t bits[], size_t len,
+ const char* password);
+
+BOTAN_DLL int botan_privkey_export_pubkey(botan_pubkey_t* out, botan_privkey_t in);
+
+BOTAN_DLL int botan_pubkey_destroy(botan_privkey_t key);
+BOTAN_DLL int botan_privkey_destroy(botan_privkey_t key);
+
+#define BOTAN_PRIVKEY_EXPORT_FLAG_DER 0
+#define BOTAN_PRIVKEY_EXPORT_FLAG_PEM 1
+
+/*
+* On input *out_len is number of bytes in out[]
+* On output *out_len is number of bytes written (or required)
+* If out is not big enough no output is written, *out_len is set and 1 is returned
+* Returns 0 on success and sets
+* If some other error occurs a negative integer is returned.
+*/
+BOTAN_DLL int botan_pubkey_export(botan_pubkey_t key, uint8_t out[], size_t* out_len, uint32_t flags);
+BOTAN_DLL int botan_privkey_export(botan_privkey_t key, uint8_t out[], size_t* out_len, uint32_t flags);
+
+/*
+* Set encryption_algo to NULL to have the library choose a default (recommended)
+*/
+BOTAN_DLL int botan_privkey_export_encrypted(botan_privkey_t key,
+ uint8_t out[], size_t* out_len,
+ botan_rng_t rng,
+ const char* passphrase,
+ const char* encryption_algo,
+ uint32_t flags);
+
+BOTAN_DLL int botan_pubkey_algo_name(botan_pubkey_t key, char out[], size_t* out_len);
+
+BOTAN_DLL int botan_pubkey_estimated_strength(botan_pubkey_t key, size_t* estimate);
+
+BOTAN_DLL int botan_pubkey_fingerprint(botan_pubkey_t key, const char* hash,
+ uint8_t out[], size_t* out_len);
+
+/*
+* Public Key Encryption
+*/
+typedef struct botan_pk_op_encrypt_struct* botan_pk_op_encrypt_t;
+
+BOTAN_DLL int botan_pk_op_encrypt_create(botan_pk_op_encrypt_t* op,
+ botan_pubkey_t key,
+ const char* padding,
+ uint32_t flags);
+
+BOTAN_DLL int botan_pk_op_encrypt_destroy(botan_pk_op_encrypt_t op);
+
+BOTAN_DLL int botan_pk_op_encrypt(botan_pk_op_encrypt_t op,
+ botan_rng_t rng,
+ uint8_t out[], size_t* out_len,
+ const uint8_t plaintext[], size_t plaintext_len);
+
+/*
+* Public Key Decryption
+*/
+typedef struct botan_pk_op_decrypt_struct* botan_pk_op_decrypt_t;
+
+BOTAN_DLL int botan_pk_op_decrypt_create(botan_pk_op_decrypt_t* op,
+ botan_privkey_t key,
+ const char* padding,
+ uint32_t flags);
+BOTAN_DLL int botan_pk_op_decrypt_destroy(botan_pk_op_decrypt_t op);
+
+BOTAN_DLL int botan_pk_op_decrypt(botan_pk_op_decrypt_t op,
+ uint8_t out[], size_t* out_len,
+ uint8_t ciphertext[], size_t ciphertext_len);
+
+/*
+* Signature Generation
+*/
+typedef struct botan_pk_op_sign_struct* botan_pk_op_sign_t;
+
+BOTAN_DLL int botan_pk_op_sign_create(botan_pk_op_sign_t* op,
+ botan_privkey_t key,
+ const char* hash_and_padding,
+ uint32_t flags);
+BOTAN_DLL int botan_pk_op_sign_destroy(botan_pk_op_sign_t op);
+
+BOTAN_DLL int botan_pk_op_sign_update(botan_pk_op_sign_t op, const uint8_t in[], size_t in_len);
+BOTAN_DLL int botan_pk_op_sign_finish(botan_pk_op_sign_t op, botan_rng_t rng,
+ uint8_t sig[], size_t* sig_len);
+
+/*
+* Signature Verification
+*/
+typedef struct botan_pk_op_verify_struct* botan_pk_op_verify_t;
+
+BOTAN_DLL int botan_pk_op_verify_create(botan_pk_op_verify_t* op,
+ botan_pubkey_t key,
+ const char* hash_and_padding,
+ uint32_t flags);
+BOTAN_DLL int botan_pk_op_verify_destroy(botan_pk_op_verify_t op);
+
+BOTAN_DLL int botan_pk_op_verify_update(botan_pk_op_verify_t op, const uint8_t in[], size_t in_len);
+BOTAN_DLL int botan_pk_op_verify_finish(botan_pk_op_verify_t op, const uint8_t sig[], size_t sig_len);
+
+/*
+* Key Agreement
+*/
+typedef struct botan_pk_op_ka_struct* botan_pk_op_ka_t;
+
+BOTAN_DLL int botan_pk_op_key_agreement_create(botan_pk_op_ka_t* op,
+ botan_privkey_t key,
+ const char* kdf,
+ uint32_t flags);
+BOTAN_DLL int botan_pk_op_key_agreement_destroy(botan_pk_op_ka_t op);
+
+BOTAN_DLL 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);
+
+/*
+* TLS (not yet implemented)
+*/
+#if defined(BOTAN_HAS_TLS) && 0
+
+typedef struct botan_tls_session_struct* botan_tls_session_t;
+
+// TODO: getters on session_t
+
+typedef struct botan_tls_channel_struct* botan_tls_channel_t;
+
+typedef void (*botan_tls_channel_output_fn)(void, const uin8_t*, size_t);
+typedef void (*botan_tls_channel_data_cb)(void, const uin8_t*, size_t);
+typedef void (*botan_tls_channel_alert_cb)(void, u16bit, const char*);
+typedef void (*botan_tls_channel_session_established)(void, botan_tls_session_t);
+
+BOTAN_DLL 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);
+
+BOTAN_DLL int botan_tls_channel_init_server(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);
+
+BOTAN_DLL int botan_tls_channel_received_data(botan_tls_channel_t chan,
+ const uint8_t input[], size_t len);
+
+BOTAN_DLL int botan_tls_channel_send(botan_tls_channel_t chan,
+ const uint8_t input[], size_t len);
+
+BOTAN_DLL int botan_tls_channel_send_alert(botan_tls_channel_t chan,
+ uint16_t alert, bool fatal);
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/lib/ffi/info.txt b/src/lib/ffi/info.txt
new file mode 100644
index 000000000..94a804ba0
--- /dev/null
+++ b/src/lib/ffi/info.txt
@@ -0,0 +1,12 @@
+define FFI 20150210
+
+<requires>
+aead
+filters
+kdf
+pbkdf
+pubkey
+auto_rng
+system_rng
+</requires>
+
diff --git a/src/lib/misc/hkdf/hkdf.cpp b/src/lib/kdf/hkdf/hkdf.cpp
index 49fa7e256..28f97cadb 100644
--- a/src/lib/misc/hkdf/hkdf.cpp
+++ b/src/lib/kdf/hkdf/hkdf.cpp
@@ -11,7 +11,12 @@ namespace Botan {
std::string HKDF::name() const
{
- return "HKDF(" + m_prf->name() + ")";
+ const std::string prf = m_prf->name();
+ const std::string ext = m_extractor->name();
+
+ if(prf == ext)
+ return "HKDF(" + prf + ")";
+ return "HKDF(" + ext + "," + prf + ")";
}
void HKDF::clear()
@@ -50,7 +55,7 @@ void HKDF::expand(byte output[], size_t output_len,
m_prf->update(T);
m_prf->update(info, info_len);
m_prf->update(counter++);
- T = m_prf->final();
+ m_prf->final(T);
const size_t to_write = std::min(T.size(), output_len);
copy_mem(&output[0], &T[0], to_write);
diff --git a/src/lib/misc/hkdf/hkdf.h b/src/lib/kdf/hkdf/hkdf.h
index 6bc68796b..f1ae61453 100644
--- a/src/lib/misc/hkdf/hkdf.h
+++ b/src/lib/kdf/hkdf/hkdf.h
@@ -10,6 +10,7 @@
#include <botan/mac.h>
#include <botan/hash.h>
+#include <botan/kdf.h>
namespace Botan {
diff --git a/src/lib/misc/hkdf/info.txt b/src/lib/kdf/hkdf/info.txt
index 7389e5bb1..7389e5bb1 100644
--- a/src/lib/misc/hkdf/info.txt
+++ b/src/lib/kdf/hkdf/info.txt
diff --git a/src/lib/misc/pbes2/pbes2.cpp b/src/lib/misc/pbes2/pbes2.cpp
index 17f14170d..e46286906 100644
--- a/src/lib/misc/pbes2/pbes2.cpp
+++ b/src/lib/misc/pbes2/pbes2.cpp
@@ -80,7 +80,7 @@ pbes2_encrypt(const secure_vector<byte>& key_bits,
if(cipher_spec[1] != "CBC" && cipher_spec[1] != "GCM")
throw Decoding_Error("PBE-PKCS5 v2.0: Don't know param format for " + cipher);
- std::unique_ptr<Keyed_Transform> enc(get_cipher_mode(cipher, ENCRYPTION));
+ std::unique_ptr<Cipher_Mode> enc(get_cipher_mode(cipher, ENCRYPTION));
PKCS5_PBKDF2 pbkdf(Algo_Registry<MessageAuthenticationCode>::global_registry().make(prf));
@@ -153,7 +153,7 @@ pbes2_decrypt(const secure_vector<byte>& key_bits,
const std::string prf = OIDS::lookup(prf_algo.oid);
PKCS5_PBKDF2 pbkdf(Algo_Registry<MessageAuthenticationCode>::global_registry().make(prf));
- std::unique_ptr<Keyed_Transform> dec(get_cipher_mode(cipher, DECRYPTION));
+ std::unique_ptr<Cipher_Mode> dec(get_cipher_mode(cipher, DECRYPTION));
if(key_length == 0)
key_length = dec->key_spec().maximum_keylength();
diff --git a/src/lib/pbkdf/pbkdf2/pbkdf2.cpp b/src/lib/pbkdf/pbkdf2/pbkdf2.cpp
index fedf036a3..146dd15b0 100644
--- a/src/lib/pbkdf/pbkdf2/pbkdf2.cpp
+++ b/src/lib/pbkdf/pbkdf2/pbkdf2.cpp
@@ -96,7 +96,7 @@ PKCS5_PBKDF2::key_derivation(size_t key_len,
avoids confusion, and likely some broken implementations
break on getting completely randomly distributed values
*/
- if(iterations % 10000 == 0)
+ if(iterations % 1000 == 0)
{
auto time_taken = std::chrono::high_resolution_clock::now() - start;
auto usec_taken = std::chrono::duration_cast<std::chrono::microseconds>(time_taken);
diff --git a/src/lib/pubkey/pubkey.cpp b/src/lib/pubkey/pubkey.cpp
index 82797094a..cea065a66 100644
--- a/src/lib/pubkey/pubkey.cpp
+++ b/src/lib/pubkey/pubkey.cpp
@@ -324,7 +324,7 @@ bool PK_Verifier::validate_signature(const secure_vector<byte>& msg,
/*
* PK_Key_Agreement Constructor
*/
-PK_Key_Agreement::PK_Key_Agreement(const PK_Key_Agreement_Key& key,
+PK_Key_Agreement::PK_Key_Agreement(const Private_Key& key,
const std::string& kdf_name)
{
m_op.reset(get_pk_op<PK_Ops::Key_Agreement>(key, kdf_name));
diff --git a/src/lib/pubkey/pubkey.h b/src/lib/pubkey/pubkey.h
index 55afbf0fa..7341cb9c8 100644
--- a/src/lib/pubkey/pubkey.h
+++ b/src/lib/pubkey/pubkey.h
@@ -381,8 +381,7 @@ class BOTAN_DLL PK_Key_Agreement
* @param key the key to use
* @param kdf name of the KDF to use (or 'Raw' for no KDF)
*/
- PK_Key_Agreement(const PK_Key_Agreement_Key& key,
- const std::string& kdf);
+ PK_Key_Agreement(const Private_Key& key, const std::string& kdf);
private:
std::unique_ptr<PK_Ops::Key_Agreement> m_op;
std::unique_ptr<KDF> m_kdf;
diff --git a/src/lib/tls/tls_exceptn.h b/src/lib/tls/tls_exceptn.h
index ae601b60b..509226094 100644
--- a/src/lib/tls/tls_exceptn.h
+++ b/src/lib/tls/tls_exceptn.h
@@ -21,14 +21,14 @@ namespace TLS {
class BOTAN_DLL TLS_Exception : public Exception
{
public:
- Alert::Type type() const noexcept { return alert_type; }
+ Alert::Type type() const { return m_alert_type; }
TLS_Exception(Alert::Type type,
const std::string& err_msg = "Unknown error") :
- Exception(err_msg), alert_type(type) {}
+ Exception(err_msg), m_alert_type(type) {}
private:
- Alert::Type alert_type;
+ Alert::Type m_alert_type;
};
/**
diff --git a/src/python/__init__.py b/src/python/__init__.py
deleted file mode 100644
index f98b5a0ec..000000000
--- a/src/python/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-from _botan import *
diff --git a/src/python/botan.py b/src/python/botan.py
new file mode 100755
index 000000000..8414308ec
--- /dev/null
+++ b/src/python/botan.py
@@ -0,0 +1,517 @@
+#!/usr/bin/python
+
+"""
+Python wrapper of the botan crypto library
+http://botan.randombit.net
+
+(C) 2015 Jack Lloyd
+
+Botan is released under the Simplified BSD License (see license.txt)
+"""
+
+import sys
+from ctypes import *
+
+"""
+Module initialization
+"""
+botan = CDLL('libbotan-1.11.so')
+
+expected_api_rev = 20150210
+botan_api_rev = botan.botan_ffi_api_version()
+
+if botan_api_rev != expected_api_rev:
+ raise Exception("Bad botan API rev got %d expected %d" % (botan_api_rev, expected_api_rev))
+
+"""
+Versions
+"""
+def version_major():
+ return botan.botan_version_major()
+
+def version_minor():
+ return botan.botan_version_minor()
+
+def version_patch():
+ return botan.botan_version_patch()
+
+def version_string():
+ botan.botan_version_string.restype = c_char_p
+ return botan.botan_version_string()
+
+"""
+RNG
+"""
+class rng(object):
+ # Can also use type "system"
+ def __init__(self, rng_type = 'user'):
+ botan.botan_rng_init.argtypes = [c_void_p, c_char_p]
+ self.rng = c_void_p(0)
+ rc = botan.botan_rng_init(byref(self.rng), rng_type)
+ if rc != 0 or self.rng is None:
+ raise Exception("No rng " + algo + " for you!")
+
+ def __del__(self):
+ botan.botan_rng_destroy.argtypes = [c_void_p]
+ botan.botan_rng_destroy(self.rng)
+
+ def reseed(self, bits = 256):
+ botan.botan_rng_reseed.argtypes = [c_void_p, c_size_t]
+ botan.botan_rng_reseed(self.rng, bits)
+
+ def get(self, length):
+ botan.botan_rng_get.argtypes = [c_void_p, POINTER(c_char), c_size_t]
+ out = create_string_buffer(length)
+ l = c_size_t(length)
+ rc = botan.botan_rng_get(self.rng, out, l)
+ return str(out.raw)
+
+"""
+Hash function
+"""
+class hash_function(object):
+ def __init__(self, algo):
+ botan.botan_hash_init.argtypes = [c_void_p, c_char_p, c_uint32]
+ flags = 0 # always zero in this API version
+ self.hash = c_void_p(0)
+ rc = botan.botan_hash_init(byref(self.hash), algo, flags)
+ if rc != 0 or self.hash is None:
+ raise Exception("No hash " + algo + " for you!")
+
+ def __del__(self):
+ botan.botan_hash_destroy.argtypes = [c_void_p]
+ botan.botan_hash_destroy(self.hash)
+
+ def clear(self):
+ botan.botan_hash_clear.argtypes = [c_void_p]
+ return botan.botan_hash_clear(self.hash)
+
+ def output_length(self):
+ botan.botan_hash_output_length.argtypes = [c_void_p,POINTER(c_size_t)]
+ l = c_size_t(0)
+ rc = botan.botan_hash_output_length(self.hash, byref(l))
+ return l.value
+
+ def update(self, x):
+ botan.botan_hash_update.argtypes = [c_void_p, POINTER(c_char), c_size_t]
+ botan.botan_hash_update(self.hash, x, len(x))
+
+ def final(self):
+ botan.botan_hash_final.argtypes = [c_void_p, POINTER(c_char)]
+ out = create_string_buffer(self.output_length())
+ botan.botan_hash_final(self.hash, out)
+ return str(out.raw)
+
+"""
+Message authentication codes
+"""
+class message_authentication_code(object):
+ def __init__(self, algo):
+ botan.botan_mac_init.argtypes = [c_void_p, c_char_p, c_uint32]
+ flags = 0 # always zero in this API version
+ self.mac = c_void_p(0)
+ rc = botan.botan_mac_init(byref(self.mac), algo, flags)
+ if rc != 0 or self.hash is None:
+ raise Exception("No mac " + algo + " for you!")
+
+ def __del__(self):
+ botan.botan_mac_destroy.argtypes = [c_void_p]
+ botan.botan_mac_destroy(self.mac)
+
+ def clear(self):
+ botan.botan_mac_clear.argtypes = [c_void_p]
+ return botan.botan_mac_clear(self.mac)
+
+ def output_length(self):
+ botan.botan_mac_output_length.argtypes = [c_void_p, POINTER(c_size_t)]
+ l = c_size_t(0)
+ rc = botan.botan_mac_output_length(self.mac, byref(l))
+ return l.value
+
+ def set_key(self, key):
+ botan.botan_mac_set_key.argtypes = [c_void_p, POINTER(c_char), c_size_t]
+ return botan.botan_mac_set_key(self.mac, k, len(k))
+
+ def update(self, x):
+ botan.botan_mac_update.argtypes = [c_void_p, POINTER(c_char), c_size_t]
+ botan.botan_mac_update(self.mac, x, len(x))
+
+ def final(self):
+ botan.botan_mac_final.argtypes = [c_void_p, POINTER(c_char)]
+ out = create_string_buffer(self.output_length())
+ botan.botan_mac_final(self.mac, out)
+ return str(out.raw)
+
+class cipher(object):
+ def __init__(self, algo, encrypt = True):
+ botan.botan_cipher_init.argtypes = [c_void_p,c_char_p, c_uint32]
+ flags = 0 if encrypt else 1
+ self.cipher = c_void_p(0)
+ rc = botan.botan_cipher_init(byref(self.cipher), algo, flags)
+ if rc != 0 or self.cipher is None:
+ raise Exception("No cipher " + algo + " for you!")
+
+ def __del__(self):
+ botan.botan_cipher_destroy.argtypes = [c_void_p]
+ botan.botan_cipher_destroy(self.cipher)
+
+ def tag_length(self):
+ botan.botan_cipher_tag_length.argtypes = [c_void_p,POINTER(c_size_t)]
+ l = c_size_t(0)
+ botan.botan_cipher_tag_size(self.cipher, byref(l))
+ return l.value
+
+ def default_nonce_length(self):
+ botan.botan_cipher_default_nonce_length.argtypes = [c_void_p, POINTER(c_size_t)]
+ l = c_size_t(0)
+ botan.botan_cipher_default_nonce_length(self.cipher, byref(l))
+ return l.value
+
+ def update_granularity(self):
+ botan.botan_cipher_update_granularity.argtypes = [c_void_p, POINTER(c_size_t)]
+ l = c_size_t(0)
+ botan.botan_cipher_update_granularity(self.cipher, byref(l))
+ return l.value
+
+ def tag_length(self):
+ botan.botan_cipher_get_tag_length.argtypes = [c_void_p, POINTER(c_size_t)]
+ l = c_size_t(0)
+ botan.botan_cipher_get_tag_length(self.cipher, byref(l))
+ return l.value
+
+ def is_authenticated(self):
+ return self.tag_length() > 0
+
+ def valid_nonce_length(self, nonce_len):
+ botan.botan_cipher_valid_nonce_length.argtypes = [c_void_p, c_size_t]
+ rc = botan.botan_cipher_valid_nonce_length(self.cipher, nonce_len)
+ if rc < 0:
+ raise Exception('Error calling valid_nonce_length')
+ return True if rc == 1 else False
+
+ def clear(self):
+ botan.botan_cipher_clear.argtypes = [c_void_p]
+ botan.botan_cipher_clear(self.cipher)
+
+ def set_key(self, key):
+ botan.botan_cipher_set_key.argtypes = [c_void_p, POINTER(c_char), c_size_t]
+ botan.botan_cipher_set_key(self.cipher, key, len(key))
+
+
+ def start(self, nonce):
+ botan.botan_cipher_start.argtypes = [c_void_p, POINTER(c_char), c_size_t]
+ botan.botan_cipher_start(self.cipher, nonce, len(nonce))
+
+ def _update(self, txt, final):
+ botan.botan_cipher_update.argtypes = [c_void_p, c_uint32,
+ POINTER(c_char), c_size_t, POINTER(c_size_t),
+ POINTER(c_char), c_size_t, POINTER(c_size_t)]
+
+ inp = txt if txt else ''
+ inp_sz = c_size_t(len(inp))
+ inp_consumed = c_size_t(0)
+ out = create_string_buffer(inp_sz.value + (self.tag_length() if final else 0))
+ out_sz = c_size_t(len(out))
+ out_written = c_size_t(0)
+ flags = c_uint32(1 if final else 0)
+
+ botan.botan_cipher_update(self.cipher, flags,
+ out, out_sz, byref(out_written),
+ inp, inp_sz, byref(inp_consumed))
+
+ # buffering not supported yet
+ assert inp_consumed.value == inp_sz.value
+ return out.raw[0:out_written.value]
+
+ def update(self, txt):
+ return self._update(txt, False)
+
+ def finish(self, txt = None):
+ return self._update(txt, True)
+
+
+"""
+Bcrypt
+TODO: might not be enabled - handle that gracefully!
+"""
+def generate_bcrypt(passwd, rng, work_factor = 10):
+ botan.botan_bcrypt_generate.argtypes = [POINTER(c_char), c_size_t, c_char_p, c_void_p, c_size_t]
+ out = create_string_buffer(61)
+ rc = botan.botan_bcrypt_generate(out, sizeof(out), passwd, rng.rng, c_size_t(work_factor))
+
+ if rc != 0:
+ raise Exception('botan bcrypt failed, error %s' % (rc))
+ return str(out.raw)
+
+def check_bcrypt(passwd, bcrypt):
+ rc = botan.botan_bcrypt_is_valid(passwd, bcrypt)
+ return (rc == 0)
+
+"""
+PBKDF
+"""
+def pbkdf(algo, password, out_len, iterations, salt):
+ botan.botan_pbkdf.argtypes = [c_char_p, POINTER(c_char), c_size_t, c_char_p, c_void_p, c_size_t, c_size_t]
+ out_buf = create_string_buffer(out_len)
+ botan.botan_pbkdf(algo, out_buf, out_len, password, salt, len(salt), iterations)
+ return out_buf.raw
+
+def pbkdf_timed(algo, password, out_len, rng, ms_to_run, salt_len = 12):
+ botan.botan_pbkdf_timed.argtypes = [c_char_p, POINTER(c_char), c_size_t, c_char_p,
+ c_void_p, c_size_t, c_size_t, POINTER(c_size_t)]
+ out_buf = create_string_buffer(out_len)
+ salt = rng.get(salt_len)
+ iterations = c_size_t(0)
+ botan.botan_pbkdf_timed(algo, out_buf, out_len, password, salt, len(salt), ms_to_run, byref(iterations))
+ return (salt,iterations.value,out_buf.raw)
+
+"""
+KDF
+"""
+def kdf(algo, secret, out_len, salt):
+ botan.botan_kdf.argtypes = [c_char_p, POINTER(c_char), c_size_t, POINTER(c_char), c_size_t, POINTER(c_char), c_size_t]
+ out_buf = create_string_buffer(out_len)
+ out_sz = c_size_t(out_len)
+ botan.botan_kdf(algo, out_buf, out_sz, secret, len(secret), salt, len(salt))
+ return out_buf.raw[0:out_sz.value]
+
+"""
+Public and private keys
+"""
+class public_key(object):
+ def __init__(self, obj = c_void_p(0)):
+ self.pubkey = obj
+
+ def __del__(self):
+ botan.botan_pubkey_destroy.argtypes = [c_void_p]
+ botan.botan_pubkey_destroy(self.pubkey)
+
+ def fingerprint(self, hash = 'SHA-256'):
+ botan.botan_pubkey_fingerprint.argtypes = [c_void_p, c_char_p,
+ POINTER(c_char), POINTER(c_size_t)]
+
+ n = hash_function(hash).output_length()
+ buf = create_string_buffer(n)
+ buf_len = c_size_t(n)
+ botan.botan_pubkey_fingerprint(self.pubkey, hash, buf, byref(buf_len))
+ return buf[0:buf_len.value].encode('hex')
+
+class private_key(object):
+ def __init__(self, alg, param, rng):
+ botan.botan_privkey_create_rsa.argtypes = [c_void_p, c_void_p, c_size_t]
+ botan.botan_privkey_create_ecdsa.argtypes = [c_void_p, c_void_p, c_char_p]
+ botan.botan_privkey_create_ecdh.argtypes = [c_void_p, c_void_p, c_char_p]
+
+ self.privkey = c_void_p(0)
+ if alg == 'rsa':
+ botan.botan_privkey_create_rsa(byref(self.privkey), rng.rng, param)
+ elif alg == 'ecdsa':
+ botan.botan_privkey_create_ecdsa(byref(self.privkey), rng.rng, param)
+ elif alg == 'ecdh':
+ botan.botan_privkey_create_ecdh(byref(self.privkey), rng.rng, param)
+ else:
+ raise Exception('Unknown public key algo ' + alg)
+
+ if self.privkey is None:
+ raise Exception('Error creating ' + alg + ' key')
+
+ def __del__(self):
+ botan.botan_privkey_destroy.argtypes = [c_void_p]
+ botan.botan_privkey_destroy(self.privkey)
+
+ def get_public_key(self):
+ botan.botan_privkey_export_pubkey.argtypes = [c_void_p, c_void_p]
+
+ pub = c_void_p(0)
+ botan.botan_privkey_export_pubkey(byref(pub), self.privkey)
+ return public_key(pub)
+
+ def export(self):
+ botan.botan_privkey_export.argtypes = [c_void_p,POINTER(c_char),c_void_p]
+
+ n = 4096
+ buf = create_string_buffer(n)
+ buf_len = c_size_t(n)
+
+ rc = botan.botan_privkey_export(self.privkey, buf, byref(buf_len))
+ if rc != 0:
+ buf = create_string_buffer(buf_len.value)
+ botan.botan_privkey_export(self.privkey, buf, byref(buf_len))
+ return buf[0:buf_len.value]
+
+
+class pk_op_encrypt(object):
+ def __init__(self, key, padding, rng):
+ botan.botan_pk_op_encrypt_create.argtypes = [c_void_p, c_void_p, c_char_p, c_uint32]
+ self.op = c_void_p(0)
+ flags = 0 # always zero in this ABI
+ botan.botan_pk_op_encrypt_create(byref(self.op), key.pubkey, padding, flags)
+ if not self.op:
+ raise Exception("No pk op for you")
+
+ def __del__(self):
+ botan.botan_pk_op_encrypt_destroy.argtypes = [c_void_p]
+ botan.botan_pk_op_encrypt_destroy(self.op)
+
+ def encrypt(self, msg, rng):
+ botan.botan_pk_op_encrypt.argtypes = [c_void_p, c_void_p,
+ POINTER(c_char), POINTER(c_size_t),
+ POINTER(c_char), c_size_t]
+
+ outbuf_sz = c_size_t(4096) #?!?!
+ outbuf = create_string_buffer(outbuf_sz.value)
+ botan.botan_pk_op_encrypt(self.op, rng.rng, outbuf, byref(outbuf_sz), msg, len(msg))
+ return outbuf.raw[0:outbuf_sz.value]
+
+class pk_op_decrypt(object):
+ def __init__(self, key, padding):
+ botan.botan_pk_op_decrypt_create.argtypes = [c_void_p, c_void_p, c_char_p, c_uint32]
+ self.op = c_void_p(0)
+ flags = 0 # always zero in this ABI
+ botan.botan_pk_op_decrypt_create(byref(self.op), key.privkey, padding, flags)
+ if not self.op:
+ raise Exception("No pk op for you")
+
+ def __del__(self):
+ botan.botan_pk_op_decrypt_destroy.argtypes = [c_void_p]
+ botan.botan_pk_op_decrypt_destroy(self.op)
+
+ def decrypt(self, msg):
+ botan.botan_pk_op_decrypt.argtypes = [c_void_p,
+ POINTER(c_char), POINTER(c_size_t),
+ POINTER(c_char), c_size_t]
+
+ outbuf_sz = c_size_t(4096) #?!?!
+ outbuf = create_string_buffer(outbuf_sz.value)
+ botan.botan_pk_op_decrypt(self.op, outbuf, byref(outbuf_sz), msg, len(msg))
+ return outbuf.raw[0:outbuf_sz.value]
+
+class pk_op_sign(object):
+ def __init__(self, key, padding):
+ botan.botan_pk_op_sign_create.argtypes = [c_void_p, c_void_p, c_char_p, c_uint32]
+ self.op = c_void_p(0)
+ flags = 0 # always zero in this ABI
+ botan.botan_pk_op_sign_create(byref(self.op), key.privkey, padding, flags)
+ if not self.op:
+ raise Exception("No pk op for you")
+
+ def __del__(self):
+ botan.botan_pk_op_sign_destroy.argtypes = [c_void_p]
+ botan.botan_pk_op_sign_destroy(self.op)
+
+ def update(self, msg):
+ botan.botan_pk_op_sign_update.argtypes = [c_void_p, POINTER(c_char), c_size_t]
+ botan.botan_pk_op_sign_update(self.op, msg, len(msg))
+
+ def finish(self, rng):
+ botan.botan_pk_op_sign_finish.argtypes = [c_void_p, c_void_p, POINTER(c_char), POINTER(c_size_t)]
+ outbuf_sz = c_size_t(4096) #?!?!
+ outbuf = create_string_buffer(outbuf_sz.value)
+ botan.botan_pk_op_sign_finish(self.op, rng.rng, outbuf, byref(outbuf_sz))
+ return outbuf.raw[0:outbuf_sz.value]
+
+class pk_op_verify(object):
+ def __init__(self, key, padding):
+ botan.botan_pk_op_verify_create.argtypes = [c_void_p, c_void_p, c_char_p, c_uint32]
+ self.op = c_void_p(0)
+ flags = 0 # always zero in this ABI
+ botan.botan_pk_op_verify_create(byref(self.op), key.pubkey, padding, flags)
+ if not self.op:
+ raise Exception("No pk op for you")
+
+ def __del__(self):
+ botan.botan_pk_op_verify_destroy.argtypes = [c_void_p]
+ botan.botan_pk_op_verify_destroy(self.op)
+
+ def update(self, msg):
+ botan.botan_pk_op_verify_update.argtypes = [c_void_p, POINTER(c_char), c_size_t]
+ botan.botan_pk_op_verify_update(self.op, msg, len(msg))
+
+ def check_signature(self, signature):
+ botan.botan_pk_op_verify_finish.argtypes = [c_void_p, POINTER(c_char), c_size_t]
+ rc = botan.botan_pk_op_verify_finish(self.op, signature, len(signature))
+ if rc == 0:
+ return True
+ return False
+
+"""
+Tests and examples
+"""
+def test():
+ print version_string()
+ print version_major(), version_minor(), version_patch()
+
+
+ print kdf('KDF2(SHA-1)', '701F3480DFE95F57941F804B1B2413EF'.decode('hex'), 7, '55A4E9DD5F4CA2EF82'.decode('hex')).encode('hex')
+
+ print pbkdf('PBKDF2(SHA-1)', '', 32, 10000, '0001020304050607'.decode('hex')).encode('hex').upper()
+ print '59B2B1143B4CB1059EC58D9722FB1C72471E0D85C6F7543BA5228526375B0127'
+
+ r = rng("user")
+ (salt,iterations,psk) = pbkdf_timed('PBKDF2(SHA-256)', 'xyz', 32, r, 200, 12)
+ print salt.encode('hex'), iterations
+ print 'x', psk.encode('hex')
+ print 'y', pbkdf('PBKDF2(SHA-256)', 'xyz', 32, iterations, salt).encode('hex')
+
+ print r.get(42).encode('hex'), r.get(13).encode('hex'), r.get(9).encode('hex')
+
+ h = hash_function('MD5')
+ assert h.output_length() == 16
+ h.update('h')
+ h.update('i')
+ print "md5", h.final().encode('hex')
+
+ gcm = cipher('AES-128/GCM')
+ gcm.set_key('00000000000000000000000000000000'.decode('hex'))
+ gcm.start('000000000000000000000000'.decode('hex'))
+ gcm.update('')
+ gcm.update('')
+ print 'gcm', gcm.finish('00000000000000000000000000000000'.decode('hex')).encode('hex')
+
+ rsapriv = private_key('rsa', 1536, r)
+
+ dec = pk_op_decrypt(rsapriv, "EME1(SHA-256)")
+
+ rsapub = rsapriv.get_public_key()
+ print rsapub.fingerprint("SHA-1")
+
+ enc = pk_op_encrypt(rsapub, "EME1(SHA-256)", r)
+
+ ctext = enc.encrypt('foof', r)
+ print ctext.encode('hex')
+ print dec.decrypt(ctext)
+
+ signer = pk_op_sign(rsapriv, 'EMSA4(SHA-384)')
+
+ signer.update('mess')
+ signer.update('age')
+ sig = signer.finish(r)
+
+ r.reseed(200)
+ print sig.encode('hex')
+
+ verify = pk_op_verify(rsapub, 'EMSA4(SHA-384)')
+
+ verify.update('mess')
+ verify.update('age')
+ print "correct sig accepted?", verify.check_signature(sig)
+
+ verify.update('mess of things')
+ verify.update('age')
+ print "bad sig accepted?", verify.check_signature(sig)
+
+ key = private_key('ecdsa', 'secp256r1', r)
+ blob = key.export()
+
+ #f = open('key.ber','wb')
+ #f.write(blob)
+ #f.close()
+
+
+def main(args = None):
+ if args is None:
+ args = sys.argv
+ test()
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/src/python/core.cpp b/src/python/core.cpp
deleted file mode 100644
index cb395ee60..000000000
--- a/src/python/core.cpp
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
-* Boost.Python module definition
-* (C) 1999-2007 Jack Lloyd
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#include <botan/pipe.h>
-#include <botan/lookup.h>
-#include <botan/cryptobox.h>
-#include <botan/pbkdf2.h>
-#include <botan/hmac.h>
-using namespace Botan;
-
-#include "python_botan.h"
-
-class Py_Cipher
- {
- public:
- Py_Cipher(std::string algo_name, std::string direction,
- std::string key);
-
- std::string cipher_noiv(const std::string& text);
-
- std::string cipher(const std::string& text,
- const std::string& iv);
-
- std::string name() const { return algo_name; }
- private:
- std::string algo_name;
- Keyed_Filter* filter;
- Pipe pipe;
- };
-
-std::string Py_Cipher::cipher(const std::string& input,
- const std::string& iv_str)
- {
- if(iv_str.size())
- {
- const byte* iv_bytes = reinterpret_cast<const byte*>(iv_str.data());
- u32bit iv_len = iv_str.size();
- filter->set_iv(InitializationVector(iv_bytes, iv_len));
- }
-
- pipe.process_msg(input);
- return pipe.read_all_as_string(Pipe::LAST_MESSAGE);
- }
-
-// For IV-less algorithms
-std::string Py_Cipher::cipher_noiv(const std::string& input)
- {
- pipe.process_msg(input);
- return pipe.read_all_as_string(Pipe::LAST_MESSAGE);
- }
-
-Py_Cipher::Py_Cipher(std::string algo_name,
- std::string direction,
- std::string key_str)
- {
- const byte* key_bytes = reinterpret_cast<const byte*>(key_str.data());
- u32bit key_len = key_str.size();
-
- Cipher_Dir dir;
-
- if(direction == "encrypt")
- dir = ENCRYPTION;
- else if(direction == "decrypt")
- dir = DECRYPTION;
- else
- throw std::invalid_argument("Bad cipher direction " + direction);
-
- filter = get_cipher(algo_name, dir);
- filter->set_key(SymmetricKey(key_bytes, key_len));
- pipe.append(filter);
- }
-
-class Py_HashFunction
- {
- public:
- Py_HashFunction(const std::string& algo_name)
- {
- hash = get_hash(algo_name);
- }
-
- ~Py_HashFunction() { delete hash; }
-
- void update(const std::string& input)
- {
- hash->update(input);
- }
-
- std::string final()
- {
- std::string out(output_length(), 0);
- hash->final(reinterpret_cast<byte*>(&out[0]));
- return out;
- }
-
- std::string name() const
- {
- return hash->name();
- }
-
- u32bit output_length() const
- {
- return hash->output_length();
- }
-
- private:
- HashFunction* hash;
- };
-
-class Py_MAC
- {
- public:
-
- Py_MAC(const std::string& name, const std::string& key_str)
- {
- mac = get_mac(name);
-
- mac->set_key(reinterpret_cast<const byte*>(key_str.data()),
- key_str.size());
- }
-
- ~Py_MAC() { delete mac; }
-
- u32bit output_length() const { return mac->output_length(); }
-
- std::string name() const { return mac->name(); }
-
- void update(const std::string& in) { mac->update(in); }
-
- std::string final()
- {
- std::string out(output_length(), 0);
- mac->final(reinterpret_cast<byte*>(&out[0]));
- return out;
- }
- private:
- MessageAuthenticationCode* mac;
- };
-
-std::string cryptobox_encrypt(const std::string& in,
- const std::string& passphrase,
- Python_RandomNumberGenerator& rng)
- {
- const byte* in_bytes = reinterpret_cast<const byte*>(in.data());
-
- return CryptoBox::encrypt(in_bytes, in.size(),
- passphrase, rng.get_underlying_rng());
- }
-
-std::string cryptobox_decrypt(const std::string& in,
- const std::string& passphrase)
- {
- const byte* in_bytes = reinterpret_cast<const byte*>(in.data());
-
- return CryptoBox::decrypt(in_bytes, in.size(),
- passphrase);
- }
-
-std::string python_pbkdf2(const std::string& passphrase,
- const std::string& salt,
- u32bit iterations,
- u32bit output_size,
- const std::string& hash_fn)
- {
- PKCS5_PBKDF2 pbkdf2(new HMAC(get_hash(hash_fn)));
-
- return make_string(
- pbkdf2.derive_key(output_size,
- passphrase,
- reinterpret_cast<const byte*>(salt.data()),
- salt.size(),
- iterations).bits_of());
- }
-
-std::string python_kdf2(const std::string& param,
- const std::string& masterkey,
- u32bit outputlength)
- {
- std::unique_ptr<KDF> kdf(get_kdf("KDF2(SHA-1)"));
-
- return make_string(
- kdf->derive_key(outputlength,
- reinterpret_cast<const byte*>(masterkey.data()),
- masterkey.length(),
- param));
- }
-
-BOOST_PYTHON_MODULE(_botan)
- {
- python::class_<Python_RandomNumberGenerator>("RandomNumberGenerator")
- .def(python::init<>())
- .def("__str__", &Python_RandomNumberGenerator::name)
- .def("name", &Python_RandomNumberGenerator::name)
- .def("reseed", &Python_RandomNumberGenerator::reseed)
- .def("add_entropy", &Python_RandomNumberGenerator::add_entropy)
- .def("gen_random_byte", &Python_RandomNumberGenerator::gen_random_byte)
- .def("gen_random", &Python_RandomNumberGenerator::gen_random);
-
- python::class_<Py_Cipher, boost::noncopyable>
- ("Cipher", python::init<std::string, std::string, std::string>())
- .def("name", &Py_Cipher::name)
- .def("cipher", &Py_Cipher::cipher)
- .def("cipher", &Py_Cipher::cipher_noiv);
-
- python::class_<Py_HashFunction, boost::noncopyable>
- ("HashFunction", python::init<std::string>())
- .def("update", &Py_HashFunction::update)
- .def("final", &Py_HashFunction::final)
- .def("name", &Py_HashFunction::name)
- .def("output_length", &Py_HashFunction::output_length);
-
- python::class_<Py_MAC, boost::noncopyable>
- ("MAC", python::init<std::string, std::string>())
- .def("update", &Py_MAC::update)
- .def("final", &Py_MAC::final)
- .def("name", &Py_MAC::name)
- .def("output_length", &Py_MAC::output_length);
-
- python::def("cryptobox_encrypt", cryptobox_encrypt);
- python::def("cryptobox_decrypt", cryptobox_decrypt);
- python::def("pbkdf2", python_pbkdf2);
- python::def("derive_key", python_kdf2);
-
- export_filters();
- export_rsa();
- export_x509();
- }
diff --git a/src/python/filter.cpp b/src/python/filter.cpp
deleted file mode 100644
index dc02a05e1..000000000
--- a/src/python/filter.cpp
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
-* Boost.Python module definition
-* (C) 1999-2007 Jack Lloyd
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#include <boost/python.hpp>
-using namespace boost::python;
-
-#include <botan/pipe.h>
-#include <botan/lookup.h>
-using namespace Botan;
-
-class Py_Filter : public Filter
- {
- public:
- virtual void write_str(const std::string&) = 0;
-
- std::string name() const { return "Py_Filter_FIXME"; }
-
- void write(const byte data[], size_t length)
- {
- write_str(std::string((const char*)data, length));
- }
-
- void send_str(const std::string& str)
- {
- send((const byte*)str.data(), str.length());
- }
- };
-
-class FilterWrapper : public Py_Filter, public wrapper<Py_Filter>
- {
- public:
- void start_msg()
- {
- if(override start_msg = this->get_override("start_msg"))
- start_msg();
- }
-
- void end_msg()
- {
- if(override end_msg = this->get_override("end_msg"))
- end_msg();
- }
-
- void default_start_msg() {}
- void default_end_msg() {}
-
- virtual void write_str(const std::string& str)
- {
- this->get_override("write")(str);
- }
- };
-
-Filter* return_or_raise(Filter* filter, const std::string& name)
- {
- if(filter)
- return filter;
- throw Invalid_Argument("Filter " + name + " could not be found");
- }
-
-Filter* make_filter1(const std::string& name)
- {
- Filter* filter = 0;
-
- if(have_hash(name)) filter = new Hash_Filter(name);
- else if(name == "Hex_Encoder") filter = new Hex_Encoder;
- else if(name == "Hex_Decoder") filter = new Hex_Decoder;
- else if(name == "Base64_Encoder") filter = new Base64_Encoder;
- else if(name == "Base64_Decoder") filter = new Base64_Decoder;
-
- return return_or_raise(filter, name);
- }
-
-Filter* make_filter2(const std::string& name,
- const SymmetricKey& key)
- {
- Filter* filter = 0;
-
- if(have_mac(name))
- filter = new MAC_Filter(name, key);
- else if(have_stream_cipher(name))
- filter = new StreamCipher_Filter(name, key);
-
- return return_or_raise(filter, name);
- }
-
-// FIXME: add new wrapper for Keyed_Filter here
-Filter* make_filter3(const std::string& name,
- const SymmetricKey& key,
- Cipher_Dir direction)
- {
- return return_or_raise(
- get_cipher(name, key, direction),
- name);
- }
-
-Filter* make_filter4(const std::string& name,
- const SymmetricKey& key,
- const InitializationVector& iv,
- Cipher_Dir direction)
- {
- return return_or_raise(
- get_cipher(name, key, iv, direction),
- name);
- }
-
-void append_filter(Pipe& pipe, std::auto_ptr<Filter> filter)
- {
- pipe.append(filter.get());
- filter.release();
- }
-
-void prepend_filter(Pipe& pipe, std::auto_ptr<Filter> filter)
- {
- pipe.prepend(filter.get());
- filter.release();
- }
-
-void do_send(std::auto_ptr<FilterWrapper> filter, const std::string& data)
- {
- filter->send_str(data);
- }
-
-BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(rallas_ovls, read_all_as_string, 0, 1)
-
-void export_filters()
- {
- class_<Filter, std::auto_ptr<Filter>, boost::noncopyable>
- ("__Internal_FilterObj", no_init);
-
- def("make_filter", make_filter1,
- return_value_policy<manage_new_object>());
- def("make_filter", make_filter2,
- return_value_policy<manage_new_object>());
- def("make_filter", make_filter3,
- return_value_policy<manage_new_object>());
- def("make_filter", make_filter4,
- return_value_policy<manage_new_object>());
-
- // This might not work - Pipe will delete the filter, but Python
- // might have allocated the space with malloc() or who-knows-what -> bad
- class_<FilterWrapper, std::auto_ptr<FilterWrapper>,
- bases<Filter>, boost::noncopyable>
- ("FilterObj")
- .def("write", pure_virtual(&Py_Filter::write_str))
- .def("send", &do_send)
- .def("start_msg", &Filter::start_msg, &FilterWrapper::default_start_msg)
- .def("end_msg", &Filter::end_msg, &FilterWrapper::default_end_msg);
-
- implicitly_convertible<std::auto_ptr<FilterWrapper>,
- std::auto_ptr<Filter> >();
-
- void (Pipe::*pipe_write_str)(const std::string&) = &Pipe::write;
- void (Pipe::*pipe_process_str)(const std::string&) = &Pipe::process_msg;
-
- class_<Pipe, boost::noncopyable>("PipeObj")
- .def(init<>())
- /*
- .def_readonly("LAST_MESSAGE", &Pipe::LAST_MESSAGE)
- .def_readonly("DEFAULT_MESSAGE", &Pipe::DEFAULT_MESSAGE)
- */
- .add_property("default_msg", &Pipe::default_msg, &Pipe::set_default_msg)
- .add_property("msg_count", &Pipe::message_count)
- .def("append", append_filter)
- .def("prepend", prepend_filter)
- .def("reset", &Pipe::reset)
- .def("pop", &Pipe::pop)
- .def("end_of_data", &Pipe::end_of_data)
- .def("start_msg", &Pipe::start_msg)
- .def("end_msg", &Pipe::end_msg)
- .def("write", pipe_write_str)
- .def("process_msg", pipe_process_str)
- .def("read_all", &Pipe::read_all_as_string, rallas_ovls());
- }
diff --git a/src/python/python_botan.h b/src/python/python_botan.h
deleted file mode 100644
index c4ee6a9e0..000000000
--- a/src/python/python_botan.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
-* (C) 2009 Jack Lloyd
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#ifndef BOTAN_BOOST_PYTHON_COMMON_H__
-#define BOTAN_BOOST_PYTHON_COMMON_H__
-
-#include <botan/exceptn.h>
-#include <botan/parsing.h>
-#include <botan/secmem.h>
-using namespace Botan;
-
-#include <boost/python.hpp>
-namespace python = boost::python;
-
-extern void export_filters();
-extern void export_rsa();
-extern void export_x509();
-
-class Bad_Size : public Exception
- {
- public:
- Bad_Size(u32bit got, u32bit expected) :
- Exception("Bad size detected in Python/C++ conversion layer: got " +
- std::to_string(got) + " bytes, expected " +
- std::to_string(expected))
- {}
- };
-
-inline std::string make_string(const byte input[], u32bit length)
- {
- return std::string((const char*)input, length);
- }
-
-template<typename Alloc>
-inline std::string make_string(const std::vector<byte, Alloc>& in)
- {
- return make_string(&in[0], in.size());
- }
-
-inline void string2binary(const std::string& from, byte to[], u32bit expected)
- {
- if(from.size() != expected)
- throw Bad_Size(from.size(), expected);
- std::memcpy(to, from.data(), expected);
- }
-
-template<typename T>
-inline python::object get_owner(T* me)
- {
- return python::object(
- python::handle<>(
- python::borrowed(python::detail::wrapper_base_::get_owner(*me))));
- }
-
-class Python_RandomNumberGenerator
- {
- public:
- Python_RandomNumberGenerator()
- { rng = RandomNumberGenerator::make_rng(); }
- ~Python_RandomNumberGenerator() { delete rng; }
-
- std::string name() const { return rng->name(); }
-
- void reseed() { rng->reseed(192); }
-
- int gen_random_byte() { return rng->next_byte(); }
-
- std::string gen_random(int n)
- {
- std::string s(n, 0);
- rng->randomize(reinterpret_cast<byte*>(&s[0]), n);
- return s;
- }
-
- void add_entropy(const std::string& in)
- { rng->add_entropy(reinterpret_cast<const byte*>(in.c_str()), in.length()); }
-
- RandomNumberGenerator& get_underlying_rng() { return *rng; }
- private:
- RandomNumberGenerator* rng;
- };
-
-#endif
diff --git a/src/python/rsa.cpp b/src/python/rsa.cpp
deleted file mode 100644
index 4ba19991c..000000000
--- a/src/python/rsa.cpp
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
-* Boost.Python module definition
-* (C) 1999-2007 Jack Lloyd
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#include <botan/rsa.h>
-#include <botan/pubkey.h>
-#include <botan/x509_key.h>
-using namespace Botan;
-
-#include "python_botan.h"
-#include <sstream>
-
-std::string bigint2str(const BigInt& n)
- {
- std::ostringstream out;
- out << n;
- return out.str();
- }
-
-class Py_RSA_PrivateKey
- {
- public:
- Py_RSA_PrivateKey(std::string pem_str,
- Python_RandomNumberGenerator& rng,
- std::string pass);
- Py_RSA_PrivateKey(std::string pem_str,
- Python_RandomNumberGenerator& rng);
-
- Py_RSA_PrivateKey(u32bit bits, Python_RandomNumberGenerator& rng);
- ~Py_RSA_PrivateKey() { delete rsa_key; }
-
- std::string to_string() const
- {
- return PKCS8::PEM_encode(*rsa_key);
- }
-
- std::string to_ber() const
- {
- secure_vector<byte> bits = PKCS8::BER_encode(*rsa_key);
- return std::string(reinterpret_cast<const char*>(&bits[0]), bits.size());
- }
-
- std::string get_N() const { return bigint2str(get_bigint_N()); }
- std::string get_E() const { return bigint2str(get_bigint_E()); }
-
- const BigInt& get_bigint_N() const { return rsa_key->get_n(); }
- const BigInt& get_bigint_E() const { return rsa_key->get_e(); }
-
- std::string decrypt(const std::string& in,
- const std::string& padding);
-
- std::string sign(const std::string& in,
- const std::string& padding,
- Python_RandomNumberGenerator& rng);
- private:
- RSA_PrivateKey* rsa_key;
- };
-
-std::string Py_RSA_PrivateKey::decrypt(const std::string& in,
- const std::string& padding)
- {
- PK_Decryptor_EME dec(*rsa_key, padding);
-
- const byte* in_bytes = reinterpret_cast<const byte*>(in.data());
-
- return make_string(dec.decrypt(in_bytes, in.size()));
- }
-
-std::string Py_RSA_PrivateKey::sign(const std::string& in,
- const std::string& padding,
- Python_RandomNumberGenerator& rng)
- {
- PK_Signer sign(*rsa_key, padding);
- const byte* in_bytes = reinterpret_cast<const byte*>(in.data());
- sign.update(in_bytes, in.size());
- return make_string(sign.signature(rng.get_underlying_rng()));
- }
-
-Py_RSA_PrivateKey::Py_RSA_PrivateKey(u32bit bits,
- Python_RandomNumberGenerator& rng)
- {
- rsa_key = new RSA_PrivateKey(rng.get_underlying_rng(), bits);
- }
-
-Py_RSA_PrivateKey::Py_RSA_PrivateKey(std::string pem_str,
- Python_RandomNumberGenerator& rng)
- {
- DataSource_Memory in(pem_str);
-
- Private_Key* pkcs8_key =
- PKCS8::load_key(in,
- rng.get_underlying_rng());
-
- rsa_key = dynamic_cast<RSA_PrivateKey*>(pkcs8_key);
-
- if(!rsa_key)
- throw std::invalid_argument("Key is not an RSA key");
- }
-
-Py_RSA_PrivateKey::Py_RSA_PrivateKey(std::string pem_str,
- Python_RandomNumberGenerator& rng,
- std::string passphrase)
- {
- DataSource_Memory in(pem_str);
-
- Private_Key* pkcs8_key =
- PKCS8::load_key(in,
- rng.get_underlying_rng(),
- passphrase);
-
- rsa_key = dynamic_cast<RSA_PrivateKey*>(pkcs8_key);
-
- if(!rsa_key)
- throw std::invalid_argument("Key is not an RSA key");
- }
-
-class Py_RSA_PublicKey
- {
- public:
- Py_RSA_PublicKey(std::string pem_str);
- Py_RSA_PublicKey(const Py_RSA_PrivateKey&);
- ~Py_RSA_PublicKey() { delete rsa_key; }
-
- std::string get_N() const { return bigint2str(get_bigint_N()); }
- std::string get_E() const { return bigint2str(get_bigint_E()); }
-
- const BigInt& get_bigint_N() const { return rsa_key->get_n(); }
- const BigInt& get_bigint_E() const { return rsa_key->get_e(); }
-
- std::string to_string() const
- {
- return X509::PEM_encode(*rsa_key);
- }
-
- std::string to_ber() const
- {
- std::vector<byte> bits = X509::BER_encode(*rsa_key);
-
- return std::string(reinterpret_cast<const char*>(&bits[0]),
- bits.size());
- }
-
- std::string encrypt(const std::string& in,
- const std::string& padding,
- Python_RandomNumberGenerator& rng);
-
- bool verify(const std::string& in,
- const std::string& padding,
- const std::string& signature);
- private:
- RSA_PublicKey* rsa_key;
- };
-
-Py_RSA_PublicKey::Py_RSA_PublicKey(const Py_RSA_PrivateKey& priv)
- {
- rsa_key = new RSA_PublicKey(priv.get_bigint_N(), priv.get_bigint_E());
- }
-
-Py_RSA_PublicKey::Py_RSA_PublicKey(std::string pem_str)
- {
- DataSource_Memory in(pem_str);
- Public_Key* x509_key = X509::load_key(in);
-
- rsa_key = dynamic_cast<RSA_PublicKey*>(x509_key);
-
- if(!rsa_key)
- throw std::invalid_argument("Key is not an RSA key");
- }
-
-std::string Py_RSA_PublicKey::encrypt(const std::string& in,
- const std::string& padding,
- Python_RandomNumberGenerator& rng)
- {
- PK_Encryptor_EME enc(*rsa_key, padding);
-
- const byte* in_bytes = reinterpret_cast<const byte*>(in.data());
-
- return make_string(enc.encrypt(in_bytes, in.size(),
- rng.get_underlying_rng()));
- }
-
-bool Py_RSA_PublicKey::verify(const std::string& in,
- const std::string& signature,
- const std::string& padding)
- {
- PK_Verifier ver(*rsa_key, padding);
-
- const byte* in_bytes = reinterpret_cast<const byte*>(in.data());
- const byte* sig_bytes = reinterpret_cast<const byte*>(signature.data());
-
- ver.update(in_bytes, in.size());
- return ver.check_signature(sig_bytes, signature.size());
- }
-
-void export_rsa()
- {
- python::class_<Py_RSA_PublicKey>
- ("RSA_PublicKey", python::init<std::string>())
- .def(python::init<const Py_RSA_PrivateKey&>())
- .def("to_string", &Py_RSA_PublicKey::to_string)
- .def("to_ber", &Py_RSA_PublicKey::to_ber)
- .def("encrypt", &Py_RSA_PublicKey::encrypt)
- .def("verify", &Py_RSA_PublicKey::verify)
- .def("get_N", &Py_RSA_PublicKey::get_N)
- .def("get_E", &Py_RSA_PublicKey::get_E);
-
- python::class_<Py_RSA_PrivateKey>
- ("RSA_PrivateKey", python::init<std::string, Python_RandomNumberGenerator&, std::string>())
- .def(python::init<std::string, Python_RandomNumberGenerator&>())
- .def(python::init<u32bit, Python_RandomNumberGenerator&>())
- .def("to_string", &Py_RSA_PrivateKey::to_string)
- .def("to_ber", &Py_RSA_PrivateKey::to_ber)
- .def("decrypt", &Py_RSA_PrivateKey::decrypt)
- .def("sign", &Py_RSA_PrivateKey::sign)
- .def("get_N", &Py_RSA_PrivateKey::get_N)
- .def("get_E", &Py_RSA_PrivateKey::get_E);
- }
diff --git a/src/python/x509.cpp b/src/python/x509.cpp
deleted file mode 100644
index 48cfca2c7..000000000
--- a/src/python/x509.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
-* Boost.Python module definition
-* (C) 2009 Jack Lloyd
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#include <botan/oids.h>
-#include <botan/pipe.h>
-#include <botan/filters.h>
-#include <botan/x509cert.h>
-#include <botan/x509_crl.h>
-using namespace Botan;
-
-#include <boost/python.hpp>
-namespace python = boost::python;
-
-template<typename T>
-class vector_to_list
- {
- public:
- static PyObject* convert(const std::vector<T>& in)
- {
- python::list out;
- typename std::vector<T>::const_iterator i = in.begin();
- while(i != in.end())
- {
- out.append(*i);
- ++i;
- }
- return python::incref(out.ptr());
- }
-
- vector_to_list()
- {
- python::to_python_converter<std::vector<T>, vector_to_list<T> >();
- }
- };
-
-template<typename T>
-class memvec_to_hexstr
- {
- public:
- static PyObject* convert(const T& in)
- {
- Pipe pipe(new Hex_Encoder);
- pipe.process_msg(in);
- std::string result = pipe.read_all_as_string();
- return python::incref(python::str(result).ptr());
- }
-
- memvec_to_hexstr()
- {
- python::to_python_converter<T, memvec_to_hexstr<T> >();
- }
- };
-
-BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(add_cert_ols, add_cert, 1, 2)
-BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(validate_cert_ols, validate_cert, 1, 2)
-
-void export_x509()
- {
- vector_to_list<std::string>();
- vector_to_list<X509_Certificate>();
- memvec_to_hexstr<std::vector<byte> >();
-
- python::class_<X509_Certificate>
- ("X509_Certificate", python::init<std::string>())
- .def(python::self == python::self)
- .def(python::self != python::self)
- .add_property("version", &X509_Certificate::x509_version)
- .add_property("is_CA", &X509_Certificate::is_CA_cert)
- .add_property("self_signed", &X509_Certificate::is_self_signed)
- .add_property("pathlimit", &X509_Certificate::path_limit)
- .add_property("as_pem", &X509_Object::PEM_encode)
- .def("start_time", &X509_Certificate::start_time)
- .def("end_time", &X509_Certificate::end_time)
- .def("subject_info", &X509_Certificate::subject_info)
- .def("issuer_info", &X509_Certificate::issuer_info)
- .def("ex_constraints", &X509_Certificate::ex_constraints)
- .def("policies", &X509_Certificate::policies)
- .def("subject_key_id", &X509_Certificate::subject_key_id)
- .def("authority_key_id", &X509_Certificate::authority_key_id);
-
- python::class_<X509_CRL>
- ("X509_CRL", python::init<std::string>())
- .add_property("as_pem", &X509_Object::PEM_encode);
- }
diff --git a/src/scripts/examples/cipher.py b/src/scripts/examples/cipher.py
deleted file mode 100755
index 1be2759ae..000000000
--- a/src/scripts/examples/cipher.py
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/usr/bin/python
-
-import botan
-import sys
-
-def encrypt(input, passphrase):
- rng = botan.RandomNumberGenerator()
-
- # Use as both EAX IV and PBKDF2 salt
- salt = rng.gen_random(10)
-
- iterations = 10000
- output_size = 16
-
- key = botan.pbkdf2(passphrase, salt, iterations, output_size, "SHA-1")
-
- encryptor = botan.Cipher("AES-128/EAX", "encrypt", key)
-
- ciphertext = encryptor.cipher(input, salt)
- return (ciphertext, salt)
-
-def decrypt(input, salt, passphrase):
- iterations = 10000
- output_size = 16
-
- key = botan.pbkdf2(passphrase, salt, iterations, output_size, "SHA-1")
-
- decryptor = botan.Cipher("AES-128/EAX", "decrypt", key)
-
- return decryptor.cipher(input, salt)
-
-def main(args = None):
- if args is None:
- args = sys.argv
-
- passphrase = args[1]
- input = ''.join(open(args[2]).readlines())
-
- (ciphertext, salt) = encrypt(input, passphrase)
-
- print decrypt(ciphertext, salt, passphrase)
-
-if __name__ == '__main__':
- sys.exit(main())
diff --git a/src/scripts/examples/cryptobox.py b/src/scripts/examples/cryptobox.py
deleted file mode 100755
index f76ed6bc3..000000000
--- a/src/scripts/examples/cryptobox.py
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/usr/bin/python
-
-import sys
-import botan
-
-def main(args = None):
- if args is None:
- args = sys.argv
-
- if len(args) != 3:
- raise Exception("Usage: <password> <input>");
-
- password = args[1]
- input = ''.join(open(args[2]).readlines())
-
- rng = botan.RandomNumberGenerator()
-
- ciphertext = botan.cryptobox_encrypt(input, password, rng)
-
- print ciphertext
-
- plaintext = ''
-
- try:
- plaintext = botan.cryptobox_decrypt(ciphertext, password + 'FAIL')
- except Exception, e:
- print "Good news: bad password caused exception: "
- print e
-
- plaintext = botan.cryptobox_decrypt(ciphertext, password)
-
- print "Original input was: "
- print plaintext
-
-if __name__ == '__main__':
- sys.exit(main())
diff --git a/src/scripts/examples/nisttest.py b/src/scripts/examples/nisttest.py
deleted file mode 100755
index 1260b1226..000000000
--- a/src/scripts/examples/nisttest.py
+++ /dev/null
@@ -1,61 +0,0 @@
-#!/usr/bin/python
-
-import sys, os, botan
-from os.path import join;
-
-def validate(ca_certs, certs, crls, ee_certs):
- store = botan.X509_Store()
- for cert in certs:
- if cert not in ee_certs:
- store.add_cert(botan.X509_Certificate(cert), cert in ca_certs)
-
- for crl in crls:
- r = store.add_crl(botan.X509_CRL(crl))
- if r != botan.verify_result.verified:
- return r
-
- for ee in ee_certs:
- r = store.validate(botan.X509_Certificate(ee))
- if r != botan.verify_result.verified:
- return r
-
- return botan.verify_result.verified
-
-def run_test(files, rootdir, testname, expected):
- crls = [join(rootdir,x) for x in files if x.endswith(".crl")]
- certs = [join(rootdir,x) for x in files if x.endswith(".crt")]
- end_entity = [x for x in certs if x.find("end.crt") != -1]
- ca_certs = [x for x in certs if x.find("root.crt") != -1]
-
- print "%s..." % testname,
-
- result = validate(ca_certs, certs, crls, end_entity)
- result = repr(result).replace('botan._botan.verify_result.', '')
-
- if result != expected:
- print "FAILED: got %s, expected %s" % (result, expected)
- else:
- print "passed"
-
-def main():
- def load_results(file):
- results = {}
- for line in open(file, 'r'):
- line = line[0:line.find('#')].strip()
- if line:
- test,result = line.split(' ')
- results[test] = result
- return results
-
- results = load_results('results.vec')
-
- for root, dirs, files in os.walk('../../checks/nist_tests/tests'):
- if files:
- thistest = root[root.rfind('/')+1:]
- if thistest in results:
- run_test(files, root, thistest, results[thistest])
- else:
- print "%s... skipping - no expected result set" % thistest
-
-if __name__ == "__main__":
- sys.exit(main())
diff --git a/src/scripts/examples/results.vec b/src/scripts/examples/results.vec
deleted file mode 100644
index 7a3824001..000000000
--- a/src/scripts/examples/results.vec
+++ /dev/null
@@ -1,60 +0,0 @@
-# This is the file of expected results for nisttest.py
-test01 verified
-test02 signature_error
-test03 signature_error
-test04 verified
-test05 cert_not_yet_valid
-test06 cert_not_yet_valid
-test07 verified
-test08 cert_not_yet_valid
-test09 cert_has_expired
-test10 cert_has_expired
-test11 cert_has_expired
-test12 verified
-test13 cert_issuer_not_found
-test14 cert_issuer_not_found
-test15 verified
-test16 verified
-test17 verified
-test18 verified
-# changed; should be no_revocation_data_available, but I don't want to
-# force people to use CRLs
-test19 verified
-test20 cert_is_revoked
-test21 cert_is_revoked
-test22 ca_cert_not_for_cert_issuer
-test23 ca_cert_not_for_cert_issuer
-test24 verified
-test25 ca_cert_not_for_cert_issuer
-test26 verified
-test27 verified
-test28 ca_cert_not_for_cert_issuer
-test29 ca_cert_not_for_cert_issuer
-test30 verified
-test31 ca_cert_not_for_crl_issuer
-test32 ca_cert_not_for_crl_issuer
-test33 verified
-test54 cert_chain_too_long
-test55 cert_chain_too_long
-test56 verified
-test57 verified
-test58 cert_chain_too_long
-test59 cert_chain_too_long
-test60 cert_chain_too_long
-test61 cert_chain_too_long
-test62 verified
-test63 verified
-test64 signature_error
-# changed; I have no idea why this test is supposed to fail
-test65 verified
-test66 crl_issuer_not_found
-# changed; one of the CRLs has an unknown creator, so we fail
-# prior to getting to the end-entity check
-test67 crl_issuer_not_found
-test68 cert_is_revoked
-test69 cert_is_revoked
-test70 cert_is_revoked
-test71 cert_is_revoked
-test72 crl_has_expired
-test73 crl_has_expired
-test74 verified
diff --git a/src/scripts/examples/rng_test.py b/src/scripts/examples/rng_test.py
deleted file mode 100755
index 06c79b84e..000000000
--- a/src/scripts/examples/rng_test.py
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/usr/bin/python
-
-import botan
-
-rng = botan.RandomNumberGenerator()
-
-print "name", rng.name()
-
-rng.add_entropy("blah")
-
-print "random 16", rng.gen_random(16).encode("hex")
-print "random 32", rng.gen_random(32).encode("base64"),
-
-rng.reseed()
-
-for i in range(0, 10):
- print rng.gen_random_byte(),
-print
-
-rng.add_entropy("blah")
-
-print "random 16", rng.gen_random(16).encode("hex")
diff --git a/src/scripts/examples/rsa.py b/src/scripts/examples/rsa.py
deleted file mode 100755
index 998b72b7b..000000000
--- a/src/scripts/examples/rsa.py
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/usr/bin/python
-
-import botan
-
-def make_into_c_array(ber):
- output = 'static unsigned char key_data[%d] = {\n\t' % (len(ber))
-
- for (idx,c) in zip(range(len(ber)), ber):
- if idx != 0 and idx % 8 == 0:
- output += "\n\t"
- output += "0x%s, " % (c.encode('hex'))
-
- output += "\n};\n"
-
- return output
-
-rng = botan.RandomNumberGenerator()
-
-rsa_priv = botan.RSA_PrivateKey(1024, rng)
-
-print rsa_priv.to_string()
-print int(rsa_priv.get_N())
-print int(rsa_priv.get_E())
-
-rsa_pub = botan.RSA_PublicKey(rsa_priv)
-
-print make_into_c_array(rsa_pub.to_ber())
-#print make_into_c_array(rsa_priv.to_ber())
-
-key = rng.gen_random(20)
-
-ciphertext = rsa_pub.encrypt(key, 'EME1(SHA-1)', rng)
-
-print ciphertext.encode('hex')
-
-plaintext = rsa_priv.decrypt(ciphertext, 'EME1(SHA-1)')
-
-print plaintext == key
-
-signature = rsa_priv.sign(key, 'EMSA4(SHA-256)', rng)
-
-print rsa_pub.verify(key, signature, 'EMSA4(SHA-256)')
-
-# Corrupt the signature, make sure it doesn't verify
-signature = signature.replace(signature[0], '0')
-
-print rsa_pub.verify(key, signature, 'EMSA4(SHA-256)')
diff --git a/src/tests/data/pbkdf/pbkdf2.vec b/src/tests/data/pbkdf/pbkdf2.vec
index 88c2f894e..6a027721a 100644
--- a/src/tests/data/pbkdf/pbkdf2.vec
+++ b/src/tests/data/pbkdf/pbkdf2.vec
@@ -59,6 +59,27 @@ Passphrase = gwrxpqxumsdsmbmhfhmfdcvlcvngzkig
OutputLen = 64
Output = 4C9DB7BA24955225D5B845F65EF24EF1B0C6E86F2E39C8DDAA4B8ABD26082D1F350381FADEAEB560DC447AFC68A6B47E6EA1E7412F6CF7B2D82342FCCD11D3B4
+[PBKDF2(SHA-256)]
+Salt = 0001020304050607
+Iterations = 10000
+Passphrase = xyz
+OutputLen = 48
+Output = DEFD2987FA26A4672F4D16D98398432AD95E896BF619F6A6B8D4ED1FAF98E8B531B39FFB66966D0E115A6CD8E70B72D0
+
+[PBKDF2(SHA-384)]
+Salt = 0001020304050607
+Iterations = 10000
+Passphrase = xyz
+OutputLen = 48
+Output = 47A3AE920B24EDAA2BB53155808554B13FAB58DF62B81F043D9812E9F2881164DF20BBFFA54E5EE2489FA183B6718A74
+
+[PBKDF2(SHA-512)]
+Salt = 0001020304050607
+Iterations = 10000
+Passphrase = xyz
+OutputLen = 48
+Output = DAF8A734327745EB63D19054DBD4018A682CEF11086A1BFB63FDBC16158C2F8B0742802F36AEF1B1DF92ACCBEA5D31A5
+
[PBKDF2(CMAC(Blowfish))]
Salt = 24A1A50B17D63EE8394B69FC70887F4F94883D68
Iterations = 5