Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: RoadRunnr/otp
...
head fork: RoadRunnr/otp
Checking mergeability… Don't worry, you can still create the pull request.
  • 14 commits
  • 38 files changed
  • 2 commit comments
  • 1 contributor
Commits on Mar 16, 2013
@RoadRunnr SSL: run OpenSSL tests only on cipher suites supported in OpenSSL
Erlangs SSL app can in some cases support more TLS cipher suites
that the underlying openssl version itself. So when running the
openssl connection tests we need to consider not only our own
capabilites, but openssl's as well.
9ef7c20
@RoadRunnr SSL: add TLS PSK (RFC 4279 and RFC 5487) cipher suites eac7b9b
@RoadRunnr CRYPTO: add support for RFC-2945 SRP-3 and RFC-5054 SRP-6a authentica…
…tion
3ea28f0
@RoadRunnr SSL: add TLS-SRP (RFC 5054) cipher suites 2a30fb4
@RoadRunnr SSL: add tests for PSK and SRP ciphers f346fad
@RoadRunnr SSL: enable hash_size values for sha224, sha384 and sha512
Some of the PSK and SRP ciphers default to sha384, this enables
hash_size for that cipher. It also adds sha512 and sha224 to be
prepared for further cipher enhancements.
7dd1d4b
@RoadRunnr SSL: add documentation for PSK and SRP ciphers options 0c3dff6
@RoadRunnr CRYPTO: add algorithms/0 function that returns a list off compiled in…
… crypto algorithms

add algorithms/0 function that returns a list off compiled in crypto algorithms
and make tests suites with SHA226, SHA256, SHA384 and SHA512 conditional based
on that
dad0776
@RoadRunnr SSL: replace sha256_mac() tests with crypto:algorithms() 831575a
@RoadRunnr CRYPTO: add support for Elliptic Curves to crypto app 865854d
@RoadRunnr PUBLIC_KEY: add support for Elliptic Curves to public_key app 3f91457
@RoadRunnr SSL: filter TLS cipher suites for supported algorithms 1e73d9c
Commits on Mar 17, 2013
@RoadRunnr SSL: add Elliptic Curve support for ssl app 41c4617
@RoadRunnr SSL: add Elliptic Curve ciphers unit tests 947ae83
Showing with 5,471 additions and 568 deletions.
  1. +1,081 −1 lib/crypto/c_src/crypto.c
  2. +244 −0 lib/crypto/doc/src/crypto.xml
  3. +188 −4 lib/crypto/src/crypto.erl
  4. +419 −373 lib/crypto/test/crypto_SUITE.erl
  5. +24 −0 lib/public_key/asn1/ECPrivateKey.asn1
  6. +40 −2 lib/public_key/asn1/OTP-PKIX.asn1
  7. +1 −0  lib/public_key/asn1/OTP-PUB-KEY.set.asn
  8. +32 −0 lib/public_key/asn1/PKCS-1.asn1
  9. +83 −35 lib/public_key/asn1/PKIX1Algorithms88.asn1
  10. +10 −5 lib/public_key/doc/src/public_key.xml
  11. +4 −0 lib/public_key/include/public_key.hrl
  12. +85 −3 lib/public_key/src/pubkey_cert_records.erl
  13. +14 −2 lib/public_key/src/pubkey_pem.erl
  14. +87 −3 lib/public_key/src/public_key.erl
  15. +61 −6 lib/public_key/test/erl_make_certs.erl
  16. +59 −6 lib/ssl/doc/src/ssl.xml
  17. +2 −1  lib/ssl/src/Makefile
  18. +1 −0  lib/ssl/src/ssl.app.src
  19. +36 −9 lib/ssl/src/ssl.erl
  20. +3 −1 lib/ssl/src/ssl_alert.erl
  21. +2 −0  lib/ssl/src/ssl_alert.hrl
  22. +14 −1 lib/ssl/src/ssl_certificate.erl
  23. +675 −26 lib/ssl/src/ssl_cipher.erl
  24. +219 −0 lib/ssl/src/ssl_cipher.hrl
  25. +608 −19 lib/ssl/src/ssl_connection.erl
  26. +383 −26 lib/ssl/src/ssl_handshake.erl
  27. +94 −1 lib/ssl/src/ssl_handshake.hrl
  28. +3 −0  lib/ssl/src/ssl_internal.hrl
  29. +1 −9 lib/ssl/src/ssl_record.erl
  30. +31 −0 lib/ssl/src/ssl_srp.hrl
  31. +506 −0 lib/ssl/src/ssl_srp_primes.erl
  32. +1 −0  lib/ssl/src/ssl_srp_primes.hrl
  33. +92 −1 lib/ssl/src/ssl_tls1.erl
  34. +61 −6 lib/ssl/test/erl_make_certs.erl
  35. +115 −5 lib/ssl/test/ssl_basic_SUITE.erl
  36. +4 −2 lib/ssl/test/ssl_npn_hello_SUITE.erl
  37. +172 −20 lib/ssl/test/ssl_test_lib.erl
  38. +16 −1 lib/ssl/test/ssl_to_openssl_SUITE.erl
View
1,082 lib/crypto/c_src/crypto.c
@@ -74,6 +74,19 @@
# define HAVE_DES_ede3_cfb_encrypt
#endif
+#if OPENSSL_VERSION_NUMBER >= 0x009080ffL \
+ && !defined(OPENSSL_NO_EC) \
+ && !defined(OPENSSL_NO_ECDH) \
+ && !defined(OPENSSL_NO_ECDSA)
+# define HAVE_EC
+#endif
+
+#if defined(HAVE_EC)
+#include <openssl/ec.h>
+#include <openssl/ecdh.h>
+#include <openssl/ecdsa.h>
+#endif
+
#ifdef VALGRIND
# include <valgrind/memcheck.h>
@@ -136,6 +149,7 @@ static void unload(ErlNifEnv* env, void* priv_data);
/* The NIFs: */
static ERL_NIF_TERM info_lib(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM md5(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM md5_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM md5_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
@@ -207,14 +221,25 @@ static ERL_NIF_TERM dh_generate_parameters_nif(ErlNifEnv* env, int argc, const E
static ERL_NIF_TERM dh_check(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM srp_value_B_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM srp_client_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM srp_server_secret(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM bf_cfb64_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM bf_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM bf_ecb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM blowfish_ofb64_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM ec_key_new(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM ec_key_to_term_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM term_to_ec_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM ec_key_generate(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM ecdsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM ecdsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM ecdh_compute_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
/* helpers */
+static void init_algorithms_types(void);
static void init_digest_types(ErlNifEnv* env);
static void hmac_md5(unsigned char *key, int klen,
unsigned char *dbuf, int dlen,
@@ -247,6 +272,7 @@ static int library_refc = 0; /* number of users of this dynamic library */
static ErlNifFunc nif_funcs[] = {
{"info_lib", 0, info_lib},
+ {"algorithms", 0, algorithms},
{"md5", 1, md5},
{"md5_init", 0, md5_init},
{"md5_update", 2, md5_update},
@@ -321,12 +347,120 @@ static ErlNifFunc nif_funcs[] = {
{"dh_check", 1, dh_check},
{"dh_generate_key_nif", 2, dh_generate_key_nif},
{"dh_compute_key_nif", 3, dh_compute_key_nif},
+ {"srp_value_B_nif", 5, srp_value_B_nif},
+ {"srp_client_secret_nif", 7, srp_client_secret_nif},
+ {"srp_server_secret", 5, srp_server_secret},
{"bf_cfb64_crypt", 4, bf_cfb64_crypt},
{"bf_cbc_crypt", 4, bf_cbc_crypt},
{"bf_ecb_crypt", 3, bf_ecb_crypt},
- {"blowfish_ofb64_encrypt", 3, blowfish_ofb64_encrypt}
+ {"blowfish_ofb64_encrypt", 3, blowfish_ofb64_encrypt},
+
+ {"ec_key_new", 1, ec_key_new},
+ {"ec_key_to_term_nif", 1, ec_key_to_term_nif},
+ {"term_to_ec_key_nif", 3, term_to_ec_key_nif},
+ {"ec_key_generate", 1, ec_key_generate},
+ {"ecdsa_sign_nif", 3, ecdsa_sign_nif},
+ {"ecdsa_verify_nif", 4, ecdsa_verify_nif},
+ {"ecdh_compute_key", 2, ecdh_compute_key}
+};
+
+#if defined(HAVE_EC)
+struct nid_map {
+ char *name;
+ int nid;
+ ERL_NIF_TERM atom;
};
+static struct nid_map ec_curves[] = {
+ /* prime field curves */
+ /* secg curves */
+ { "secp112r1", NID_secp112r1 },
+ { "secp112r2", NID_secp112r2 },
+ { "secp128r1", NID_secp128r1 },
+ { "secp128r2", NID_secp128r2 },
+ { "secp160k1", NID_secp160k1 },
+ { "secp160r1", NID_secp160r1 },
+ { "secp160r2", NID_secp160r2 },
+ /* SECG secp192r1 is the same as X9.62 prime192v1 */
+ { "secp192r1", NID_X9_62_prime192v1 },
+ { "secp192k1", NID_secp192k1 },
+ { "secp224k1", NID_secp224k1 },
+ { "secp224r1", NID_secp224r1 },
+ { "secp256k1", NID_secp256k1 },
+ /* SECG secp256r1 is the same as X9.62 prime256v1 */
+ { "secp256r1", NID_X9_62_prime256v1 },
+ { "secp384r1", NID_secp384r1 },
+ { "secp521r1", NID_secp521r1 },
+ /* X9.62 curves */
+ { "prime192v1", NID_X9_62_prime192v1 },
+ { "prime192v2", NID_X9_62_prime192v2 },
+ { "prime192v3", NID_X9_62_prime192v3 },
+ { "prime239v1", NID_X9_62_prime239v1 },
+ { "prime239v2", NID_X9_62_prime239v2 },
+ { "prime239v3", NID_X9_62_prime239v3 },
+ { "prime256v1", NID_X9_62_prime256v1 },
+ /* characteristic two field curves */
+ /* NIST/SECG curves */
+ { "sect113r1", NID_sect113r1 },
+ { "sect113r2", NID_sect113r2 },
+ { "sect131r1", NID_sect131r1 },
+ { "sect131r2", NID_sect131r2 },
+ { "sect163k1", NID_sect163k1 },
+ { "sect163r1", NID_sect163r1 },
+ { "sect163r2", NID_sect163r2 },
+ { "sect193r1", NID_sect193r1 },
+ { "sect193r2", NID_sect193r2 },
+ { "sect233k1", NID_sect233k1 },
+ { "sect233r1", NID_sect233r1 },
+ { "sect239k1", NID_sect239k1 },
+ { "sect283k1", NID_sect283k1 },
+ { "sect283r1", NID_sect283r1 },
+ { "sect409k1", NID_sect409k1 },
+ { "sect409r1", NID_sect409r1 },
+ { "sect571k1", NID_sect571k1 },
+ { "sect571r1", NID_sect571r1 },
+ /* X9.62 curves */
+ { "c2pnb163v1", NID_X9_62_c2pnb163v1 },
+ { "c2pnb163v2", NID_X9_62_c2pnb163v2 },
+ { "c2pnb163v3", NID_X9_62_c2pnb163v3 },
+ { "c2pnb176v1", NID_X9_62_c2pnb176v1 },
+ { "c2tnb191v1", NID_X9_62_c2tnb191v1 },
+ { "c2tnb191v2", NID_X9_62_c2tnb191v2 },
+ { "c2tnb191v3", NID_X9_62_c2tnb191v3 },
+ { "c2pnb208w1", NID_X9_62_c2pnb208w1 },
+ { "c2tnb239v1", NID_X9_62_c2tnb239v1 },
+ { "c2tnb239v2", NID_X9_62_c2tnb239v2 },
+ { "c2tnb239v3", NID_X9_62_c2tnb239v3 },
+ { "c2pnb272w1", NID_X9_62_c2pnb272w1 },
+ { "c2pnb304w1", NID_X9_62_c2pnb304w1 },
+ { "c2tnb359v1", NID_X9_62_c2tnb359v1 },
+ { "c2pnb368w1", NID_X9_62_c2pnb368w1 },
+ { "c2tnb431r1", NID_X9_62_c2tnb431r1 },
+ /* the WAP/WTLS curves
+ * [unlike SECG, spec has its own OIDs for curves from X9.62] */
+ { "wtls1", NID_wap_wsg_idm_ecid_wtls1 },
+ { "wtls3", NID_wap_wsg_idm_ecid_wtls3 },
+ { "wtls4", NID_wap_wsg_idm_ecid_wtls4 },
+ { "wtls5", NID_wap_wsg_idm_ecid_wtls5 },
+ { "wtls6", NID_wap_wsg_idm_ecid_wtls6 },
+ { "wtls7", NID_wap_wsg_idm_ecid_wtls7 },
+ { "wtls8", NID_wap_wsg_idm_ecid_wtls8 },
+ { "wtls9", NID_wap_wsg_idm_ecid_wtls9 },
+ { "wtls10", NID_wap_wsg_idm_ecid_wtls10 },
+ { "wtls11", NID_wap_wsg_idm_ecid_wtls11 },
+ { "wtls12", NID_wap_wsg_idm_ecid_wtls12 },
+ /* IPSec curves */
+ { "ipsec3", NID_ipsec3 },
+ { "ipsec4", NID_ipsec4 }
+};
+
+#define EC_CURVES_CNT (sizeof(ec_curves)/sizeof(struct nid_map))
+
+struct nif_ec_key {
+ EC_KEY *key;
+};
+#endif
+
ERL_NIF_INIT(crypto,nif_funcs,load,NULL,upgrade,unload)
@@ -377,6 +511,19 @@ static ERL_NIF_TERM atom_none;
static ERL_NIF_TERM atom_notsup;
static ERL_NIF_TERM atom_digest;
+static ERL_NIF_TERM atom_ec;
+
+#if defined(HAVE_EC)
+static ERL_NIF_TERM atom_prime_field;
+static ERL_NIF_TERM atom_characteristic_two_field;
+static ERL_NIF_TERM atom_tpbasis;
+static ERL_NIF_TERM atom_ppbasis;
+static ERL_NIF_TERM atom_onbasis;
+
+static ErlNifResourceType* res_type_ec_key;
+static void ec_key_dtor(ErlNifEnv* env, void* obj);
+#endif
+
/*
#define PRINTF_ERR0(FMT) enif_fprintf(stderr, FMT "\n")
#define PRINTF_ERR1(FMT, A1) enif_fprintf(stderr, FMT "\n", A1)
@@ -406,6 +553,7 @@ static void error_handler(void* null, const char* errstr)
static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)
{
+ int i;
ErlNifSysInfo sys_info;
get_crypto_callbacks_t* funcp;
struct crypto_callbacks* ccb;
@@ -457,7 +605,24 @@ static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)
atom_notsup = enif_make_atom(env,"notsup");
atom_digest = enif_make_atom(env,"digest");
+#if defined(HAVE_EC)
+ atom_ec = enif_make_atom(env,"ec");
+ atom_prime_field = enif_make_atom(env,"prime_field");
+ atom_characteristic_two_field = enif_make_atom(env,"characteristic_two_field");
+ atom_tpbasis = enif_make_atom(env,"tpbasis");
+ atom_ppbasis = enif_make_atom(env,"ppbasis");
+ atom_onbasis = enif_make_atom(env,"onbasis");
+
+ for (i = 0; i < EC_CURVES_CNT; i++)
+ ec_curves[i].atom = enif_make_atom(env,ec_curves[i].name);
+
+ res_type_ec_key = enif_open_resource_type(env,NULL,"crypto.EC_KEY",
+ ec_key_dtor,
+ ERL_NIF_RT_CREATE, NULL);
+#endif
+
init_digest_types(env);
+ init_algorithms_types();
#ifdef HAVE_DYNAMIC_CRYPTO_LIB
{
@@ -538,6 +703,38 @@ static void unload(ErlNifEnv* env, void* priv_data)
--library_refc;
}
+static int algos_cnt;
+static ERL_NIF_TERM algos[8]; /* increase when extending the list */
+
+static void init_algorithms_types(void)
+{
+ algos_cnt = 0;
+
+ algos[algos_cnt++] = atom_md5;
+ algos[algos_cnt++] = atom_sha;
+ algos[algos_cnt++] = atom_ripemd160;
+#ifdef HAVE_SHA224
+ algos[algos_cnt++] = atom_sha224;
+#endif
+#ifdef HAVE_SHA256
+ algos[algos_cnt++] = atom_sha256;
+#endif
+#ifdef HAVE_SHA384
+ algos[algos_cnt++] = atom_sha384;
+#endif
+#ifdef HAVE_SHA512
+ algos[algos_cnt++] = atom_sha512;
+#endif
+#if defined(HAVE_EC)
+ algos[algos_cnt++] = atom_ec;
+#endif
+}
+
+static ERL_NIF_TERM algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ return enif_make_list_from_array(env, algos, algos_cnt);
+}
+
static ERL_NIF_TERM info_lib(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
/* [{<<"OpenSSL">>,9470143,<<"OpenSSL 0.9.8k 25 Mar 2009">>}] */
@@ -1515,6 +1712,17 @@ static int get_bn_from_mpint(ErlNifEnv* env, ERL_NIF_TERM term, BIGNUM** bnp)
return 1;
}
+static int get_bn_from_bin(ErlNifEnv* env, ERL_NIF_TERM term, BIGNUM** bnp)
+{
+ ErlNifBinary bin;
+ if (!enif_inspect_binary(env,term,&bin)) {
+ return 0;
+ }
+ ERL_VALGRIND_ASSERT_MEM_DEFINED(bin.data, bin.size);
+ *bnp = BN_bin2bn(bin.data, bin.size, NULL);
+ return 1;
+}
+
static ERL_NIF_TERM rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Lo,Hi) */
BIGNUM *bn_from = NULL, *bn_to, *bn_rand;
@@ -2344,6 +2552,205 @@ static ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_T
return ret;
}
+static ERL_NIF_TERM srp_value_B_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Multiplier, Verifier, Generator, Exponent, Prime) */
+ BIGNUM *bn_verifier = NULL;
+ BIGNUM *bn_exponent, *bn_generator, *bn_prime, *bn_multiplier, *bn_result;
+ BN_CTX *bn_ctx;
+ unsigned char* ptr;
+ unsigned dlen;
+ ERL_NIF_TERM ret;
+
+ if (!get_bn_from_mpint(env, argv[0], &bn_multiplier)
+ || !get_bn_from_bin(env, argv[1], &bn_verifier)
+ || !get_bn_from_bin(env, argv[2], &bn_generator)
+ || !get_bn_from_bin(env, argv[3], &bn_exponent)
+ || !get_bn_from_bin(env, argv[4], &bn_prime)) {
+ if (bn_multiplier) BN_free(bn_multiplier);
+ if (bn_verifier) BN_free(bn_verifier);
+ if (bn_verifier) BN_free(bn_generator);
+ if (bn_verifier) BN_free(bn_exponent);
+ if (bn_verifier) BN_free(bn_prime);
+ return enif_make_badarg(env);
+ }
+
+ bn_result = BN_new();
+ bn_ctx = BN_CTX_new();
+
+ /* B = k*v + g^b % N */
+
+ /* k * v */
+ BN_mod_mul(bn_multiplier, bn_multiplier, bn_verifier, bn_prime, bn_ctx);
+
+ /* g^b % N */
+ BN_mod_exp(bn_result, bn_generator, bn_exponent, bn_prime, bn_ctx);
+
+ /* k*v + g^b % N */
+ BN_mod_add(bn_result, bn_result, bn_multiplier, bn_prime, bn_ctx);
+
+ /* check that B % N != 0, reuse bn_multiplier */
+ BN_nnmod(bn_multiplier, bn_result, bn_prime, bn_ctx);
+ if (BN_is_zero(bn_multiplier)) {
+ ret = atom_error;
+ } else {
+ dlen = BN_num_bytes(bn_result);
+ ptr = enif_make_new_binary(env, dlen, &ret);
+ BN_bn2bin(bn_result, ptr);
+ }
+ BN_free(bn_result);
+ BN_CTX_free(bn_ctx);
+ BN_free(bn_prime);
+ BN_free(bn_generator);
+ BN_free(bn_multiplier);
+ BN_free(bn_exponent);
+ BN_free(bn_verifier);
+ return ret;
+}
+
+static ERL_NIF_TERM srp_client_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (a, u, B, Multiplier, Prime, Exponent, Generator) */
+/*
+ <premaster secret> = (B - (k * g^x)) ^ (a + (u * x)) % N
+*/
+ BIGNUM *bn_exponent = NULL, *bn_a = NULL;
+ BIGNUM *bn_u, *bn_multiplier, *bn_exp2, *bn_base,
+ *bn_prime, *bn_generator, *bn_B, *bn_result;
+ BN_CTX *bn_ctx;
+ unsigned char* ptr;
+ unsigned dlen;
+ ERL_NIF_TERM ret;
+
+ if (!get_bn_from_bin(env, argv[0], &bn_a)
+ || !get_bn_from_bin(env, argv[1], &bn_u)
+ || !get_bn_from_bin(env, argv[2], &bn_B)
+ || !get_bn_from_mpint(env, argv[3], &bn_multiplier)
+ || !get_bn_from_bin(env, argv[4], &bn_generator)
+ || !get_bn_from_bin(env, argv[5], &bn_exponent)
+ || !get_bn_from_bin(env, argv[6], &bn_prime))
+ {
+ if (bn_exponent) BN_free(bn_exponent);
+ if (bn_a) BN_free(bn_a);
+ if (bn_u) BN_free(bn_u);
+ if (bn_B) BN_free(bn_B);
+ if (bn_multiplier) BN_free(bn_multiplier);
+ if (bn_generator) BN_free(bn_generator);
+ if (bn_prime) BN_free(bn_prime);
+ return enif_make_badarg(env);
+ }
+
+ bn_ctx = BN_CTX_new();
+ bn_result = BN_new();
+
+ /* check that B % N != 0 */
+ BN_nnmod(bn_result, bn_B, bn_prime, bn_ctx);
+ if (BN_is_zero(bn_result)) {
+ BN_free(bn_exponent);
+ BN_free(bn_a);
+ BN_free(bn_generator);
+ BN_free(bn_prime);
+ BN_free(bn_u);
+ BN_free(bn_B);
+ BN_CTX_free(bn_ctx);
+
+ return atom_error;
+ }
+
+ /* (B - (k * g^x)) */
+ bn_base = BN_new();
+ BN_mod_exp(bn_result, bn_generator, bn_exponent, bn_prime, bn_ctx);
+ BN_mod_mul(bn_result, bn_multiplier, bn_result, bn_prime, bn_ctx);
+ BN_mod_sub(bn_base, bn_B, bn_result, bn_prime, bn_ctx);
+
+ /* a + (u * x) */
+ bn_exp2 = BN_new();
+ BN_mod_mul(bn_result, bn_u, bn_exponent, bn_prime, bn_ctx);
+ BN_mod_add(bn_exp2, bn_a, bn_result, bn_prime, bn_ctx);
+
+ /* (B - (k * g^x)) ^ (a + (u * x)) % N */
+ BN_mod_exp(bn_result, bn_base, bn_exp2, bn_prime, bn_ctx);
+
+ dlen = BN_num_bytes(bn_result);
+ ptr = enif_make_new_binary(env, dlen, &ret);
+ BN_bn2bin(bn_result, ptr);
+ BN_free(bn_result);
+ BN_CTX_free(bn_ctx);
+
+ BN_free(bn_multiplier);
+ BN_free(bn_exp2);
+ BN_free(bn_u);
+ BN_free(bn_exponent);
+ BN_free(bn_a);
+ BN_free(bn_B);
+ BN_free(bn_base);
+ BN_free(bn_generator);
+ BN_free(bn_prime);
+ return ret;
+}
+
+static ERL_NIF_TERM srp_server_secret(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Verifier, b, u, A, Prime) */
+/*
+ <premaster secret> = (A * v^u) ^ b % N
+*/
+ BIGNUM *bn_b = NULL, *bn_verifier = NULL;
+ BIGNUM *bn_prime, *bn_A, *bn_u, *bn_base, *bn_result;
+ BN_CTX *bn_ctx;
+ unsigned char* ptr;
+ unsigned dlen;
+ ERL_NIF_TERM ret;
+
+ if (!get_bn_from_bin(env, argv[0], &bn_verifier)
+ || !get_bn_from_bin(env, argv[1], &bn_b)
+ || !get_bn_from_bin(env, argv[2], &bn_u)
+ || !get_bn_from_bin(env, argv[3], &bn_A)
+ || !get_bn_from_bin(env, argv[4], &bn_prime))
+ {
+ if (bn_verifier) BN_free(bn_verifier);
+ if (bn_b) BN_free(bn_b);
+ if (bn_u) BN_free(bn_u);
+ if (bn_A) BN_free(bn_A);
+ if (bn_prime) BN_free(bn_prime);
+ return enif_make_badarg(env);
+ }
+
+ bn_ctx = BN_CTX_new();
+ bn_result = BN_new();
+
+ /* check that A % N != 0 */
+ BN_nnmod(bn_result, bn_A, bn_prime, bn_ctx);
+ if (BN_is_zero(bn_result)) {
+ BN_free(bn_b);
+ BN_free(bn_verifier);
+ BN_free(bn_prime);
+ BN_free(bn_A);
+ BN_CTX_free(bn_ctx);
+
+ return atom_error;
+ }
+
+ /* (A * v^u) */
+ bn_base = BN_new();
+ BN_mod_exp(bn_base, bn_verifier, bn_u, bn_prime, bn_ctx);
+ BN_mod_mul(bn_base, bn_A, bn_base, bn_prime, bn_ctx);
+
+ /* (A * v^u) ^ b % N */
+ BN_mod_exp(bn_result, bn_base, bn_b, bn_prime, bn_ctx);
+
+ dlen = BN_num_bytes(bn_result);
+ ptr = enif_make_new_binary(env, dlen, &ret);
+ BN_bn2bin(bn_result, ptr);
+ BN_free(bn_result);
+ BN_CTX_free(bn_ctx);
+
+ BN_free(bn_u);
+ BN_free(bn_base);
+ BN_free(bn_verifier);
+ BN_free(bn_prime);
+ BN_free(bn_A);
+ BN_free(bn_b);
+ return ret;
+}
+
static ERL_NIF_TERM bf_cfb64_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Key, Ivec, Data, IsEncrypt) */
ErlNifBinary key_bin, ivec_bin, data_bin;
@@ -2429,7 +2836,680 @@ static ERL_NIF_TERM blowfish_ofb64_encrypt(ErlNifEnv* env, int argc, const ERL_N
return ret;
}
+#if defined(HAVE_EC)
+static int term2curve_id(ERL_NIF_TERM nid)
+{
+ int i;
+
+ for (i = 0; i < EC_CURVES_CNT; i++)
+ if (ec_curves[i].atom == nid)
+ return ec_curves[i].nid;
+
+ return 0;
+}
+
+static ERL_NIF_TERM curve_id2term(int nid)
+{
+ int i;
+
+ for (i = 0; i < EC_CURVES_CNT; i++)
+ if (ec_curves[i].nid == nid)
+ return ec_curves[i].atom;
+
+ return atom_undefined;
+}
+#endif
+
+static ERL_NIF_TERM ec_key_new(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+#if defined(HAVE_EC)
+ EC_KEY *key = NULL;
+ int nid = 0;
+ nid = term2curve_id(argv[0]);
+ if (nid == 0)
+ return enif_make_badarg(env);
+ key = EC_KEY_new_by_curve_name(nid);
+
+ if (key) {
+ ERL_NIF_TERM term;
+ struct nif_ec_key *obj = enif_alloc_resource(res_type_ec_key, sizeof(struct nif_ec_key));
+ if (!obj)
+ return atom_error;
+ obj->key = key;
+ term = enif_make_resource(env, obj);
+ enif_release_resource(obj);
+
+ return term;
+ } else
+ return enif_make_badarg(env);
+#else
+ return atom_notsup;
+#endif
+}
+
+#if defined(HAVE_EC)
+static ERL_NIF_TERM bn2term(ErlNifEnv* env, const BIGNUM *bn)
+{
+ unsigned dlen;
+ unsigned char* ptr;
+ ERL_NIF_TERM ret;
+
+ if (!bn)
+ return atom_undefined;
+
+ dlen = BN_num_bytes(bn);
+ ptr = enif_make_new_binary(env, dlen+4, &ret);
+ put_int32(ptr, dlen);
+ BN_bn2bin(bn, ptr+4);
+
+ return ret;
+}
+
+static ERL_NIF_TERM point2term(ErlNifEnv* env,
+ const EC_GROUP *group,
+ const EC_POINT *point,
+ point_conversion_form_t form)
+{
+ unsigned dlen;
+ ErlNifBinary bin;
+
+ dlen = EC_POINT_point2oct(group, point, form, NULL, 0, NULL);
+ if (dlen == 0)
+ return atom_undefined;
+
+ if (!enif_alloc_binary(dlen, &bin))
+ return enif_make_badarg(env);
+
+ if (!EC_POINT_point2oct(group, point, form, bin.data, bin.size, NULL)) {
+ enif_release_binary(&bin);
+ return enif_make_badarg(env);
+ }
+
+ return enif_make_binary(env, &bin);
+}
+#endif
+
+static ERL_NIF_TERM ec_key_to_term_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+#if defined(HAVE_EC)
+ struct nif_ec_key *obj;
+ const EC_GROUP *group;
+ const EC_POINT *public_key;
+ BIGNUM *order=NULL;
+ const BIGNUM *priv_key = NULL;
+ ERL_NIF_TERM pub_key = atom_undefined;
+ ERL_NIF_TERM group_term = atom_undefined;
+
+ if (!enif_get_resource(env, argv[0], res_type_ec_key, (void **)&obj))
+ return enif_make_badarg(env);
+
+ group = EC_KEY_get0_group(obj->key);
+ public_key = EC_KEY_get0_public_key(obj->key);
+ priv_key = EC_KEY_get0_private_key(obj->key);
+
+ if (group) {
+ if (EC_GROUP_get_curve_name(group) != 0) {
+ /* named group */
+ group_term = curve_id2term(EC_GROUP_get_curve_name(group));
+ } else {
+ /* export group paramters */
+ ERL_NIF_TERM field_term = atom_undefined;
+ ERL_NIF_TERM prime_term = atom_undefined;
+ ERL_NIF_TERM seed_term = atom_none;
+ ERL_NIF_TERM point_term = atom_none;
+ ERL_NIF_TERM order_term = atom_none;
+ ERL_NIF_TERM cofactor_term = atom_none;
+
+ int nid = 0;
+ const EC_POINT *point = NULL;
+ BIGNUM *tmp = BN_new();
+ BIGNUM *tmp_1 = BN_new();
+ BIGNUM *tmp_2 = BN_new();
+
+ nid = EC_METHOD_get_field_type(EC_GROUP_method_of(group));
+ if (nid == NID_X9_62_prime_field) {
+ /* the parameters are specified by the prime number p */
+ EC_GROUP_get_curve_GFp(group, tmp, tmp_1, tmp_2, NULL);
+
+ /* {prime_field, Prime} */
+ field_term = enif_make_tuple2(env, atom_prime_field, bn2term(env, tmp));
+ } else { /* nid == NID_X9_62_characteristic_two_field */
+ int field_type;
+ ERL_NIF_TERM basis_term;
+ ERL_NIF_TERM m_term;
+
+ EC_GROUP_get_curve_GF2m(group, NULL, tmp_1, tmp_2, NULL);
+
+ m_term = enif_make_long(env, (long)EC_GROUP_get_degree(group));
+
+ field_type = EC_GROUP_get_basis_type(group);
+ if (field_type == 0) {
+ basis_term = atom_undefined;
+ } else if (field_type == NID_X9_62_tpBasis) {
+ unsigned int k;
+ ERL_NIF_TERM k_term = atom_undefined;
+
+ if (EC_GROUP_get_trinomial_basis(group, &k))
+ k_term = enif_make_uint(env, k);
+
+ basis_term = enif_make_tuple2(env, atom_tpbasis, k_term);
+ } else if (field_type == NID_X9_62_ppBasis) {
+ unsigned int k1, k2, k3;
+ ERL_NIF_TERM k1_term = atom_undefined;
+ ERL_NIF_TERM k2_term = atom_undefined;
+ ERL_NIF_TERM k3_term = atom_undefined;
+
+ if (EC_GROUP_get_pentanomial_basis(group, &k1, &k2, &k3)) {
+ /* set k? values */
+ k1_term = enif_make_uint(env, k1);
+ k2_term = enif_make_uint(env, k2);
+ k3_term = enif_make_uint(env, k3);
+ }
+ basis_term = enif_make_tuple4(env, atom_ppbasis, k1_term, k2_term, k3_term);
+ } else { /* field_type == NID_X9_62_onBasis */
+ basis_term = atom_onbasis;
+ }
+ /* {characteristic_two_field, M, Basis} */
+ field_term = enif_make_tuple3(env, atom_characteristic_two_field, m_term, basis_term);
+ }
+
+ if (EC_GROUP_get0_seed(group)) {
+ unsigned char* ptr;
+
+ ptr = enif_make_new_binary(env, EC_GROUP_get_seed_len(group), &seed_term);
+ memcpy(ptr, EC_GROUP_get0_seed(group), EC_GROUP_get_seed_len(group));
+ }
+
+
+ /* set the base point */
+ point = EC_GROUP_get0_generator(group);
+ if (point)
+ point_term = point2term(env, group, point, EC_GROUP_get_point_conversion_form(group));
+
+ /* set the order */
+ if (EC_GROUP_get_order(group, tmp, NULL))
+ order_term = bn2term(env, tmp);
+
+ /* set the cofactor (optional) */
+ if (EC_GROUP_get_cofactor(group, tmp, NULL))
+ cofactor_term = bn2term(env, tmp);
+
+ prime_term = enif_make_tuple3(env, bn2term(env, tmp_1), bn2term(env, tmp_2), seed_term);
+ group_term = enif_make_tuple5(env, field_term, prime_term, point_term, order_term, cofactor_term);
+ BN_free(tmp);
+ BN_free(tmp_1);
+ BN_free(tmp_2);
+ }
+
+ if (public_key)
+ pub_key = point2term(env, group, public_key, EC_KEY_get_conv_form(obj->key));
+
+ if (order) BN_free(order);
+ }
+
+ return enif_make_tuple3(env, group_term, bn2term(env, priv_key), pub_key);
+#else
+ return atom_notsup;
+#endif
+}
+
+#if defined(HAVE_EC)
+static int term2point(ErlNifEnv* env, ERL_NIF_TERM term,
+ EC_GROUP *group, EC_POINT **pptr)
+{
+ int ret = 0;
+ ErlNifBinary bin;
+ EC_POINT *point;
+
+ if (!enif_inspect_binary(env,term,&bin)) {
+ return 0;
+ }
+
+ if ((*pptr = point = EC_POINT_new(group)) == NULL) {
+ return 0;
+ }
+
+ /* set the point conversion form */
+ EC_GROUP_set_point_conversion_form(group, (point_conversion_form_t)(bin.data[0] & ~0x01));
+
+ /* extract the ec point */
+ if (!EC_POINT_oct2point(group, point, bin.data, bin.size, NULL)) {
+ EC_POINT_free(point);
+ *pptr = NULL;
+ } else
+ ret = 1;
+
+ return ret;
+}
+#endif
+
+static ERL_NIF_TERM term_to_ec_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+#if defined(HAVE_EC)
+ ERL_NIF_TERM ret;
+ EC_KEY *key = NULL;
+ BIGNUM *priv_key = NULL;
+ EC_POINT *pub_key = NULL;
+ struct nif_ec_key *obj;
+ int c_arity = -1;
+ const ERL_NIF_TERM* curve;
+ ErlNifBinary seed;
+ BIGNUM *p = NULL;
+ BIGNUM *a = NULL;
+ BIGNUM *b = NULL;
+ BIGNUM *bn_order = NULL;
+ BIGNUM *cofactor = NULL;
+ EC_GROUP *group = NULL;
+ EC_POINT *point = NULL;
+
+ if (!(argv[1] == atom_undefined || get_bn_from_mpint(env, argv[1], &priv_key))
+ || !(argv[2] == atom_undefined || enif_is_binary(env, argv[2]))) {
+ printf("#1\n");
+ goto out_err;
+ }
+
+ if (enif_is_atom(env, argv[0])) {
+ int nid;
+
+ nid = term2curve_id(argv[0]);
+ if (nid == 0) {
+ printf("#2\n");
+ goto out_err;
+ }
+
+ key = EC_KEY_new_by_curve_name(nid);
+ }
+ else if (enif_is_tuple(env, argv[0])
+ && enif_get_tuple(env,argv[0],&c_arity,&curve)
+ && c_arity == 5
+ && get_bn_from_mpint(env, curve[3], &bn_order)
+ && (curve[4] != atom_none && get_bn_from_mpint(env, curve[4], &cofactor))) {
+ //* {Field, Prime, Point, Order, CoFactor} = Curve */
+
+ int f_arity = -1;
+ const ERL_NIF_TERM* field;
+ int p_arity = -1;
+ const ERL_NIF_TERM* prime;
+
+ long field_bits;
+
+ /* {A, B, Seed} = Prime */
+ if (!enif_get_tuple(env,curve[1],&p_arity,&prime)
+ || !get_bn_from_mpint(env, prime[0], &a)
+ || !get_bn_from_mpint(env, prime[1], &b))
+ goto out_err;
+
+ if (!enif_get_tuple(env,curve[0],&f_arity,&field))
+ goto out_err;
+
+ if (f_arity == 2 && field[0] == atom_prime_field) {
+ /* {prime_field, Prime} */
+
+ if (!get_bn_from_mpint(env, field[1], &p))
+ goto out_err;
+
+ if (BN_is_negative(p) || BN_is_zero(p))
+ goto out_err;
+
+ field_bits = BN_num_bits(p);
+ if (field_bits > OPENSSL_ECC_MAX_FIELD_BITS)
+ goto out_err;
+
+ /* create the EC_GROUP structure */
+ group = EC_GROUP_new_curve_GFp(p, a, b, NULL);
+
+ } else if (f_arity == 3 && field[0] == atom_characteristic_two_field) {
+ /* {characteristic_two_field, M, Basis} */
+
+ int b_arity = -1;
+ const ERL_NIF_TERM* basis;
+ unsigned int k1, k2, k3;
+
+ if ((p = BN_new()) == NULL)
+ goto out_err;
+
+ if (!enif_get_long(env, field[1], &field_bits)
+ || field_bits > OPENSSL_ECC_MAX_FIELD_BITS)
+ goto out_err;
+
+ if (enif_get_tuple(env,field[2],&b_arity,&basis)) {
+ if (b_arity == 2
+ && basis[0] == atom_tpbasis
+ && enif_get_uint(env, basis[1], &k1)) {
+ /* {tpbasis, k} = Basis */
+
+ if (!(field_bits > k1 && k1 > 0))
+ goto out_err;
+
+ /* create the polynomial */
+ if (!BN_set_bit(p, (int)field_bits)
+ || !BN_set_bit(p, (int)k1)
+ || !BN_set_bit(p, 0))
+ goto out_err;
+
+ } else if (b_arity == 4
+ && basis[0] == atom_ppbasis
+ && enif_get_uint(env, basis[1], &k1)
+ && enif_get_uint(env, basis[2], &k2)
+ && enif_get_uint(env, basis[3], &k3)) {
+ /* {ppbasis, k1, k2, k3} = Basis */
+
+ if (!(field_bits > k3 && k3 > k2 && k2 > k1 && k1 > 0))
+ goto out_err;
+
+ /* create the polynomial */
+ if (!BN_set_bit(p, (int)field_bits)
+ || !BN_set_bit(p, (int)k1)
+ || !BN_set_bit(p, (int)k2)
+ || !BN_set_bit(p, (int)k3)
+ || !BN_set_bit(p, 0))
+ goto out_err;
+
+ } else
+ goto out_err;
+ } else if (field[2] == atom_onbasis) {
+ /* onbasis = Basis */
+ /* no parameters */
+ goto out_err;
+
+ } else
+ goto out_err;
+
+ group = EC_GROUP_new_curve_GF2m(p, a, b, NULL);
+ } else
+ goto out_err;
+
+ if (enif_inspect_binary(env, prime[2], &seed)) {
+ EC_GROUP_set_seed(group, seed.data, seed.size);
+ }
+
+ if (!term2point(env, curve[2], group, &point))
+ goto out_err;
+
+ if (BN_is_negative(bn_order)
+ || BN_is_zero(bn_order)
+ || BN_num_bits(bn_order) > (int)field_bits + 1)
+ goto out_err;
+
+ if (!EC_GROUP_set_generator(group, point, bn_order, cofactor))
+ goto out_err;
+
+ EC_GROUP_set_asn1_flag(group, 0x0);
+
+ key = EC_KEY_new();
+ if (!key)
+ goto out_err;
+ EC_KEY_set_group(key, group);
+ }
+ else {
+ printf("#3\n");
+ goto out_err;
+ }
+
+ if (!key) {
+ printf("#4\n");
+ goto out_err;
+ }
+
+ if (!group)
+ group = EC_GROUP_dup(EC_KEY_get0_group(key));
+
+ if (term2point(env, argv[2], group, &pub_key)) {
+ if (!EC_KEY_set_public_key(key, pub_key)) {
+ printf("#5\n");
+ goto out_err;
+ }
+ }
+ if (argv[1] != atom_undefined
+ && !BN_is_zero(priv_key)) {
+ if (!EC_KEY_set_private_key(key, priv_key))
+ goto out_err;
+
+ /* calculate public key (if necessary) */
+ if (EC_KEY_get0_public_key(key) == NULL)
+ {
+ /* the public key was not included in the SEC1 private
+ * key => calculate the public key */
+ pub_key = EC_POINT_new(group);
+ if (pub_key == NULL
+ || !EC_POINT_copy(pub_key, EC_GROUP_get0_generator(group))
+ || !EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, NULL)
+ || !EC_KEY_set_public_key(key, pub_key))
+ goto out_err;
+ }
+ }
+
+ obj = enif_alloc_resource(res_type_ec_key, sizeof(struct nif_ec_key));
+ if (!obj)
+ goto out_err;
+
+ obj->key = key;
+ ret = enif_make_resource(env, obj);
+ enif_release_resource(obj);
+
+ goto out;
+
+out_err:
+ if (key) EC_KEY_free(key);
+ ret = enif_make_badarg(env);
+
+out:
+ /* some OpenSSL structures are mem-dup'ed into the key,
+ so we have to free our copies here */
+ if (priv_key) BN_clear_free(priv_key);
+ if (pub_key) EC_POINT_free(pub_key);
+ if (p) BN_free(p);
+ if (a) BN_free(a);
+ if (b) BN_free(b);
+ if (bn_order) BN_free(bn_order);
+ if (cofactor) BN_free(cofactor);
+ if (group) EC_GROUP_free(group);
+ return ret;
+#else
+ return atom_notsup;
+#endif
+}
+
+static ERL_NIF_TERM ec_key_generate(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+#if defined(HAVE_EC)
+ struct nif_ec_key *obj;
+
+ if (!enif_get_resource(env, argv[0], res_type_ec_key, (void **)&obj))
+ return enif_make_badarg(env);
+
+ if (EC_KEY_generate_key(obj->key))
+ return atom_ok;
+ else
+ return atom_error;
+#else
+ return atom_notsup;
+#endif
+}
+
+#if defined(HAVE_EC)
+static void ec_key_dtor(ErlNifEnv* env, void* obj)
+{
+ struct nif_ec_key *key = (struct nif_ec_key*) obj;
+ EC_KEY_free(key->key);
+}
+#endif
+
+static ERL_NIF_TERM ecdsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Type, Data|{digest,Digest}, Key) */
+#if defined(HAVE_EC)
+ ErlNifBinary data_bin, ret_bin;
+ unsigned char hmacbuf[SHA_DIGEST_LENGTH];
+ unsigned int dsa_s_len;
+ struct nif_ec_key *obj;
+ int i;
+ const ERL_NIF_TERM* tpl_terms;
+ int tpl_arity;
+ struct digest_type_t *digp;
+ unsigned char* digest;
+
+ digp = get_digest_type(argv[0]);
+ if (!digp) {
+ return enif_make_badarg(env);
+ }
+ if (!digp->len) {
+ return atom_notsup;
+ }
+
+ if (!enif_get_resource(env, argv[2], res_type_ec_key, (void **)&obj))
+ return enif_make_badarg(env);
+
+ if (enif_get_tuple(env, argv[1], &tpl_arity, &tpl_terms)) {
+ if (tpl_arity != 2 || tpl_terms[0] != atom_digest
+ || !enif_inspect_binary(env, tpl_terms[1], &data_bin)
+ || data_bin.size != digp->len) {
+
+ return enif_make_badarg(env);
+ }
+ digest = data_bin.data;
+ }
+ else {
+ if (!inspect_mpint(env,argv[1],&data_bin)) {
+ return enif_make_badarg(env);
+ }
+ digest = hmacbuf;
+ digp->funcp(data_bin.data+4, data_bin.size-4, digest);
+ }
+
+ enif_alloc_binary(ECDSA_size(obj->key), &ret_bin);
+
+ i = ECDSA_sign(digp->NID_type, digest, digp->len,
+ ret_bin.data, &dsa_s_len, obj->key);
+ if (i) {
+ if (dsa_s_len != ret_bin.size) {
+ enif_realloc_binary(&ret_bin, dsa_s_len);
+ }
+ return enif_make_binary(env, &ret_bin);
+ }
+ else {
+ enif_release_binary(&ret_bin);
+ return atom_error;
+ }
+#else
+ return atom_notsup;
+#endif
+}
+
+static ERL_NIF_TERM ecdsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Type, Data|{digest,Digest}, Signature, Key) */
+#if defined(HAVE_EC)
+ ErlNifBinary data_bin, sign_bin;
+ unsigned char hmacbuf[SHA512_LEN];
+ int i;
+ struct nif_ec_key *obj;
+ const ERL_NIF_TERM type = argv[0];
+ const ERL_NIF_TERM* tpl_terms;
+ int tpl_arity;
+ struct digest_type_t* digp = NULL;
+ unsigned char* digest = NULL;
+
+ digp = get_digest_type(type);
+ if (!digp) {
+ return enif_make_badarg(env);
+ }
+ if (!digp->len) {
+ return atom_notsup;
+ }
+
+ if (!inspect_mpint(env, argv[2], &sign_bin)
+ || !enif_get_resource(env, argv[3], res_type_ec_key, (void **)&obj))
+ return enif_make_badarg(env);
+
+ if (enif_get_tuple(env, argv[1], &tpl_arity, &tpl_terms)) {
+ if (tpl_arity != 2 || tpl_terms[0] != atom_digest
+ || !enif_inspect_binary(env, tpl_terms[1], &data_bin)
+ || data_bin.size != digp->len) {
+
+ return enif_make_badarg(env);
+ }
+ digest = data_bin.data;
+ }
+ else if (inspect_mpint(env, argv[1], &data_bin)) {
+ digest = hmacbuf;
+ digp->funcp(data_bin.data+4, data_bin.size-4, digest);
+ }
+ else {
+ return enif_make_badarg(env);
+ }
+
+ i = ECDSA_verify(digp->NID_type, digest, digp->len,
+ sign_bin.data+4, sign_bin.size-4, obj->key);
+
+ return (i==1 ? atom_true : atom_false);
+#else
+ return atom_notsup;
+#endif
+}
+
+/*
+ (_OthersPublicKey, _MyPrivateKey)
+ (_OthersPublicKey, _MyEC_Point)
+*/
+static ERL_NIF_TERM ecdh_compute_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+#if defined(HAVE_EC)
+ ERL_NIF_TERM ret;
+ unsigned char *p;
+ struct nif_ec_key *other_key;
+ int field_size = 0;
+ int i;
+
+ EC_GROUP *group;
+ const BIGNUM *priv_key;
+ EC_POINT *my_ecpoint;
+ EC_KEY *other_ecdh = NULL;
+
+ if (!enif_get_resource(env, argv[0], res_type_ec_key, (void **)&other_key))
+ return enif_make_badarg(env);
+
+ group = EC_GROUP_dup(EC_KEY_get0_group(other_key->key));
+ priv_key = EC_KEY_get0_private_key(other_key->key);
+
+ if (!term2point(env, argv[1], group, &my_ecpoint)) {
+ struct nif_ec_key *my_key;
+
+ if (!enif_get_resource(env, argv[1], res_type_ec_key, (void **)&my_key))
+ goto out_err;
+
+ if ((my_ecpoint = EC_POINT_new(group)) == NULL)
+ goto out_err;
+ EC_POINT_copy(my_ecpoint, EC_KEY_get0_public_key(my_key->key));
+ }
+
+ if ((other_ecdh = EC_KEY_new()) == NULL
+ || !EC_KEY_set_group(other_ecdh, group)
+ || !EC_KEY_set_private_key(other_ecdh, priv_key))
+ goto out_err;
+
+ field_size = EC_GROUP_get_degree(group);
+ if (field_size <= 0)
+ goto out_err;
+
+ p = enif_make_new_binary(env, (field_size+7)/8, &ret);
+ i = ECDH_compute_key(p, (field_size+7)/8, my_ecpoint, other_ecdh, NULL);
+
+ if (i < 0)
+ goto out_err;
+out:
+ if (group) EC_GROUP_free(group);
+ if (my_ecpoint) EC_POINT_free(my_ecpoint);
+ if (other_ecdh) EC_KEY_free(other_ecdh);
+
+ return ret;
+
+out_err:
+ ret = enif_make_badarg(env);
+ goto out;
+#else
+ return atom_notsup;
+#endif
+}
/* HMAC */
View
244 lib/crypto/doc/src/crypto.xml 100755 → 100644
@@ -63,6 +63,20 @@
<item>
<p>dss: Digital Signature Standard (FIPS 186-2)</p>
</item>
+ <item>
+ <p>ecdsa: "Public Key Cryptography for the Financial
+ Services Industry: The Elliptic Curve Digital
+ Signature Standard (ECDSA)", November, 2005.</p>
+ </item>
+ <item>
+ <p>ec: Standards for Efficient Cryptography Group (SECG), "SEC 1:
+ Elliptic Curve Cryptography", Version 1.0, September 2000.</p>
+ </item>
+ <item>
+ <p>ecdsa: American National Standards Institute (ANSI),
+ ANS X9.62-2005: The Elliptic Curve Digital Signature
+ Algorithm (ECDSA), 2005.</p>
+ </item>
</list>
<p>The above publications can be found at <url href="http://csrc.nist.gov/publications">NIST publications</url>, at <url href="http://www.ietf.org">IETF</url>.
</p>
@@ -99,6 +113,14 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
</desc>
</func>
<func>
+ <name>algorithms() -> [atom()]</name>
+ <fsummary>Provide a list of available crypto algorithms.</fsummary>
+ <desc>
+ <p>Provides the available crypto algorithms in terms of a list
+ of atoms.</p>
+ </desc>
+ </func>
+ <func>
<name>info_lib() -> [{Name,VerNum,VerStr}]</name>
<fsummary>Provides information about the libraries used by crypto.</fsummary>
<type>
@@ -1256,6 +1278,205 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
</desc>
</func>
+ <func>
+ <name>srp_mod_exp(Generator, Exponent, Prime) -> Result</name>
+ <fsummary>Computes the SRP-SHA function: g^x % N</fsummary>
+ <type>
+ <v>Generator, Exponent, Prime = binary()</v>
+ <v>Result = binary() | error</v>
+ </type>
+ <desc>
+ <p>Computes the SRP-SHA function g^x % N used for the verifier and client public key (RFC-2945, Sect. 3)
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name>srp_value_B(Multiplier, Verifier, Generator, Exponent, Prime) -> ValueB</name>
+ <fsummary>Computes the SRP function: B = k*v + g^b % N</fsummary>
+ <type>
+ <v>Verifier (v), Generator (g), Exponent (b), Prime (N), ValueB (B) = binary()</v>
+ <v>Multiplier (k) = integer() | binary()</v>
+ </type>
+ <desc>
+ <p>Computes the SRP value B according to RFC-2945, Sect. 3 and RFC-5054, Sect. 2.5.3</p>
+ <p>B = k*v + g^b % N</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>srp_client_secret(A, U, B, Multiplier, Generator, Exponent, Prime) -> Secret</name>
+ <fsummary>Computes the SRP client secret</fsummary>
+ <type>
+ <v>A (a), U (u), B, Multiplier (k), Generator (g), Exponent (x), Prime (N), Secret = binary()</v>
+ <v>Multiplier (k) = integer() | binary()</v>
+ </type>
+ <desc>
+ <p>Computes the SRP client secret according to RFC-2945, Sect. 3 and RFC-5054, Sect. 2.6</p>
+ <p>Secret = (B - (k * g^x)) ^ (a + (u * x)) % N</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>srp_server_secret(Verifier, B, U, A, Prime) -> Secret</name>
+ <fsummary>Computes the SRP host secret</fsummary>
+ <type>
+ <v>Verifier (v), B (b), U (u), A, Prime (N), Secret = binary()</v>
+ </type>
+ <desc>
+ <p>Computes the SRP host secret according to RFC-2945, Sect. 3 and RFC-5054, Sect. 2.6</p>
+ <p>Secret = (A * v^u) ^ b % N</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>srp3_value_u(B) -> Result</name>
+ <fsummary>Computes the SRP3-SHA value u</fsummary>
+ <type>
+ <v>B = binary()</v>
+ <v>Result = integer()</v>
+ </type>
+ <desc>
+ <p>Computes the SRP-3 value u according to RFC-2945, Sect. 3
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name>srp6_value_u(A, B, Prime) -> Result</name>
+ <fsummary>Computes the SRP6a value u as u = SHA1(PAD(A) | PAD(B))</fsummary>
+ <type>
+ <v>A, B, Prime = binary()</v>
+ <v>Result = integer()</v>
+ </type>
+ <desc>
+ <p>Computes the SRP-6 value u according to RFC-5054, Sect. 2.6
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name>srp6a_multiplier(Generator, Prime) -> Result</name>
+ <fsummary>Computes the SRP-SHA function: k = SHA1(N | PAD(g))</fsummary>
+ <type>
+ <v>Generator, Prime = binary()</v>
+ <v>Result = integer()</v>
+ </type>
+ <desc>
+ <p>Computes the SRP-6a function SHA1(N | PAD(g)) as the multiplier
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name>ec_key_new(NamedCurve) -> ECKey</name>
+ <type>
+ <v>NamedCurve = atom()</v>
+ <v>ECKey = EC key resource()</v>
+ </type>
+ <desc>
+ <p>Generate an new EC key from the named curve. The private key
+ will be initialized with random data.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name>ec_key_generate(ECKey) -> ok | error</name>
+ <type>
+ <v>ECKey = EC key resource()</v>
+ </type>
+ <desc>
+ <p>Fills in the public key if only the private key is known or generates
+ a new private/public key pair if only the curve parameters are known.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name>ec_key_to_term(ECKey) -> ECKeyTerm.</name>
+ <type>
+ <v>ECKey = EC key resource()</v>
+ <v>ECKeyTerm = EC key as Erlang term</v>
+ </type>
+ <desc>
+ <p>Convert a EC key from a NIF resource into an Erlang term.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name>term_to_ec_key(ECKeyTerm) -> ECKey</name>
+ <type>
+ <v>ECKeyTerm = EC key as Erlang term</v>
+ <v>ECKey = EC key resource()</v>
+ </type>
+ <desc>
+ <p>Convert a EC key an Erlang term into a NIF resource.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name>ecdsa_sign(DataOrDigest, ECKey) -> Signature</name>
+ <name>ecdsa_sign(DigestType, DataOrDigest, ECKey) -> Signature</name>
+ <fsummary>Sign the data using ecdsa with the given key.</fsummary>
+ <type>
+ <v>DataOrDigest = Data | {digest,Digest}</v>
+ <v>Data = Mpint</v>
+ <v>Digest = binary()</v>
+ <v>ECKey = EC key resource()</v>
+ <v>DigestType = md5 | sha | sha256 | sha384 | sha512</v>
+ <d>The default <c>DigestType</c> is sha.</d>
+ <v>Mpint = binary()</v>
+ <v>Signature = binary()</v>
+ </type>
+ <desc>
+ <p>Creates a ESDSA signature with the private key <c>Key</c>
+ of a digest. The digest is either calculated as a
+ <c>DigestType</c> digest of <c>Data</c> or a precalculated
+ binary <c>Digest</c>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>ecdsa_verify(DataOrDigest, Signature, ECKey) -> Verified</name>
+ <name>ecdsa_verify(DigestType, DataOrDigest, Signature, ECKey) -> Verified </name>
+ <fsummary>Verify the digest and signature using ecdsa with given public key.</fsummary>
+ <type>
+ <v>Verified = boolean()</v>
+ <v>DataOrDigest = Data | {digest|Digest}</v>
+ <v>Data, Signature = Mpint</v>
+ <v>Digest = binary()</v>
+ <v>ECKey = EC key resource()</v>
+ <v>DigestType = md5 | sha | sha256 | sha384 | sha512</v>
+ <d>The default <c>DigestType</c> is sha.</d>
+ <v>Mpint = binary()</v>
+ </type>
+ <desc>
+ <p>Verifies that a digest matches the ECDSA signature using the
+ signer's public key <c>Key</c>.
+ The digest is either calculated as a <c>DigestType</c>
+ digest of <c>Data</c> or a precalculated binary <c>Digest</c>.</p>
+ <p>May throw exception <c>notsup</c> in case the chosen <c>DigestType</c>
+ is not supported by the underlying OpenSSL implementation.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>ecdh_compute_key(OthersPublicKey, MyPrivateKey) -> SharedSecret</name>
+ <name>ecdh_compute_key(OthersPublicKey, MyECPoint) -> SharedSecret</name>
+ <fsummary>Computes the shared secret</fsummary>
+ <type>
+ <v>OthersPublicKey, MyPrivateKey = ECKey()</v>
+ <v>MyPrivatePoint = binary()</v>
+ <v>SharedSecret = binary()</v>
+ </type>
+ <desc>
+ <p>Computes the shared secret from the private key and the other party's public key.
+ </p>
+ </desc>
+ </func>
<func>
<name>exor(Data1, Data2) -> Result</name>
@@ -1271,6 +1492,29 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
</funcs>
<section>
+ <title>Elliptic Curve Key</title>
+ <p>Elliptic Curve keys consist of the curve paramters and a the
+ private and public keys (points on the curve). Translating the
+ raw curve paraters into something usable for the underlying
+ OpenSSL implementation is a complicated process. The main cryptografic
+ functions therefore expect a NIF resource as input that contains the
+ key in an internal format. Two functions <b>ec_key_to_term/1</b>
+ and <b>term_to_ec_key</b> are provided to convert between Erlang
+ terms and the resource format</p>
+ <p><em>Key in term form</em></p>
+ <pre>
+ec_named_curve() = atom()
+ec_point() = binary()
+ec_basis() = {tpbasis, K :: non_neg_integer()} | {ppbasis, K1 :: non_neg_integer(), K2 :: non_neg_integer(), K3 :: non_neg_integer()} | onbasis
+ec_field() = {prime_field, Prime :: Mpint()} | {characteristic_two_field, M :: integer(), Basis :: ec_basis()}
+ec_prime() = {A :: Mpint(), B :: Mpint(), Seed :: binary()}
+ec_curve_spec() = {Field :: ec_field(), Prime :: ec_prime(), Point :: ec_point(), Order :: Mpint(), CoFactor :: none | Mpint()}
+ec_curve() = ec_named_curve() | ec_curve_spec()
+ec_key() = {Curve :: ec_curve(), PrivKey :: Mpint() | undefined, PubKey :: ec_point() | undefined}
+ </pre>
+ </section>
+
+ <section>
<title>DES in CBC mode</title>
<p>The Data Encryption Standard (DES) defines an algorithm for
encrypting and decrypting an 8 byte quantity using an 8 byte key
View
192 lib/crypto/src/crypto.erl
@@ -21,7 +21,7 @@
-module(crypto).
--export([start/0, stop/0, info/0, info_lib/0, version/0]).
+-export([start/0, stop/0, info/0, info_lib/0, algorithms/0, version/0]).
-export([hash/2, hash_init/1, hash_update/2, hash_final/1]).
-export([md4/1, md4_init/0, md4_update/2, md4_final/1]).
-export([md5/1, md5_init/0, md5_update/2, md5_final/1]).
@@ -58,12 +58,18 @@
-export([rand_bytes/1, rand_bytes/3, rand_uniform/2]).
-export([strong_rand_bytes/1, strong_rand_mpint/3]).
-export([mod_exp/3, mpint/1, erlint/1]).
+-export([srp_mod_exp/3, srp_value_B/5]).
+-export([srp3_value_u/1, srp6_value_u/3, srp6a_multiplier/2]).
+-export([srp_client_secret/7, srp_server_secret/5]).
+
%% -export([idea_cbc_encrypt/3, idea_cbc_decrypt/3]).
-export([aes_cbc_128_encrypt/3, aes_cbc_128_decrypt/3]).
-export([aes_cbc_256_encrypt/3, aes_cbc_256_decrypt/3]).
-export([aes_cbc_ivec/1]).
-export([aes_ctr_encrypt/3, aes_ctr_decrypt/3]).
-export([aes_ctr_stream_init/2, aes_ctr_stream_encrypt/2, aes_ctr_stream_decrypt/2]).
+-export([ec_key_new/1, ec_key_to_term/1, term_to_ec_key/1, ec_key_generate/1]).
+-export([ecdsa_sign/2, ecdsa_sign/3, ecdsa_verify/3, ecdsa_verify/4, ecdh_compute_key/2]).
-export([dh_generate_parameters/2, dh_check/1]). %% Testing see below
@@ -109,12 +115,28 @@
hash, hash_init, hash_update, hash_final,
hmac, hmac_init, hmac_update, hmac_final, hmac_final_n, info,
rc2_cbc_encrypt, rc2_cbc_decrypt,
- info_lib]).
-
+ srp_mod_exp, srp_value_B,
+ srp3_value_u, srp6_value_u, srp6a_multiplier,
+ srp_client_secret, srp_server_secret,
+ ec_key_new, ec_key_to_term, term_to_ec_key, ec_key_generate,
+ ecdsa_sign, ecdsa_verify, ecdh_compute_key,
+ info_lib, algorithms]).
+
+-type mpint() :: binary().
-type rsa_digest_type() :: 'md5' | 'sha' | 'sha224' | 'sha256' | 'sha384' | 'sha512'.
-type dss_digest_type() :: 'none' | 'sha'.
+-type ecdsa_digest_type() :: 'md5' | 'sha' | 'sha256' | 'sha384' | 'sha512'.
-type data_or_digest() :: binary() | {digest, binary()}.
-type crypto_integer() :: binary() | integer().
+-type ec_key_res() :: any(). %% nif resource
+-type ec_named_curve() :: atom().
+-type ec_point() :: binary().
+-type ec_basis() :: {tpbasis, K :: non_neg_integer()} | {ppbasis, K1 :: non_neg_integer(), K2 :: non_neg_integer(), K3 :: non_neg_integer()} | onbasis.
+-type ec_field() :: {prime_field, Prime :: mpint()} | {characteristic_two_field, M :: integer(), Basis :: ec_basis()}.
+-type ec_prime() :: {A :: mpint(), B :: mpint(), Seed :: binary()}.
+-type ec_curve_spec() :: {Field :: ec_field(), Prime :: ec_prime(), Point :: ec_point(), Order :: mpint(), CoFactor :: none | mpint()}.
+-type ec_curve() :: ec_named_curve() | ec_curve_spec().
+-type ec_key() :: {Curve :: ec_curve(), PrivKey :: mpint() | undefined, PubKey :: ec_point() | undefined}.
-define(nif_stub,nif_stub_error(?LINE)).
@@ -184,6 +206,8 @@ info() ->
info_lib() -> ?nif_stub.
+algorithms() -> ?nif_stub.
+
%% Crypto app version history:
%% (no version): Driver implementation
%% 2.0 : NIF implementation, requires OTP R14
@@ -1065,9 +1089,160 @@ dh_compute_key(OthersPublicKey, MyPrivateKey, DHParameters) ->
dh_compute_key_nif(_OthersPublicKey, _MyPrivateKey, _DHParameters) -> ?nif_stub.
%%
+%% EC
+%%
+-spec ec_key_new(ec_named_curve()) -> ec_key_res().
+ec_key_new(_Curve) -> ?nif_stub.
+
+-spec ec_key_generate(ec_key_res()) -> ok | error.
+ec_key_generate(_Key) -> ?nif_stub.
+
+nif_prime_to_term({prime_field, Prime}) ->
+ {prime_field, erlint(Prime)};
+nif_prime_to_term(PrimeField) ->
+ PrimeField.
+nif_curve_to_term({A, B, Seed}) ->
+ {erlint(A), erlint(B), Seed}.
+nif_curve_parameters_to_term({PrimeField, Curve, BasePoint, Order, CoFactor}) ->
+ {nif_prime_to_term(PrimeField), nif_curve_to_term(Curve), BasePoint, erlint(Order), erlint(CoFactor)};
+nif_curve_parameters_to_term(Curve) when is_atom(Curve) ->
+ %% named curve
+ Curve.
+
+-spec ec_key_to_term(ec_key_res()) -> ec_key().
+ec_key_to_term(Key) ->
+ case ec_key_to_term_nif(Key) of
+ {Curve, PrivKey, PubKey} ->
+ {nif_curve_parameters_to_term(Curve), erlint(PrivKey), PubKey};
+ _ ->
+ erlang:error(conversion_failed)
+ end.
+
+ec_key_to_term_nif(_Key) -> ?nif_stub.
+
+term_to_nif_prime({prime_field, Prime}) ->
+ {prime_field, mpint(Prime)};
+term_to_nif_prime(PrimeField) ->
+ PrimeField.
+term_to_nif_curve({A, B, Seed}) ->
+ {mpint(A), mpint(B), Seed}.
+term_to_nif_curve_parameters({PrimeField, Curve, BasePoint, Order, CoFactor}) ->
+ {term_to_nif_prime(PrimeField), term_to_nif_curve(Curve), BasePoint, mpint(Order), mpint(CoFactor)};
+term_to_nif_curve_parameters(Curve) when is_atom(Curve) ->
+ %% named curve
+ Curve.
+
+-spec term_to_ec_key(ec_key()) -> ec_key_res().
+term_to_ec_key({Curve, undefined, PubKey}) ->
+ term_to_ec_key_nif(term_to_nif_curve_parameters(Curve), undefined, PubKey);
+term_to_ec_key({Curve, PrivKey, PubKey}) ->
+ term_to_ec_key_nif(term_to_nif_curve_parameters(Curve), mpint(PrivKey), PubKey).
+
+term_to_ec_key_nif(_Curve, _PrivKey, _PubKey) -> ?nif_stub.
+
+%%
+%% ECDSA - sign
+%%
+-spec ecdsa_sign(data_or_digest(), ec_key_res()) -> binary().
+-spec ecdsa_sign(ecdsa_digest_type(), data_or_digest(), ec_key_res()) -> binary().
+
+ecdsa_sign(DataOrDigest,Key) ->
+ ecdsa_sign(sha, DataOrDigest, Key).
+ecdsa_sign(Type, DataOrDigest, Key) ->
+ case ecdsa_sign_nif(Type,DataOrDigest,Key) of
+ error -> erlang:error(badkey, [Type,DataOrDigest,Key]);
+ Sign -> Sign
+ end.
+
+ecdsa_sign_nif(_Type, _DataOrDigest, _Key) -> ?nif_stub.
+
+%%
+%% ECDSA - verify
+%%
+-spec ecdsa_verify(data_or_digest(), binary(), ec_key_res()) -> boolean().
+-spec ecdsa_verify(ecdsa_digest_type(), data_or_digest(), binary(), ec_key_res()) ->
+ boolean().
+
+ecdsa_verify(Data,Signature,Key) ->
+ ecdsa_verify_nif(sha, Data,Signature,Key).
+ecdsa_verify(Type, DataOrDigest, Signature, Key) ->
+ case ecdsa_verify_nif(Type, DataOrDigest, Signature, Key) of
+ notsup -> erlang:error(notsup);
+ Bool -> Bool
+ end.
+
+ecdsa_verify_nif(_Type, _DataOrDigest, _Signature, _Key) -> ?nif_stub.
+
+-spec ecdh_compute_key(ec_key_res(), ec_key_res() | ec_point()) -> binary().
+ecdh_compute_key(_Others, _My) -> ?nif_stub.
+
+%%
+%% SRP functions
+%%
+-spec srp_mod_exp(binary(), binary(), binary()) -> binary().
+srp_mod_exp(Generator, Exponent, Prime) ->
+ Verifier = mod_exp_nif(bin2bn(Generator), bin2bn(Exponent), bin2bn(Prime)),
+ case erlint(Verifier) of
+ 0 -> error;
+ _ -> bn2bin(Verifier)
+ end.
+
+-spec srp_value_B(binary(), integer(), binary(), binary(), binary()) -> binary().
+srp_value_B(Multiplier, Verifier, Generator, Exponent, Prime) ->
+ srp_value_B_nif(srp_multiplier(Multiplier), Verifier, Generator, Exponent, Prime).
+
+srp_value_B_nif(_Multiplier, _Verifier, _Generator, _Exponent, _Prime) -> ?nif_stub.
+
+-spec srp_client_secret(binary(), binary(), binary(), integer()|binary(), binary(), binary(), binary()) -> binary().
+srp_client_secret(A, U, B, Multiplier, Generator, Exponent, Prime) ->
+ srp_client_secret_nif(A, U, B, srp_multiplier(Multiplier), Generator, Exponent, Prime).
+
+srp_client_secret_nif(_A, _U, _B, _Multiplier, _Generator, _Exponent, _Prime) -> ?nif_stub.
+
+-spec srp_server_secret(binary(), binary(), binary(), binary(), binary()) -> binary().
+srp_server_secret(_Verifier, _B, _U, _A, _Prime) -> ?nif_stub.
+
+-spec srp6a_multiplier(binary(), binary()) -> binary().
+srp6a_multiplier(Generator, Prime) ->
+ %% k = SHA1(N | PAD(g))
+ C0 = sha_init(),
+ C1 = sha_update(C0, Prime),
+ C2 = sha_update(C1, srp_pad_to(erlang:byte_size(Prime), Generator)),
+ sha_final(C2).
+
+-spec srp3_value_u(binary()) -> binary().
+srp3_value_u(B) ->
+ %% The parameter u is a 32-bit unsigned integer which takes its value
+ %% from the first 32 bits of the SHA1 hash of B, MSB first.
+ <<U:32/bits, _/binary>> = sha(B),
+ U.
+
+-spec srp6_value_u(binary(), binary(), binary()) -> binary().
+srp6_value_u(A, B, Prime) ->
+ %% SHA1(PAD(A) | PAD(B))
+ PadLength = erlang:byte_size(Prime),
+ C0 = sha_init(),
+ C1 = sha_update(C0, srp_pad_to(PadLength, A)),
+ C2 = sha_update(C1, srp_pad_to(PadLength, B)),
+ sha_final(C2).
+
+%%
%% LOCAL FUNCTIONS
%%
+srp_pad_length(Width, Length) ->
+ (Width - Length rem Width) rem Width.
+
+srp_pad_to(Width, Binary) ->
+ case srp_pad_length(Width, size(Binary)) of
+ 0 -> Binary;
+ N -> << 0:(N*8), Binary/binary>>
+ end.
+
+srp_multiplier(Multiplier) when is_binary(Multiplier) ->
+ bin2bn(Multiplier);
+srp_multiplier(Multiplier) when is_integer(Multiplier) ->
+ mpint(Multiplier).
%% large integer in a binary with 32bit length
%% MP representaion (SSH2)
@@ -1110,4 +1285,13 @@ mpint_pos(X,I,Ds) ->
erlint(<<MPIntSize:32/integer,MPIntValue/binary>>) ->
Bits= MPIntSize * 8,
<<Integer:Bits/integer>> = MPIntValue,
- Integer.
+ Integer;
+erlint(undefined) ->
+ undefined.
+
+bin2bn(Bin) ->
+ Len = erlang:byte_size(Bin),
+ <<?UINT32(Len), Bin/binary>>.
+
+bn2bin(<<_:32, Bin/binary>>) ->
+ Bin.
View
792 lib/crypto/test/crypto_SUITE.erl
@@ -39,7 +39,10 @@
hmac_update_md5_io/1,
hmac_update_md5_n/1,
hmac_rfc2202/1,
- hmac_rfc4231/1,
+ hmac_rfc4231_sha224/1,
+ hmac_rfc4231_sha256/1,
+ hmac_rfc4231_sha384/1,
+ hmac_rfc4231_sha512/1,
ripemd160/1,
ripemd160_update/1,
sha256/1,
@@ -72,6 +75,8 @@
dsa_sign_hash_test/1,
rsa_encrypt_decrypt/1,
dh/1,
+ srp3/1, srp6/1, srp6a/1,
+ ec/1,
exor_test/1,
rc4_test/1,
rc4_stream_test/1,
@@ -93,14 +98,15 @@ groups() ->
sha256, sha256_update, sha512, sha512_update,
hmac_update_sha, hmac_update_sha_n, hmac_update_sha256, hmac_update_sha512,
hmac_update_md5_n, hmac_update_md5_io, hmac_update_md5,
- hmac_rfc2202, hmac_rfc4231,
+ hmac_rfc2202, hmac_rfc4231_sha224, hmac_rfc4231_sha256,
+ hmac_rfc4231_sha384, hmac_rfc4231_sha512,
des_cbc, aes_cfb, aes_cbc,
des_cfb, des_cfb_iter, des3_cbc, des3_cfb, rc2_cbc,
aes_cbc_iter, aes_ctr, aes_ctr_stream, des_cbc_iter, des_ecb,
rand_uniform_test, strong_rand_test,
rsa_verify_test, dsa_verify_test, rsa_sign_test,
rsa_sign_hash_test, dsa_sign_test, dsa_sign_hash_test,
- rsa_encrypt_decrypt, dh, exor_test,
+ rsa_encrypt_decrypt, dh, srp3, srp6, srp6a, ec, exor_test,
rc4_test, rc4_stream_test, mod_exp_test, blowfish_cfb64,
smp]}].
@@ -363,8 +369,7 @@ hmac_update_sha256(doc) ->
hmac_update_sha256(suite) ->
[];
hmac_update_sha256(Config) when is_list(Config) ->
- if_098(fun() -> hmac_update_sha256_do() end).
-
+ if_supported(sha256, fun() -> hmac_update_sha256_do() end).
hmac_update_sha256_do() ->
?line Key = hexstr2bin("00010203101112132021222330313233"
@@ -386,7 +391,7 @@ hmac_update_sha512(doc) ->
hmac_update_sha512(suite) ->
[];
hmac_update_sha512(Config) when is_list(Config) ->
- if_098(fun() -> hmac_update_sha512_do() end).
+ if_supported(sha512, fun() -> hmac_update_sha512_do() end).
hmac_update_sha512_do() ->
?line Key = hexstr2bin("00010203101112132021222330313233"
@@ -582,366 +587,192 @@ hmac_rfc2202_sha() ->
?line m(Case7Exp, Case7Mac_1),
?line m(Case7Exp, Case7Mac_2).
-hmac_rfc4231(doc) ->
- ["Generate an HMAC using crypto:shaXXX_mac, hmac, and hmac_init, hmac_update, and hmac_final. "
+hmac_rfc4231_sha224(doc) ->
+ ["Generate an HMAC using crypto:sha224_mac, hmac, and hmac_init, hmac_update, and hmac_final. "
"Testvectors are take from RFC4231." ];
-hmac_rfc4231(suite) ->
+hmac_rfc4231_sha224(suite) ->
[];
-hmac_rfc4231(Config) when is_list(Config) ->
- if_098(fun() -> hmac_rfc4231_do() end).
+hmac_rfc4231_sha224(Config) when is_list(Config) ->
+ if_supported(sha224, fun() -> hmac_rfc4231_sha224_do() end).
-hmac_rfc4231_do() ->
- %% Test Case 1
- Case1Key = binary:copy(<<16#0b>>, 20),
- Case1Data = <<"Hi There">>,
- Case1Exp224 = hexstr2bin("896fb1128abbdf196832107cd49df33f"
- "47b4b1169912ba4f53684b22"),
- Case1Exp256 = hexstr2bin("b0344c61d8db38535ca8afceaf0bf12b"
- "881dc200c9833da726e9376c2e32cff7"),
- Case1Exp384 = hexstr2bin("afd03944d84895626b0825f4ab46907f"
- "15f9dadbe4101ec682aa034c7cebc59c"
- "faea9ea9076ede7f4af152e8b2fa9cb6"),
- Case1Exp512 = hexstr2bin("87aa7cdea5ef619d4ff0b4241a1d6cb0"
- "2379f4e2ce4ec2787ad0b30545e17cde"
- "daa833b7d6b8a702038b274eaea3f4e4"
- "be9d914eeb61f1702e696c203a126854"),
-
- ?line Case1Ctx224 = crypto:hmac_init(sha224, Case1Key),
- ?line Case1Ctx224_2 = crypto:hmac_update(Case1Ctx224, Case1Data),
- ?line Case1Mac224_1 = crypto:hmac_final(Case1Ctx224_2),
- ?line Case1Mac224_2 = crypto:sha224_mac(Case1Key, Case1Data),
- ?line Case1Mac224_3 = crypto:hmac(sha224, Case1Key, Case1Data),
- ?line m(Case1Exp224, Case1Mac224_1),
- ?line m(Case1Exp224, Case1Mac224_2),
- ?line m(Case1Exp224, Case1Mac224_3),
-
- ?line Case1Ctx256 = crypto:hmac_init(sha256, Case1Key),
- ?line Case1Ctx256_2 = crypto:hmac_update(Case1Ctx256, Case1Data),
- ?line Case1Mac256_1 = crypto:hmac_final(Case1Ctx256_2),
- ?line Case1Mac256_2 = crypto:sha256_mac(Case1Key, Case1Data),
- ?line Case1Mac256_3 = crypto:hmac(sha256, Case1Key, Case1Data),
- ?line m(Case1Exp256, Case1Mac256_1),
- ?line m(Case1Exp256, Case1Mac256_2),
- ?line m(Case1Exp256, Case1Mac256_3),
-
- ?line Case1Ctx384 = crypto:hmac_init(sha384, Case1Key),
- ?line Case1Ctx384_2 = crypto:hmac_update(Case1Ctx384, Case1Data),
- ?line Case1Mac384_1 = crypto:hmac_final(Case1Ctx384_2),
- ?line Case1Mac384_2 = crypto:sha384_mac(Case1Key, Case1Data),
- ?line Case1Mac384_3 = crypto:hmac(sha384, Case1Key, Case1Data),
- ?line m(Case1Exp384, Case1Mac384_1),
- ?line m(Case1Exp384, Case1Mac384_2),
- ?line m(Case1Exp384, Case1Mac384_3),
-
- ?line Case1Ctx512 = crypto:hmac_init(sha512, Case1Key),
- ?line Case1Ctx512_2 = crypto:hmac_update(Case1Ctx512, Case1Data),
- ?line Case1Mac512_1 = crypto:hmac_final(Case1Ctx512_2),
- ?line Case1Mac512_2 = crypto:sha512_mac(Case1Key, Case1Data),
- ?line Case1Mac512_3 = crypto:hmac(sha512, Case1Key, Case1Data),
- ?line m(Case1Exp512, Case1Mac512_1),
- ?line m(Case1Exp512, Case1Mac512_2),
- ?line m(Case1Exp512, Case1Mac512_3),
-
- %% Test Case 2
- Case2Key = <<"Jefe">>,
- Case2Data = <<"what do ya want for nothing?">>,
- Case2Exp224 = hexstr2bin("a30e01098bc6dbbf45690f3a7e9e6d0f"
- "8bbea2a39e6148008fd05e44"),
- Case2Exp256 = hexstr2bin("5bdcc146bf60754e6a042426089575c7"
- "5a003f089d2739839dec58b964ec3843"),
- Case2Exp384 = hexstr2bin("af45d2e376484031617f78d2b58a6b1b"
- "9c7ef464f5a01b47e42ec3736322445e"
- "8e2240ca5e69e2c78b3239ecfab21649"),
- Case2Exp512 = hexstr2bin("164b7a7bfcf819e2e395fbe73b56e0a3"
- "87bd64222e831fd610270cd7ea250554"
- "9758bf75c05a994a6d034f65f8f0e6fd"
- "caeab1a34d4a6b4b636e070a38bce737"),
-
- ?line Case2Ctx224 = crypto:hmac_init(sha224, Case2Key),
- ?line Case2Ctx224_2 = crypto:hmac_update(Case2Ctx224, Case2Data),