diff options
author | Jack Lloyd <[email protected]> | 2015-10-04 19:14:37 -0400 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2015-10-04 19:14:37 -0400 |
commit | d96833adc142c647aca4949f6f897b99480a2d79 (patch) | |
tree | 46f2c1d0ec248d00649d0c4c9c8daea51c518fdc /src | |
parent | a5097d3ab26c61c1a44cc72cb105faaca91c7746 (diff) | |
parent | 6ab96139fa5bce258972bb3678e4c106c0bfe5bd (diff) |
Merge pull request #292 from randombit/ffi-certs
Expose X.509 certificates and McEliece to C89/Python
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/cert/x509/key_constraint.h | 1 | ||||
-rw-r--r-- | src/lib/ffi/ffi.cpp | 283 | ||||
-rw-r--r-- | src/lib/ffi/ffi.h | 204 | ||||
-rw-r--r-- | src/lib/ffi/info.txt | 4 | ||||
-rwxr-xr-x | src/python/botan.py | 246 | ||||
-rw-r--r-- | src/tests/test_ffi.cpp | 2 | ||||
-rw-r--r-- | src/tests/test_mceliece.cpp | 2 |
7 files changed, 650 insertions, 92 deletions
diff --git a/src/lib/cert/x509/key_constraint.h b/src/lib/cert/x509/key_constraint.h index 22ae7a32e..3509b6868 100644 --- a/src/lib/cert/x509/key_constraint.h +++ b/src/lib/cert/x509/key_constraint.h @@ -14,6 +14,7 @@ namespace Botan { /** * X.509v3 Key Constraints. +* If updating update copy in ffi.h */ enum Key_Constraints { NO_CONSTRAINTS = 0, diff --git a/src/lib/ffi/ffi.cpp b/src/lib/ffi/ffi.cpp index 606415575..27dcc6015 100644 --- a/src/lib/ffi/ffi.cpp +++ b/src/lib/ffi/ffi.cpp @@ -13,11 +13,15 @@ #include <botan/pbkdf.h> #include <botan/version.h> #include <botan/pkcs8.h> +#include <botan/x509cert.h> +#include <botan/data_src.h> #include <botan/pubkey.h> #include <botan/data_src.h> #include <botan/hex.h> #include <botan/mem_ops.h> #include <botan/x509_key.h> +#include <botan/tls_client.h> +#include <botan/tls_server.h> #include <cstring> #include <memory> @@ -37,6 +41,15 @@ #include <botan/curve25519.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 @@ -70,6 +83,12 @@ void log_exception(const char* func_name, const char* what) fprintf(stderr, "%s: %s\n", func_name, what); } +int ffi_error_exception_thrown(const char* exn) + { + printf("exception %s\n", exn); + return BOTAN_FFI_ERROR_EXCEPTION_THROWN; + } + template<typename T, uint32_t M> T& safe_get(botan_struct<T,M>* p) { @@ -106,15 +125,19 @@ int apply_fn(botan_struct<T, M>* o, const char* func_name, F func) inline int write_output(uint8_t out[], size_t* out_len, const uint8_t buf[], size_t buf_len) { - Botan::clear_mem(out, *out_len); const size_t avail = *out_len; *out_len = buf_len; + if(avail >= buf_len) { Botan::copy_mem(out, buf, buf_len); return 0; } - return -1; + else + { + Botan::clear_mem(out, avail); + return BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE; + } } template<typename Alloc> @@ -161,12 +184,15 @@ 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); +BOTAN_FFI_DECLARE_STRUCT(botan_tls_channel_struct, Botan::TLS::Channel, 0x0212FE99); + /* * Versioning */ uint32_t botan_ffi_api_version() { - return 20150210; // should match value in info.txt + return BOTAN_HAS_FFI; } const char* botan_version_string() @@ -181,7 +207,7 @@ uint32_t botan_version_datestamp() { return Botan::version_datestamp(); } int botan_same_mem(const uint8_t* x, const uint8_t* y, size_t len) { - return Botan::same_mem(x, y, len) ? 0 : 1; + return Botan::same_mem(x, y, len) ? 0 : -1; } int botan_hex_encode(const uint8_t* in, size_t len, char* out, uint32_t flags) @@ -636,7 +662,6 @@ int botan_kdf(const char* kdf_algo, return -1; } -#if defined(BOTAN_HAS_BCRYPT) int botan_bcrypt_generate(uint8_t* out, size_t* out_len, const char* pass, botan_rng_t rng_obj, size_t wf, @@ -654,9 +679,13 @@ int botan_bcrypt_generate(uint8_t* out, size_t* out_len, if(wf < 2 || wf > 30) throw std::runtime_error("Bad bcrypt work factor " + std::to_string(wf)); +#if defined(BOTAN_HAS_BCRYPT) 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 } catch(std::exception& e) { @@ -674,9 +703,12 @@ int botan_bcrypt_is_valid(const char* pass, const char* hash) { try { +#if defined(BOTAN_HAS_BCRYPT) if(Botan::check_bcrypt(pass, hash)) return 0; // success - return 1; +#else + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif } catch(std::exception& e) { @@ -690,8 +722,6 @@ int botan_bcrypt_is_valid(const char* pass, const char* hash) return BOTAN_FFI_ERROR_EXCEPTION_THROWN; } -#endif - int botan_privkey_create_rsa(botan_privkey_t* key_obj, botan_rng_t rng_obj, size_t n_bits) { try @@ -708,6 +738,8 @@ int botan_privkey_create_rsa(botan_privkey_t* key_obj, botan_rng_t rng_obj, size std::unique_ptr<Botan::Private_Key> key(new Botan::RSA_PrivateKey(rng, n_bits)); *key_obj = new botan_privkey_struct(key.release()); return 0; +#else + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } catch(std::exception& e) @@ -734,6 +766,8 @@ int botan_privkey_create_ecdsa(botan_privkey_t* key_obj, botan_rng_t rng_obj, co std::unique_ptr<Botan::Private_Key> key(new Botan::ECDSA_PrivateKey(rng, grp)); *key_obj = new botan_privkey_struct(key.release()); return 0; +#else + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; #endif } catch(std::exception& e) @@ -744,6 +778,31 @@ int botan_privkey_create_ecdsa(botan_privkey_t* key_obj, botan_rng_t rng_obj, co return BOTAN_FFI_ERROR_EXCEPTION_THROWN; } +int botan_privkey_create_mceliece(botan_privkey_t* key_obj, botan_rng_t rng_obj, size_t n, size_t t) + { + try + { + if(key_obj == nullptr || rng_obj == nullptr || n == 0 || t == 0) + return -1; + + *key_obj = nullptr; + +#if defined(BOTAN_HAS_MCELIECE) + 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 0; +#else + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + catch(std::exception& e) + { + log_exception(BOTAN_CURRENT_FUNCTION, e.what()); + return BOTAN_FFI_ERROR_EXCEPTION_THROWN; + } + } + int botan_privkey_create_ecdh(botan_privkey_t* key_obj, botan_rng_t rng_obj, const char* param_str) { try @@ -1137,5 +1196,213 @@ int botan_pk_op_key_agreement(botan_pk_op_ka_t op, }); } +int botan_x509_cert_load_file(botan_x509_cert_t* cert_obj, const char* cert_path) + { + try + { + if(!cert_obj || !cert_path) + return -1; + + std::unique_ptr<Botan::X509_Certificate> c(new Botan::X509_Certificate(cert_path)); + + if(c) + { + *cert_obj = new botan_x509_cert_struct(c.release()); + return 0; + } + } + catch(std::exception& e) + { + log_exception(BOTAN_CURRENT_FUNCTION, e.what()); + } + catch(...) + { + log_exception(BOTAN_CURRENT_FUNCTION, "unknown"); + } + + return -2; + } + +int botan_x509_cert_load(botan_x509_cert_t* cert_obj, const uint8_t cert_bits[], size_t cert_bits_len) + { + try + { + if(!cert_obj || !cert_bits) + return -1; + + Botan::DataSource_Memory bits(cert_bits, cert_bits_len); + + std::unique_ptr<Botan::X509_Certificate> c(new Botan::X509_Certificate(bits)); + + if(c) + { + *cert_obj = new botan_x509_cert_struct(c.release()); + return 0; + } + } + catch(std::exception& e) + { + log_exception(BOTAN_CURRENT_FUNCTION, e.what()); + } + catch(...) + { + log_exception(BOTAN_CURRENT_FUNCTION, "unknown"); + } + + return -2; + + } + +int botan_x509_cert_destroy(botan_x509_cert_t cert) + { + delete cert; + return 0; + } + +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, { return write_str_output(out, out_len, cert.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, { return write_str_output(out, out_len, cert.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, { return write_vec_output(out, out_len, cert.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, { return write_str_output(out, out_len, cert.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, { return write_vec_output(out, out_len, cert.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, { return write_vec_output(out, out_len, cert.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, { return write_vec_output(out, out_len, cert.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 BOTAN_FFI_ERROR_NOT_IMPLEMENTED; + //return BOTAN_FFI_DO(Botan::X509_Certificate, cert, { return write_vec_output(out, out_len, cert.subject_public_key_bits()); }); + } + +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, { return write_str_output(out, out_len, cert.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, { return write_str_output(out, out_len, cert.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, { return write_str_output(out, out_len, cert.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, { + const Botan::Key_Constraints k = static_cast<Botan::Key_Constraints>(key_usage); + if(cert.allowed_usage(k)) + return 0; + return 1; + }); + } + +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) + { + try + { + 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 -2; + + 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 + } + catch(std::exception& e) + { + return ffi_error_exception_thrown(e.what()); + } + } + +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) + { + try + { + 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 -2; + + 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 + } + catch(std::exception& e) + { + return ffi_error_exception_thrown(e.what()); + } + } + +/* +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 a516529b4..ce2253725 100644 --- a/src/lib/ffi/ffi.h +++ b/src/lib/ffi/ffi.h @@ -1,4 +1,5 @@ /* +* FFI (C89 API) * (C) 2015 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) @@ -11,19 +12,55 @@ extern "C" { #endif -#include <botan/build.h> -#include <stdint.h> -#include <stddef.h> - /* +This header exports some of botan's functionality via a C89 +interface. This API is uesd by the Python and OCaml bindings via those +languages respective ctypes libraries. + +The API is intended to be as easy as possible to call from other +languages, which often have easy ways to call C, because C. But some C +code is easier to deal with than others, so to make things easy this +API follows a few simple rules: + +- All interactions are via pointers to opaque structs. No need to worry about + structure padding issues and the like. + +- All functions return an int error code (except the version calls, which are + assumed to always have something to say). + +- Use simple types: size_t for lengths, const char* NULL terminated strings, + uint8_t for binary. + +- No ownership of memory transfers across the API boundary. The API will + consume data from const pointers, and will produce output by writing to + variables provided by the caller. + +- If exporting a value (a string or a blob) the function takes a pointer to the + output array and a read/write pointer to the length. If the length is insufficient, an + error is returned. So passing nullptr/0 allows querying the final value. + + Note this does not apply to all functions, like `botan_hash_final` + which is not idempotent and are documented specially. But it's a + general theory of operation. + +The API is not currently documented, nor should it be considered +stable. It is buggy as heck, most likely, and error handling is a +mess. However the goal is to provide a long term API usable for +language bindings, or for use by systems written in C. Suggestions on +how to provide the cleanest API for such users would be most welcome. + * TODO: * - Better error reporting -* - User callback for exception logging +* - User callback for exception logging? * - Doxygen comments for all functions/params * - X.509 certs and PKIX path validation goo * - TLS */ +#include <botan/build.h> +#include <stdint.h> +#include <stddef.h> + /* * Versioning */ @@ -37,22 +74,57 @@ BOTAN_DLL uint32_t botan_version_datestamp(); /* * Error handling +* +* Some way of exporting these values to other languages would be useful + + + THIS FUNCTION ASSUMES BOTH ARGUMENTS ARE LITERAL STRINGS + so it retains only the pointers and does not make a copy. + +int botan_make_error(const char* msg, const char* func, int line); +* This value is returned to callers ^^ + + normally called like + return botan_make_error(BOTAN_ERROR_STRING_NOT_IMPLEMENTED, BOTAN_FUNCTION, __LINE__); + +// This would seem to require both saving the message permanently +catch(std::exception& e) { +return botan_make_error_from_transient_string(e.what(), BOTAN_FUNCTION, __LINE__); +} + +#define botan_make_error_inf(s) return botan_make_error(s, BOTAN_FUNCTION, __LINE__); + +Easier to return a const char* from each function directly? However, + +catch(std::exception& e) { return e.what(); } + +doesn't exactly work well either! + +* +* Later call: +* const char* botan_get_error_str(int); +* To recover the msg, func, and line + */ +#define BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE (-10) #define BOTAN_FFI_ERROR_EXCEPTION_THROWN (-20) #define BOTAN_FFI_ERROR_BAD_FLAG (-30) #define BOTAN_FFI_ERROR_NULL_POINTER (-31) -#define BOTAN_FFI_ERROR_NULL_POINTER (-31) +#define BOTAN_FFI_ERROR_NOT_IMPLEMENTED (-40) //const char* botan_error_description(int err); /* -* Utility +* Returns 0 if x[0..len] == y[0..len], or otherwise -1 */ BOTAN_DLL int botan_same_mem(const uint8_t* x, const uint8_t* y, size_t len); #define BOTAN_FFI_HEX_LOWER_CASE 1 BOTAN_DLL int botan_hex_encode(const uint8_t* x, size_t len, char* out, uint32_t flags); +// TODO: botan_hex_decode +// TODO: botan_base64_encode +// TODO: botan_base64_decode /* * RNG @@ -197,11 +269,11 @@ BOTAN_DLL int botan_kdf(const char* kdf_algo, /* * Bcrypt +* *out_len should be 64 bytes +* Output is formatted bcrypt $2a$... */ -#if defined(BOTAN_HAS_BCRYPT) - BOTAN_DLL int botan_bcrypt_generate(uint8_t* out, size_t* out_len, - const char* pass, + const char* password, botan_rng_t rng, size_t work_factor, uint32_t flags); @@ -213,8 +285,6 @@ BOTAN_DLL int botan_bcrypt_generate(uint8_t* out, size_t* out_len, */ BOTAN_DLL int botan_bcrypt_is_valid(const char* pass, const char* hash); -#endif - /* * Public/private key creation, import, ... */ @@ -225,7 +295,8 @@ BOTAN_DLL int botan_privkey_create_rsa(botan_privkey_t* key, botan_rng_t rng, si //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); +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; @@ -359,6 +430,82 @@ BOTAN_DLL int botan_pk_op_key_agreement(botan_pk_op_ka_t op, const uint8_t other_key[], size_t other_key_len, const uint8_t salt[], size_t salt_len); + +/* +* +* @param mce_key must be a McEliece key +* ct_len should be pt_len + n/8 + a few? +*/ +BOTAN_DLL int botan_mceies_encrypt(botan_pubkey_t mce_key, + botan_rng_t rng, + const char* aead, + const uint8_t pt[], size_t pt_len, + const uint8_t ad[], size_t ad_len, + uint8_t ct[], size_t* ct_len); + +BOTAN_DLL int botan_mceies_decrypt(botan_privkey_t mce_key, + const char* aead, + const uint8_t ct[], size_t ct_len, + const uint8_t ad[], size_t ad_len, + uint8_t pt[], size_t* pt_len); + + + +typedef struct botan_x509_cert_struct* botan_x509_cert_t; +BOTAN_DLL int botan_x509_cert_load(botan_x509_cert_t* cert_obj, const uint8_t cert[], size_t cert_len); +BOTAN_DLL int botan_x509_cert_load_file(botan_x509_cert_t* cert_obj, const char* filename); +BOTAN_DLL int botan_x509_cert_destroy(botan_x509_cert_t cert); + +BOTAN_DLL int botan_x509_cert_gen_selfsigned(botan_x509_cert_t* cert, + botan_privkey_t key, + botan_rng_t rng, + const char* common_name, + const char* org_name); + +// TODO: return botan_time_struct instead +BOTAN_DLL int botan_x509_cert_get_time_starts(botan_x509_cert_t cert, char out[], size_t* out_len); +BOTAN_DLL int botan_x509_cert_get_time_expires(botan_x509_cert_t cert, char out[], size_t* out_len); + +BOTAN_DLL int botan_x509_cert_get_fingerprint(botan_x509_cert_t cert, const char* hash, uint8_t out[], size_t* out_len); + +BOTAN_DLL int botan_x509_cert_get_serial_number(botan_x509_cert_t cert, uint8_t out[], size_t* out_len); +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); + +BOTAN_DLL int botan_x509_cert_get_public_key(botan_x509_cert_t cert, botan_pubkey_t* key); + +BOTAN_DLL 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); + +BOTAN_DLL 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); + +BOTAN_DLL int botan_x509_cert_to_string(botan_x509_cert_t cert, char out[], size_t* out_len); + +// Must match values of Key_Constraints in key_constraints.h +enum botan_x509_cert_key_constraints { + NO_CONSTRAINTS = 0, + DIGITAL_SIGNATURE = 32768, + NON_REPUDIATION = 16384, + KEY_ENCIPHERMENT = 8192, + DATA_ENCIPHERMENT = 4096, + KEY_AGREEMENT = 2048, + KEY_CERT_SIGN = 1024, + CRL_SIGN = 512, + ENCIPHER_ONLY = 256, + DECIPHER_ONLY = 128 +}; + +BOTAN_DLL int botan_x509_cert_allowed_usage(botan_x509_cert_t cert, unsigned int key_usage); + /* * TLS (WIP) */ @@ -366,16 +513,29 @@ BOTAN_DLL int botan_pk_op_key_agreement(botan_pk_op_ka_t op, typedef struct botan_tls_session_struct* botan_tls_session_t; -BOTAN_DLL int botan_tls_session_get_version(botan_tls_session_t* session, uint16_t* tls_version); -BOTAN_DLL int botan_tls_session_get_ciphersuite(botan_tls_session_t* session, uint16_t* ciphersuite); +BOTAN_DLL int botan_tls_session_decrypt(botan_tls_session_t* session, + const byte key[], size_t key_len, + const byte blob[], size_t blob_len); + +BOTAN_DLL int botan_tls_session_get_version(botan_tls_session_t session, uint16_t* tls_version); +BOTAN_DLL int botan_tls_session_get_ciphersuite(botan_tls_session_t session, uint16_t* ciphersuite); +BOTAN_DLL int botan_tls_session_encrypt(botan_tls_session_t session, botan_rng_t rng, byte key[], size_t* key_len); + +BOTAN_DLL int botan_tls_session_get_peer_certs(botan_tls_session_t session, botan_x509_cert_t certs[], size_t* cert_len); + // TODO: peer certs, validation, ... typedef struct botan_tls_channel_struct* botan_tls_channel_t; -typedef void (*botan_tls_channel_output_fn)(void*, const uint8_t*, size_t); -typedef void (*botan_tls_channel_data_cb)(void*, const uint8_t*, size_t); -typedef void (*botan_tls_channel_alert_cb)(void*, uint16_t, const char*); -typedef void (*botan_tls_channel_session_established)(void*, botan_tls_session_t); +typedef void (*botan_tls_channel_output_fn)(void* application_data, const uint8_t* data, size_t data_len); + +typedef void (*botan_tls_channel_data_cb)(void* application_data, const uint8_t* data, size_t data_len); + +typedef void (*botan_tls_channel_alert_cb)(void* application_data, uint16_t alert_code); + +typedef void (*botan_tls_channel_session_established)(void* application_data, + botan_tls_channel_t channel, + botan_tls_session_t session); BOTAN_DLL int botan_tls_channel_init_client(botan_tls_channel_t* channel, botan_tls_channel_output_fn output_fn, @@ -393,6 +553,11 @@ BOTAN_DLL int botan_tls_channel_init_server(botan_tls_channel_t* channel, BOTAN_DLL int botan_tls_channel_received_data(botan_tls_channel_t chan, const uint8_t input[], size_t len); +/** +* Returns 0 for client, 1 for server, negative for error +*/ +BOTAN_DLL int botan_tls_channel_type(botan_tls_channel_t chan); + BOTAN_DLL int botan_tls_channel_send(botan_tls_channel_t chan, const uint8_t input[], size_t len); @@ -401,7 +566,6 @@ BOTAN_DLL int botan_tls_channel_close(botan_tls_channel_t chan); BOTAN_DLL int botan_tls_channel_destroy(botan_tls_channel_t chan); #endif - #ifdef __cplusplus } #endif diff --git a/src/lib/ffi/info.txt b/src/lib/ffi/info.txt index 94a804ba0..8d6c5237e 100644 --- a/src/lib/ffi/info.txt +++ b/src/lib/ffi/info.txt @@ -1,4 +1,4 @@ -define FFI 20150210 +define FFI 20151001 <requires> aead @@ -6,6 +6,8 @@ filters kdf pbkdf pubkey +x509 +#tls auto_rng system_rng </requires> diff --git a/src/python/botan.py b/src/python/botan.py index a28f3ddb0..04e574746 100755 --- a/src/python/botan.py +++ b/src/python/botan.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 """ Python wrapper of the botan crypto library @@ -29,6 +29,40 @@ 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)) +# Internal utilities +def _call_fn_returning_string(guess, fn): + + buf = create_string_buffer(guess) + buf_len = c_size_t(len(buf)) + + rc = fn(buf, byref(buf_len)) + if rc < 0: + if buf_len.value > len(buf): + #print("Calling again with %d" % (buf_len.value)) + return _call_fn_returning_string(buf_len.value, fn) + else: + raise Exception("Call failed: %d" % (rc)) + + assert buf_len.value <= len(buf) + return str(buf.raw[0:buf_len.value]) + +def _call_fn_returning_vec(guess, fn): + + buf = create_string_buffer(guess) + buf_len = c_size_t(len(buf)) + + rc = fn(buf, byref(buf_len)) + if rc < 0: + if buf_len.value > len(buf): + #print("Calling again with %d" % (buf_len.value)) + return _call_fn_returning_vec(buf_len.value, fn) + else: + raise Exception("Call failed: %d" % (rc)) + + assert buf_len.value <= len(buf) + return buf.raw[0:buf_len.value] + + """ Versions """ @@ -57,7 +91,7 @@ class rng(object): rc = botan.botan_rng_init(byref(self.rng), rng_type) else: rc = botan.botan_rng_init(byref(self.rng), rng_type.encode('ascii')) - + if rc != 0 or self.rng is None: raise Exception("No rng " + algo + " for you!") @@ -256,7 +290,6 @@ class cipher(object): """ Bcrypt -TODO: might not be enabled - handle that gracefully! """ def bcrypt(passwd, rng, work_factor = 10): botan.botan_bcrypt_generate.argtypes = [POINTER(c_char), POINTER(c_size_t), @@ -322,12 +355,17 @@ class public_key(object): def algo_name(self): botan.botan_pubkey_algo_name.argtypes = [c_void_p, POINTER(c_char), POINTER(c_size_t)] + return _call_fn_returning_string(32, lambda b,bl: botan.botan_pubkey_algo_name(self.pubkey, b, bl)) - buf = create_string_buffer(64) - buf_len = c_size_t(len(buf)) - botan.botan_pubkey_algo_name(self.pubkey, buf, byref(buf_len)) - assert buf_len.value <= len(buf) - return buf.raw[0:buf_len.value] + def encoding(self, pem = False): + botan.botan_pubkey_export.argtypes = [c_void_p, POINTER(c_char), POINTER(c_size_t), c_uint32] + + flag = 1 if pem else 0 + + if pem: + return _call_fn_returning_string(0, lambda b,bl: botan.botan_pubkey_export(self.pubkey, b, bl, 1)) + else: + return _call_fn_returning_string(0, lambda b,bl: botan.botan_pubkey_export(self.pubkey, b, bl, 0)) def fingerprint(self, hash = 'SHA-256'): botan.botan_pubkey_fingerprint.argtypes = [c_void_p, c_char_p, @@ -338,7 +376,7 @@ class public_key(object): buf_len = c_size_t(n) if sys.version_info[0] > 2: hash = hash.encode('utf-8') - + botan.botan_pubkey_fingerprint(self.pubkey, hash, buf, byref(buf_len)) return hexlify(buf[0:buf_len.value]) @@ -347,6 +385,7 @@ class private_key(object): 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] + botan.botan_privkey_create_mceliece.argtypes = [c_void_p, c_void_p, c_size_t, c_size_t] self.privkey = c_void_p(0) if alg == 'rsa': @@ -355,6 +394,8 @@ class private_key(object): 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) + elif alg in ['mce', 'mceliece']: + botan.botan_privkey_create_mceliece(byref(self.privkey), rng.rng, param[0], param[1]) else: raise Exception('Unknown public key algo ' + alg) @@ -385,7 +426,6 @@ class private_key(object): 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): botan.botan_pk_op_encrypt_create.argtypes = [c_void_p, c_void_p, c_char_p, c_uint32] @@ -417,7 +457,7 @@ class pk_op_encrypt(object): #print("encrypt: outbuf_sz.value=%d" % outbuf_sz.value) 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] @@ -497,6 +537,24 @@ class pk_op_verify(object): return True return False +""" +MCEIES encryption +Must be used with McEliece keys +""" +def mceies_encrypt(mce, rng, aead, pt, ad): + botan.botan_mceies_encrypt.argtypes = [c_void_p, c_void_p, c_char_p, POINTER(c_char), c_size_t, + POINTER(c_char), c_size_t, POINTER(c_char), POINTER(c_size_t)] + + return _call_fn_returning_string(0, lambda b,bl: + botan.botan_mceies_encrypt(mce.pubkey, rng.rng, aead, pt, len(pt), ad, len(ad), b, bl)) + +def mceies_decrypt(mce, aead, pt, ad): + botan.botan_mceies_decrypt.argtypes = [c_void_p, c_char_p, POINTER(c_char), c_size_t, + POINTER(c_char), c_size_t, POINTER(c_char), POINTER(c_size_t)] + + return _call_fn_returning_string(0, lambda b,bl: + botan.botan_mceies_decrypt(mce.privkey, aead, pt, len(pt), ad, len(ad), b, bl)) + class pk_op_key_agreement(object): def __init__(self, key, kdf): botan.botan_pk_op_key_agreement_create.argtypes = [c_void_p, c_void_p, c_char_p, c_uint32] @@ -507,10 +565,7 @@ class pk_op_key_agreement(object): if not self.op: raise Exception("No key agreement for you") - pub = create_string_buffer(4096) - pub_len = c_size_t(len(pub)) - botan.botan_pk_op_key_agreement_export_public(key.privkey, pub, byref(pub_len)) - self.m_public_value = pub.raw[0:pub_len.value] + self.m_public_value = _call_fn_returning_string(0, lambda b, bl: botan.botan_pk_op_key_agreement_export_public(key.privkey, b, bl)) def __del__(self): botan.botan_pk_op_key_agreement_destroy.argtypes = [c_void_p] @@ -523,28 +578,73 @@ class pk_op_key_agreement(object): botan.botan_pk_op_key_agreement.argtypes = [c_void_p, POINTER(c_char), POINTER(c_size_t), POINTER(c_char), c_size_t, POINTER(c_char), c_size_t] - outbuf_sz = c_size_t(key_len) - outbuf = create_string_buffer(outbuf_sz.value) - rc = botan.botan_pk_op_key_agreement(self.op, outbuf, byref(outbuf_sz), - other, len(other), salt, len(salt)) + return _call_fn_returning_string(key_len, + lambda b,bl: botan.botan_pk_op_key_agreement(self.op, b, bl, + other, len(other), + salt, len(salt))) + +class x509_cert(object): + def __init__(self, filename): + botan.botan_x509_cert_load_file.argtypes = [POINTER(c_void_p), c_char_p] + self.x509_cert = c_void_p(0) + if sys.version_info[0] > 2: + filename = cast(filename, c_char_p) + botan.botan_x509_cert_load_file(byref(self.x509_cert), filename) + + def __del__(self): + botan.botan_x509_cert_destroy.argtypes = [c_void_p] + botan.botan_x509_cert_destroy(self.x509_cert) + + # TODO: have these convert to a python datetime + def time_starts(self): + botan.botan_x509_cert_get_time_starts.argtypes = [c_void_p, POINTER(c_char), POINTER(c_size_t)] + return _call_fn_returning_string(16, lambda b,bl: botan.botan_x509_cert_get_time_starts(self.x509_cert, b, bl)) + + def time_expires(self): + botan.botan_x509_cert_get_time_expires.argtypes = [c_void_p, POINTER(c_char), POINTER(c_size_t)] + return _call_fn_returning_string(16, lambda b,bl: botan.botan_x509_cert_get_time_expires(self.x509_cert, b, bl)) + + def to_string(self): + botan.botan_x509_cert_to_string.argtypes = [c_void_p, POINTER(c_char), POINTER(c_size_t)] + return _call_fn_returning_string(0, lambda b,bl: botan.botan_x509_cert_to_string(self.x509_cert, b, bl)) + + def fingerprint(self, hash_algo = 'SHA-256'): + botan.botan_x509_cert_get_fingerprint.argtypes = [c_void_p, c_char_p, + POINTER(c_char), POINTER(c_size_t)] + + n = hash_function(hash_algo).output_length() * 3 + if sys.version_info[0] > 2: + hash_algo = hash_algo.encode('utf-8') + + return _call_fn_returning_string(n, lambda b,bl: botan.botan_x509_cert_get_fingerprint(self.x509_cert, hash_algo, b, bl)) + + def serial_number(self): + botan.botan_x509_cert_get_serial_number.argtypes = [c_void_p, POINTER(c_char), POINTER(c_size_t)] + return _call_fn_returning_vec(0, lambda b,bl: botan.botan_x509_cert_get_serial_number(self.x509_cert, b, bl)) + + def authority_key_id(self): + botan.botan_x509_cert_get_authority_key_id.argtypes = [c_void_p, POINTER(c_char), POINTER(c_size_t)] + return _call_fn_returning_vec(0, lambda b,bl: botan.botan_x509_cert_get_authority_key_id(self.x509_cert, b, bl)) + + def subject_key_id(self): + botan.botan_x509_cert_get_subject_key_id.argtypes = [c_void_p, POINTER(c_char), POINTER(c_size_t)] + return _call_fn_returning_vec(0, lambda b,bl: botan.botan_x509_cert_get_subject_key_id(self.x509_cert, b, bl)) + + def subject_public_key_bits(self): + botan.botan_x509_cert_get_public_key_bits.argtypes = [c_void_p, POINTER(c_char), POINTER(c_size_t)] + return _call_fn_returning_vec(0, lambda b,bl: botan.botan_x509_cert_get_public_key_bits(self.x509_cert, b, bl)) - if rc == -1 and outbuf_sz.value > len(outbuf): - outbuf = create_string_buffer(outbuf_sz.value) - botan.botan_pk_op_key_agreement(self.op, outbuf, byref(outbuf_sz), - other, len(other), salt, len(salt)) - return outbuf.raw[0:outbuf_sz.value] """ Tests and examples """ def test(): - r = rng("user") + r = rng("user") print("\n%s" % version_string().decode('utf-8')) print("v%d.%d.%d\n" % (version_major(), version_minor(), version_patch())) - print("KDF2(SHA-1) %s" % hexlify(kdf('KDF2(SHA-1)'.encode('ascii'), unhexlify('701F3480DFE95F57941F804B1B2413EF'), 7, unhexlify('55A4E9DD5F4CA2EF82')) @@ -559,18 +659,12 @@ def test(): print("good output %s\n" % '59B2B1143B4CB1059EC58D9722FB1C72471E0D85C6F7543BA5228526375B0127') - - (salt,iterations,psk) = pbkdf_timed('PBKDF2(SHA-256)'.encode('ascii'), 'xyz'.encode('utf-8'), 32, 200) - if sys.version_info[0] < 3: - print("PBKDF2(SHA-256) x=timed, y=iterated; salt = %s (len=%d) #iterations = %d\n" % - (hexlify(salt), len(salt), iterations) ) - else: - print("PBKDF2(SHA-256) x=timed, y=iterated; salt = %s (len=%d) #iterations = %d\n" % - (hexlify(salt).decode('ascii'), len(salt), iterations) ) - + print("PBKDF2(SHA-256) x=timed, y=iterated; salt = %s (len=%d) #iterations = %d\n" % + (hexlify(salt).decode('ascii'), len(salt), iterations)) + print('x %s' % hexlify(psk).decode('utf-8')) print('y %s\n' % (hexlify(pbkdf('PBKDF2(SHA-256)'.encode('utf-8'), @@ -579,7 +673,7 @@ def test(): hmac = message_authentication_code('HMAC(SHA-256)'.encode('ascii')) hmac.set_key(unhexlify('0102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20')) hmac.update(unhexlify('616263')) - + hmac_output = hmac.final() if hmac_output != unhexlify('A21B1F5D4CF4F73A4DD939750F7A066A7F98CC131CB16A6692759021CFAB8181'): @@ -587,7 +681,7 @@ def test(): print("vs good: \tA21B1F5D4CF4F73A4DD939750F7A066A7F98CC131CB16A6692759021CFAB8181"); else: print("HMAC output (good): %s\n" % hexlify(hmac_output).decode('utf-8')) - + print("rng output:\n\t%s\n\t%s\n\t%s\n" % (hexlify(r.get(42)).decode('utf-8'), hexlify(r.get(13)).decode('utf-8'), @@ -642,13 +736,31 @@ def test(): print("OCB pt %s %d" % (hexlify(pt).decode('utf-8'), len(pt))) print("OCB de %s %d\n" % (hexlify(dec).decode('utf-8'), len(dec))) + + mce_priv = private_key('mce', [2960,57], r) + mce_pub = mce_priv.get_public_key() + + mce_plaintext = 'mce plaintext' + mce_ad = 'mce AD' + mce_ciphertext = mceies_encrypt(mce_pub, r, 'ChaCha20Poly1305', mce_plaintext, mce_ad) + + print "mce", len(mce_plaintext), len(mce_ciphertext) + + mce_decrypt = mceies_decrypt(mce_priv, 'ChaCha20Poly1305', mce_ciphertext, mce_ad) + + print("mce_pub %s/SHA-1 fingerprint: %s (estimated strength %s) (len %d)" % + (mce_pub.algo_name().decode('utf-8'), mce_pub.fingerprint("SHA-1").decode('utf-8'), + mce_pub.estimated_strength(), len(mce_pub.encoding()) + ) + ) + rsapriv = private_key('rsa', 1536, r) rsapub = rsapriv.get_public_key() - - print("rsapub %s/SHA-1 fingerprint: %s (estimated strength %s)" % + + print("rsapub %s SHA-1 fingerprint: %s estimated strength %d len %d" % (rsapub.algo_name().decode('utf-8'), rsapub.fingerprint("SHA-1").decode('utf-8'), - rsapub.estimated_strength() + rsapub.estimated_strength(), len(rsapub.encoding()) ) ) @@ -656,7 +768,7 @@ def test(): enc = pk_op_encrypt(rsapub, "EME1(SHA-256)".encode('utf-8')) ctext = enc.encrypt('foof'.encode('utf-8'), r) - print("ptext \'%s\'" % 'foof') + print("ptext \'%s\'" % 'foof') print("ctext \'%s\'" % hexlify(ctext).decode('utf-8')) print("decrypt \'%s\'\n" % dec.decrypt(ctext).decode('utf-8')) @@ -669,7 +781,7 @@ def test(): r.reseed(200) print("EMSA4(SHA-384) signature: %s" % hexlify(sig).decode('utf-8')) - + verify = pk_op_verify(rsapub, 'EMSA4(SHA-384)'.encode('utf-8')) verify.update('mess'.encode('utf-8')) @@ -683,32 +795,44 @@ def test(): verify.update('message'.encode('utf-8')) print("good sig accepted? %s\n" % verify.check_signature(sig)) - dh_grp = 'secp256r1'.encode('utf-8') - #dh_grp = 'curve25519'.encode('utf-8') - dh_kdf = 'KDF2(SHA-384)'.encode('utf-8') - a_dh_priv = private_key('ecdh', dh_grp, r) - a_dh_pub = a_dh_priv.get_public_key() + for dh_grps in ['secp256r1', 'curve25519']: + dh_grp = dh_grps.encode('utf-8') + dh_kdf = 'KDF2(SHA-384)'.encode('utf-8') + a_dh_priv = private_key('ecdh', dh_grp, r) + a_dh_pub = a_dh_priv.get_public_key() + + b_dh_priv = private_key('ecdh', dh_grp, r) + b_dh_pub = b_dh_priv.get_public_key() + + a_dh = pk_op_key_agreement(a_dh_priv, dh_kdf) + b_dh = pk_op_key_agreement(b_dh_priv, dh_kdf) + + print("ecdh %s pubs:\n %s\n %s\n" % + (dh_grps, + hexlify(a_dh.public_value()).decode('utf-8'), + hexlify(b_dh.public_value()).decode('utf-8'))) - b_dh_priv = private_key('ecdh', dh_grp, r) - b_dh_pub = b_dh_priv.get_public_key() + a_key = a_dh.agree(b_dh.public_value(), 20, 'salt'.encode('utf-8')) + b_key = b_dh.agree(a_dh.public_value(), 20, 'salt'.encode('utf-8')) - a_dh = pk_op_key_agreement(a_dh_priv, dh_kdf) - b_dh = pk_op_key_agreement(b_dh_priv, dh_kdf) + print("ecdh %s shared:\n %s\n %s\n" % + (dh_grps, hexlify(a_key).decode('utf-8'), hexlify(b_key).decode('utf-8'))) - print("ecdh pubs:\n %s\n %s\n" % - (hexlify(a_dh.public_value()).decode('utf-8'), - hexlify(b_dh.public_value()).decode('utf-8'))) + cert = x509_cert("src/tests/data/ecc/CSCA.CSCA.csca-germany.1.crt") + print(cert.fingerprint("SHA-1")) + print("32:42:1C:C3:EC:54:D7:E9:43:EC:51:F0:19:23:BD:85:1D:F2:1B:B9") - a_key = a_dh.agree(b_dh.public_value(), 20, 'salt'.encode('utf-8')) - b_key = b_dh.agree(a_dh.public_value(), 20, 'salt'.encode('utf-8')) + print(cert.time_starts()) + print(cert.time_expires()) - print("ecdh shared:\n %s\n %s\n" % - (hexlify(a_key).decode('utf-8'), hexlify(b_key).decode('utf-8'))) + print(hexlify(cert.serial_number())) + print(hexlify(cert.authority_key_id())) + print(hexlify(cert.subject_key_id())) + print(hexlify(cert.subject_public_key_bits())) + print(cert.to_string()) - #f = open('key.ber','wb') - #f.write(blob) - #f.close() + return def main(args = None): diff --git a/src/tests/test_ffi.cpp b/src/tests/test_ffi.cpp index 63f8a5b20..edc06f90a 100644 --- a/src/tests/test_ffi.cpp +++ b/src/tests/test_ffi.cpp @@ -193,7 +193,7 @@ TEST_CASE("FFI bcrypt", "[ffi]") CHECK_THAT(botan_bcrypt_generate(outbuf.data(), &ol, "password", rng, 10, 0), Equals(0)); botan_rng_destroy(rng); - CHECK_THAT(botan_bcrypt_is_valid("wrong", reinterpret_cast<const char*>(outbuf.data())), Equals(1)); + REQUIRE(botan_bcrypt_is_valid("wrong", reinterpret_cast<const char*>(outbuf.data())) < 0); CHECK_THAT(botan_bcrypt_is_valid("password", reinterpret_cast<const char*>(outbuf.data())), Equals(0)); } diff --git a/src/tests/test_mceliece.cpp b/src/tests/test_mceliece.cpp index 0ed62b5ea..fc20d93f7 100644 --- a/src/tests/test_mceliece.cpp +++ b/src/tests/test_mceliece.cpp @@ -180,7 +180,7 @@ size_t test_mceliece() size_t code_length = params__n__t_min_max[i]; for(size_t t = params__n__t_min_max[i+1]; t <= params__n__t_min_max[i+2]; t++) { - std::cout << "testing parameters n = " << code_length << ", t = " << t << std::endl; + //std::cout << "testing parameters n = " << code_length << ", t = " << t << std::endl; McEliece_PrivateKey sk1(rng, code_length, t); const McEliece_PublicKey& pk1 = sk1; |