aboutsummaryrefslogtreecommitdiffstats
path: root/lib/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'lib/crypto')
-rw-r--r--lib/crypto/c_src/crypto.c439
-rw-r--r--lib/crypto/src/crypto.erl29
-rw-r--r--lib/crypto/test/crypto_SUITE.erl3
3 files changed, 171 insertions, 300 deletions
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index 5781c1de78..99e5cb1c1f 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -229,7 +229,6 @@ static ERL_NIF_TERM bf_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
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[]);
@@ -267,6 +266,11 @@ static void hmac_sha512(unsigned char *key, int klen,
unsigned char *dbuf, int dlen,
unsigned char *hmacbuf);
#endif
+#ifdef HAVE_EC
+static EC_KEY* ec_key_new(ErlNifEnv* env, ERL_NIF_TERM curve_arg);
+static int term2point(ErlNifEnv* env, ERL_NIF_TERM term,
+ EC_GROUP *group, EC_POINT **pptr);
+#endif
static int library_refc = 0; /* number of users of this dynamic library */
@@ -355,7 +359,6 @@ static ErlNifFunc nif_funcs[] = {
{"bf_ecb_crypt", 3, bf_ecb_crypt},
{"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},
@@ -2850,249 +2853,10 @@ static int term2curve_id(ERL_NIF_TERM 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[])
+static EC_KEY* ec_key_new(ErlNifEnv* env, ERL_NIF_TERM curve_arg)
{
-#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, &ret);
- BN_bn2bin(bn, ptr);
-
- 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;
@@ -3104,28 +2868,17 @@ static ERL_NIF_TERM term_to_ec_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_T
EC_GROUP *group = NULL;
EC_POINT *point = NULL;
- if (!(argv[1] == atom_undefined || get_bn_from_bin(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;
- }
-
+ if (enif_is_atom(env, curve_arg)) {
+ nid = term2curve_id(curve_arg);
+ if (nid == 0)
+ return NULL;
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_bin(env, curve[3], &bn_order)
- && (curve[4] != atom_none && get_bn_from_bin(env, curve[4], &cofactor))) {
+ else if (enif_is_tuple(env, curve_arg)
+ && enif_get_tuple(env,curve_arg,&c_arity,&curve)
+ && c_arity == 5
+ && get_bn_from_bin(env, curve[3], &bn_order)
+ && (curve[4] != atom_none && get_bn_from_bin(env, curve[4], &cofactor))) {
//* {Field, Prime, Point, Order, CoFactor} = Curve */
int f_arity = -1;
@@ -3244,10 +2997,146 @@ static ERL_NIF_TERM term_to_ec_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_T
EC_KEY_set_group(key, group);
}
else {
- printf("#3\n");
+ printf("#3\n");
+ goto out_err;
+ }
+
+
+ goto out;
+
+out_err:
+ if (key) EC_KEY_free(key);
+ key = NULL;
+
+out:
+ /* some OpenSSL structures are mem-dup'ed into the key,
+ so we have to free our copies here */
+ 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 key;
+}
+
+
+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, &ret);
+ BN_bn2bin(bn, ptr);
+
+ 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;
+ const BIGNUM *priv_key = NULL;
+ ERL_NIF_TERM pub_key = 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 (public_key)
+ pub_key = point2term(env, group, public_key, EC_KEY_get_conv_form(obj->key));
+ }
+
+ return enif_make_tuple2(env, 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;
+ EC_GROUP *group = NULL;
+
+ if (!(argv[1] == atom_undefined || get_bn_from_bin(env, argv[1], &priv_key))
+ || !(argv[2] == atom_undefined || enif_is_binary(env, argv[2]))) {
+ printf("#1\n");
goto out_err;
}
+ key = ec_key_new(env, argv[0]);
+
if (!key) {
printf("#4\n");
goto out_err;
@@ -3300,11 +3189,6 @@ out:
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
@@ -3315,15 +3199,20 @@ out:
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;
+ EC_KEY *key = ec_key_new(env, argv[0]);
- 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;
+ if (key && EC_KEY_generate_key(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 atom_error;
+ return enif_make_badarg(env);
#else
return atom_notsup;
#endif
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 6f4092ea74..999a65042d 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -1226,39 +1226,20 @@ srp_compute_key(Verifier, Prime, ClientPublic, ServerPublic, ServerPrivate, Vers
%%
%% EC
%%
--spec ec_key_new(ec_named_curve()) -> ec_key_res().
-ec_key_new(_Curve) -> ?nif_stub.
-ecdh_generate_key(Curve) when is_atom(Curve) ->
- ECKey = ec_key_new(Curve),
- ec_key_generate(ECKey),
- ec_key_to_term(ECKey);
-ecdh_generate_key(Key) ->
- ECKey = term_to_ec_key(Key),
- ec_key_generate(ECKey),
- ec_key_to_term(ECKey).
+-spec ecdh_generate_key(ec_curve()) -> ec_key() | error.
+ecdh_generate_key(Curve) ->
+ ec_key_to_term(ec_key_generate(Curve)).
--spec ec_key_generate(ec_key_res()) -> ok | error.
ec_key_generate(_Key) -> ?nif_stub.
-nif_prime_to_term({prime_field, Prime}) ->
- {prime_field, bin_to_int(Prime)};
-nif_prime_to_term(PrimeField) ->
- PrimeField.
-nif_curve_to_term({A, B, Seed}) ->
- {bin_to_int(A), bin_to_int(B), Seed}.
-nif_curve_parameters_to_term({PrimeField, Curve, BasePoint, Order, CoFactor}) ->
- {nif_prime_to_term(PrimeField), nif_curve_to_term(Curve), BasePoint, bin_to_int(Order), bin_to_int(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), bin_to_int(PrivKey), PubKey};
+ {PrivKey, PubKey} ->
+ {bin_to_int(PrivKey), PubKey};
_ ->
erlang:error(conversion_failed)
end.
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index 55db09d9dd..384d15c68c 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -1887,7 +1887,8 @@ ec(Config) when is_list(Config) ->
ec_do() ->
%% test for a name curve
- D2 = crypto:ecdh_generate_key(sect113r2),
+ {D2_priv, D2_pub} = crypto:ecdh_generate_key(sect113r2),
+ D2 = {sect113r2, D2_priv, D2_pub},
%%TODO: find a published test case for a EC key