From 9a7f4c8d4e1eae051feb3becf34e5e02b55220f7 Mon Sep 17 00:00:00 2001 From: Jesper Louis Andersen Date: Tue, 18 Nov 2014 23:16:49 +0100 Subject: [PATCH] Initial checkin. --- Makefile | 13 ++++++++++ README.md | 10 ++++++++ c_src/enacl_nif.c | 54 ++++++++++++++++++++++++++++++++++++++++++ eqc_test/Makefile | 5 ++++ eqc_test/enacl_eqc.erl | 33 ++++++++++++++++++++++++++ rebar.config | 8 +++++++ src/Makefile | 2 ++ src/enacl.app.src | 9 +++++++ src/enacl.erl | 13 ++++++++++ src/enacl_app.erl | 10 ++++++++ src/enacl_nif.erl | 21 ++++++++++++++++ 11 files changed, 178 insertions(+) create mode 100644 Makefile create mode 100644 README.md create mode 100644 c_src/enacl_nif.c create mode 100644 eqc_test/Makefile create mode 100644 eqc_test/enacl_eqc.erl create mode 100644 rebar.config create mode 100644 src/Makefile create mode 100644 src/enacl.app.src create mode 100644 src/enacl.erl create mode 100644 src/enacl_app.erl create mode 100644 src/enacl_nif.erl diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..89c5d14 --- /dev/null +++ b/Makefile @@ -0,0 +1,13 @@ +REBAR=rebar + +.PHONY: compile +compile: deps + $(REBAR) compile + +.PHONY: deps +deps: + $(REBAR) get-deps + +.PHONY: clean +clean: + $(REBAR) clean diff --git a/README.md b/README.md new file mode 100644 index 0000000..a36cb58 --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +# Erlang bindings for NaCl + +This library provides bindings for the NaCl cryptographic library for Erlang. Several such libraries exist, but this one is a re-write with a number of different requirements, and foci: + +* Erlang/OTP 17.3. This library *needs* the newest dirty scheduler implementation. +* Uses the original NaCl sources over something like libsodium. This is a deliberate choice. +* Tests created by aggressive use of Erlang QuickCheck. +* provides gen_nacl, a gen_tcp wrapper for sending/receiving messages over a tcp socket. + +This package draws heavy inspiration from "erlang-nacl" by Tony Garnock-Jones. diff --git a/c_src/enacl_nif.c b/c_src/enacl_nif.c new file mode 100644 index 0000000..adcbb31 --- /dev/null +++ b/c_src/enacl_nif.c @@ -0,0 +1,54 @@ +#include "erl_nif.h" + +#include + +static +ERL_NIF_TERM nacl_error_tuple(ErlNifEnv *env, char *error_atom) { + return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, error_atom)); +} + +static +ERL_NIF_TERM enif_crypto_hash(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) { + ErlNifBinary input; + ErlNifBinary result; + + if ((argc != 1) || (!enif_inspect_iolist_as_binary(env, argv[0], &input))) { + return enif_make_badarg(env); + } + + if (!enif_alloc_binary(crypto_hash_BYTES, &result)) { + return nacl_error_tuple(env, "alloc_failed"); + } + + crypto_hash(result.data, input.data, input.size); + + return enif_make_binary(env, &result); +} + +static +ERL_NIF_TERM enif_crypto_box_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_box_PUBLICKEYBYTES, &pk)) { + return nacl_error_tuple(env, "alloc_failed"); + } + + if (!enif_alloc_binary(crypto_box_SECRETKEYBYTES, &sk)) { + return nacl_error_tuple(env, "alloc_failed"); + } + + crypto_box_keypair(pk.data, sk.data); + + return enif_make_tuple3(env, enif_make_atom(env, "ok"), enif_make_binary(env, &pk), enif_make_binary(env, &sk)); +} + +static ErlNifFunc nif_funcs[] = { + {"crypto_box_keypair", 0, enif_crypto_box_keypair}, + {"crypto_hash", 1, enif_crypto_hash, ERL_NIF_DIRTY_JOB_CPU_BOUND} +}; + +ERL_NIF_INIT(enacl_nif, nif_funcs, NULL, NULL, NULL, NULL); diff --git a/eqc_test/Makefile b/eqc_test/Makefile new file mode 100644 index 0000000..eb9870c --- /dev/null +++ b/eqc_test/Makefile @@ -0,0 +1,5 @@ +console: + erl -pa ../ebin ../deps/*/ebin + +clean: + rm *.beam diff --git a/eqc_test/enacl_eqc.erl b/eqc_test/enacl_eqc.erl new file mode 100644 index 0000000..a135c00 --- /dev/null +++ b/eqc_test/enacl_eqc.erl @@ -0,0 +1,33 @@ +-module(enacl_eqc). +-include_lib("eqc/include/eqc.hrl"). +-compile(export_all). + +%% CRYPTO BOX +%% --------------------------- + +prop_box_keypair() -> + ?FORALL(_X, return(dummy), + ok_box(enacl:box_keypair())). + +ok_box({ok, _PK, _SK}) -> true; +ok_box(_) -> false. + + +%% HASHING +%% --------------------------- +diff_pair(Sz) -> + ?SUCHTHAT({X, Y}, {binary(Sz), binary(Sz)}, + X /= Y). + +prop_crypto_hash_eq() -> + ?FORALL(Sz, oneof([1, 128, 1024, 1024*4]), + ?FORALL(X, binary(Sz), + equals(enacl:hash(X), enacl:hash(X)) + )). + +prop_crypto_hash_neq() -> + ?FORALL(Sz, oneof([1, 128, 1024, 1024*4]), + ?FORALL({X, Y}, diff_pair(Sz), + enacl:hash(X) /= enacl:hash(Y) + )). + diff --git a/rebar.config b/rebar.config new file mode 100644 index 0000000..c849e10 --- /dev/null +++ b/rebar.config @@ -0,0 +1,8 @@ +{erl_opts, [debug_info]}. + +{port_env, [ + {"CFLAGS", "$CFLAGS $LIBSODIUM_CFLAGS"}, + {"LDFLAGS", "$LDFLAGS $LIBSODIUM_LDFLAGS -lsodium"} +]}. + +{port_specs, [{"priv/enacl_nif.so", ["c_src/*.c"]}]}. diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..71182f7 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,2 @@ +all: + $(MAKE) -C .. compile diff --git a/src/enacl.app.src b/src/enacl.app.src new file mode 100644 index 0000000..c7053df --- /dev/null +++ b/src/enacl.app.src @@ -0,0 +1,9 @@ +{application, enacl, + [ + {description, "Erlang NaCl bindings"}, + {vsn, "0.0.1"}, + {registered, []}, + {applications, [kernel, stdlib]}, + {mod, {enacl_app, []}}, + {env, []} +]}. diff --git a/src/enacl.erl b/src/enacl.erl new file mode 100644 index 0000000..5dc54a0 --- /dev/null +++ b/src/enacl.erl @@ -0,0 +1,13 @@ +-module(enacl). + +-export([ + hash/1, + box_keypair/0 +]). + +hash(Bin) -> + enacl_nif:crypto_hash(Bin). + +box_keypair() -> + enacl_nif:crypto_box_keypair(). + diff --git a/src/enacl_app.erl b/src/enacl_app.erl new file mode 100644 index 0000000..65711ac --- /dev/null +++ b/src/enacl_app.erl @@ -0,0 +1,10 @@ +-module(enacl_app). +-behaviour(application). + +-export([start/2, stop/1]). + +start(_StartType, _StartArgs) -> + enacl_sup:start_link(). + +stop(_State) -> + ok. diff --git a/src/enacl_nif.erl b/src/enacl_nif.erl new file mode 100644 index 0000000..0a7075b --- /dev/null +++ b/src/enacl_nif.erl @@ -0,0 +1,21 @@ +-module(enacl_nif). + +-export([ + crypto_hash/1, + crypto_box_keypair/0 +]). +-on_load(init/0). + +init() -> + SoName = filename:join( + case code:priv_dir(enacl) of + {error, bad_name} -> + filename:join(filename:dirname(filename:dirname(code:which(?MODULE))), "priv"); + Dir -> + Dir + end, atom_to_list(?MODULE)), + erlang:load_nif(SoName, 0). + +crypto_hash(Input) when is_binary(Input) -> error({nif_not_loaded, ?MODULE}). +crypto_box_keypair() -> error({nif_not_loaded, ?MODULE}). +