From d34e3bfef14900bb328a24c9b6afc2fcf1b34810 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20F=C3=A6r=C3=B8y?= Date: Thu, 2 Apr 2015 18:15:48 +0200 Subject: [PATCH 1/3] Remove dot after @end. --- src/enacl_ext.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/enacl_ext.erl b/src/enacl_ext.erl index cc3a594..4f49397 100644 --- a/src/enacl_ext.erl +++ b/src/enacl_ext.erl @@ -37,7 +37,7 @@ scramble_block_16(Block, Key) -> %% %% Generates and returns a new key pair for the Curve 25519 encryption scheme. The return value is a %% map in order to avoid using the public key as a secret key and vice versa. -%% @end. +%% @end -spec curve25519_keypair() -> #{ atom() => binary() }. curve25519_keypair() -> <> = enacl:randombytes(32), From b544a37a72bd4c5546d7e407878f45cfa6126668 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20F=C3=A6r=C3=B8y?= Date: Thu, 2 Apr 2015 18:43:24 +0200 Subject: [PATCH 2/3] Fix warning: missing declaration for memcpy(). --- c_src/enacl_nif.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/c_src/enacl_nif.c b/c_src/enacl_nif.c index 6273eda..7f59087 100644 --- a/c_src/enacl_nif.c +++ b/c_src/enacl_nif.c @@ -1,5 +1,7 @@ #include "erl_nif.h" +#include + #include #ifndef ERL_NIF_DIRTY_SCHEDULER_SUPPORT From de0ce86473dba2a0373d2eed2157d96f79315f1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20F=C3=A6r=C3=B8y?= Date: Thu, 2 Apr 2015 18:17:42 +0200 Subject: [PATCH 3/3] Add Ed 25519 Utility API. --- c_src/enacl_nif.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++ src/enacl.erl | 43 +++++++++++++++++++++++++ src/enacl_nif.erl | 15 +++++++++ 3 files changed, 138 insertions(+) diff --git a/c_src/enacl_nif.c b/c_src/enacl_nif.c index 7f59087..d558aa5 100644 --- a/c_src/enacl_nif.c +++ b/c_src/enacl_nif.c @@ -120,6 +120,80 @@ ERL_NIF_TERM enif_crypto_curve25519_scalarmult(ErlNifEnv *env, int argc, ERL_NIF return result; } +/* Ed 25519 */ +static +ERL_NIF_TERM enif_crypto_sign_ed25519_keypair(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) { + ErlNifBinary pk, sk; + + if (argc != 0) { + return enif_make_badarg(env); + } + + if (!enif_alloc_binary(crypto_sign_ed25519_PUBLICKEYBYTES, &pk)) { + return nacl_error_tuple(env, "alloc_failed"); + } + + if (!enif_alloc_binary(crypto_sign_ed25519_SECRETKEYBYTES, &sk)) { + return nacl_error_tuple(env, "alloc_failed"); + } + + crypto_sign_ed25519_keypair(pk.data, sk.data); + + return enif_make_tuple2(env, enif_make_binary(env, &pk), enif_make_binary(env, &sk)); +} + +static +ERL_NIF_TERM enif_crypto_sign_ed25519_public_to_curve25519(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) { + ErlNifBinary curve25519_pk, ed25519_pk; + + if ((argc != 1) + || (!enif_inspect_binary(env, argv[0], &ed25519_pk)) + || (ed25519_pk.size != crypto_sign_ed25519_PUBLICKEYBYTES)) { + return enif_make_badarg(env); + } + + if (!enif_alloc_binary(crypto_scalarmult_curve25519_BYTES, &curve25519_pk)) { + return nacl_error_tuple(env, "alloc_failed"); + } + + if (crypto_sign_ed25519_pk_to_curve25519(curve25519_pk.data, ed25519_pk.data) != 0) { + return nacl_error_tuple(env, "ed25519_public_to_curve25519_failed"); + } + + return enif_make_binary(env, &curve25519_pk); +} + +static +ERL_NIF_TERM enif_crypto_sign_ed25519_secret_to_curve25519(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) { + ErlNifBinary curve25519_sk, ed25519_sk; + + if ((argc != 1) + || (!enif_inspect_binary(env, argv[0], &ed25519_sk)) + || (ed25519_sk.size != crypto_sign_ed25519_SECRETKEYBYTES)) { + return enif_make_badarg(env); + } + + if (!enif_alloc_binary(crypto_scalarmult_curve25519_BYTES, &curve25519_sk)) { + return nacl_error_tuple(env, "alloc_failed"); + } + + if (crypto_sign_ed25519_sk_to_curve25519(curve25519_sk.data, ed25519_sk.data) != 0) { + return nacl_error_tuple(env, "ed25519_secret_to_curve25519_failed"); + } + + return enif_make_binary(env, &curve25519_sk); +} + +static +ERL_NIF_TERM enif_crypto_sign_ed25519_PUBLICKEYBYTES(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) { + return enif_make_int64(env, crypto_sign_ed25519_PUBLICKEYBYTES); +} + +static +ERL_NIF_TERM enif_crypto_sign_ed25519_SECRETKEYBYTES(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) { + return enif_make_int64(env, crypto_sign_ed25519_SECRETKEYBYTES); +} + /* Public-key cryptography */ static ERL_NIF_TERM enif_crypto_box_NONCEBYTES(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) { @@ -849,6 +923,12 @@ static ErlNifFunc nif_funcs[] = { {"crypto_curve25519_scalarmult", 2, enif_crypto_curve25519_scalarmult}, + {"crypto_sign_ed25519_keypair", 0, enif_crypto_sign_ed25519_keypair}, + {"crypto_sign_ed25519_public_to_curve25519", 1, enif_crypto_sign_ed25519_public_to_curve25519}, + {"crypto_sign_ed25519_secret_to_curve25519", 1, enif_crypto_sign_ed25519_secret_to_curve25519}, + {"crypto_sign_ed25519_PUBLICKEYBYTES", 0, enif_crypto_sign_ed25519_PUBLICKEYBYTES}, + {"crypto_sign_ed25519_SECRETKEYBYTES", 0, enif_crypto_sign_ed25519_SECRETKEYBYTES}, + {"randombytes_b", 1, enif_randombytes}, {"randombytes", 1, enif_randombytes, ERL_NIF_DIRTY_JOB_CPU_BOUND}, diff --git a/src/enacl.erl b/src/enacl.erl index f73eace..459d3c5 100644 --- a/src/enacl.erl +++ b/src/enacl.erl @@ -65,6 +65,15 @@ curve25519_scalarmult/2 ]). +%% Ed 25519. +-export([ + crypto_sign_ed25519_keypair/0, + crypto_sign_ed25519_public_to_curve25519/1, + crypto_sign_ed25519_secret_to_curve25519/1, + crypto_sign_ed25519_public_size/0, + crypto_sign_ed25519_secret_size/0 +]). + %% Low-level functions -export([ hash/1, @@ -604,6 +613,40 @@ onetime_auth_key_size() -> enacl_nif:crypto_onetimeauth_KEYBYTES(). curve25519_scalarmult(Secret, BasePoint) -> enacl_nif:crypto_curve25519_scalarmult(Secret, BasePoint). +%% Ed 25519 Crypto +%% --------------- +%% @doc crypto_sign_ed25519_keypair/0 creates a new Ed 25519 Public/Secret keypair. +%% +%% Generates and returns a new key pair for the Ed 25519 signature scheme. The return value is a +%% map in order to avoid using the public key as a secret key and vice versa. +%% @end +-spec crypto_sign_ed25519_keypair() -> #{ atom() => binary() }. +crypto_sign_ed25519_keypair() -> + {PK, SK} = enacl_nif:crypto_sign_ed25519_keypair(), + #{ public => PK, secret => SK }. + +%% @doc crypto_sign_ed25519_public_to_curve25519/1 converts a given Ed 25519 public +%% key to a Curve 25519 public key. +%% @end +-spec crypto_sign_ed25519_public_to_curve25519(PublicKey :: binary()) -> binary(). +crypto_sign_ed25519_public_to_curve25519(PublicKey) -> + enacl_nif:crypto_sign_ed25519_public_to_curve25519(PublicKey). + +%% @doc crypto_sign_ed25519_secret_to_curve25519/1 converts a given Ed 25519 secret +%% key to a Curve 25519 secret key. +%% @end +-spec crypto_sign_ed25519_secret_to_curve25519(SecretKey :: binary()) -> binary(). +crypto_sign_ed25519_secret_to_curve25519(SecretKey) -> + enacl_nif:crypto_sign_ed25519_secret_to_curve25519(SecretKey). + +-spec crypto_sign_ed25519_public_size() -> pos_integer(). +crypto_sign_ed25519_public_size() -> + enacl_nif:crypto_sign_ed25519_PUBLICKEYBYTES(). + +-spec crypto_sign_ed25519_secret_size() -> pos_integer(). +crypto_sign_ed25519_secret_size() -> + enacl_nif:crypto_sign_ed25519_SECRETKEYBYTES(). + %% Obtaining random bytes %% @doc randombytes/1 produces a stream of random bytes of the given size diff --git a/src/enacl_nif.erl b/src/enacl_nif.erl index e8c4e2e..7748856 100644 --- a/src/enacl_nif.erl +++ b/src/enacl_nif.erl @@ -76,6 +76,15 @@ crypto_curve25519_scalarmult/2 ]). +%% Ed 25519 +-export([ + crypto_sign_ed25519_keypair/0, + crypto_sign_ed25519_public_to_curve25519/1, + crypto_sign_ed25519_secret_to_curve25519/1, + crypto_sign_ed25519_PUBLICKEYBYTES/0, + crypto_sign_ed25519_SECRETKEYBYTES/0 +]). + %% Miscellaneous helper functions -export([ crypto_hash/1, @@ -168,6 +177,12 @@ crypto_onetimeauth_verify_b(_Authenticator, _Msg, _Key) -> erlang:nif_error(nif_ crypto_curve25519_scalarmult(_Secret, _BasePoint) -> erlang:nif_error(nif_not_loaded). +crypto_sign_ed25519_keypair() -> erlang:nif_error(nif_not_loaded). +crypto_sign_ed25519_public_to_curve25519(_PublicKey) -> erlang:nif_error(nif_not_loaded). +crypto_sign_ed25519_secret_to_curve25519(_SecretKey) -> erlang:nif_error(nif_not_loaded). +crypto_sign_ed25519_PUBLICKEYBYTES() -> erlang:nif_error(nif_not_loaded). +crypto_sign_ed25519_SECRETKEYBYTES() -> erlang:nif_error(nif_not_loaded). + crypto_hash(Input) when is_binary(Input) -> erlang:nif_error(nif_not_loaded). crypto_hash_b(Input) when is_binary(Input) -> erlang:nif_error(nif_not_loaded). crypto_verify_16(_X, _Y) -> erlang:nif_error(nif_not_loaded).