From bf6fb6cf7b78e71941db0ecd00da4642d2e15510 Mon Sep 17 00:00:00 2001 From: Jesper Louis Andersen Date: Mon, 20 Jan 2020 15:31:44 +0100 Subject: [PATCH] Split the remaining operations --- CHANGELOG.md | 2 + c_src/enacl_nif.c | 715 +--------------------------------------------- c_src/hash.c | 32 +++ c_src/hash.h | 9 + c_src/kx.c | 110 +++++++ c_src/kx.h | 24 ++ c_src/public.c | 257 +++++++++++++++++ c_src/public.h | 49 ++++ c_src/secret.c | 322 +++++++++++++++++++++ c_src/secret.h | 70 +++++ 10 files changed, 888 insertions(+), 702 deletions(-) create mode 100644 c_src/kx.c create mode 100644 c_src/kx.h create mode 100644 c_src/public.c create mode 100644 c_src/public.h create mode 100644 c_src/secret.c create mode 100644 c_src/secret.h diff --git a/CHANGELOG.md b/CHANGELOG.md index fe0d620..c192c35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ is a list of changes which are planned for a 1.0 release. - The AEAD_chacha20_poly1305 construction does the nonce wrong. It assumes a 64bit integer, though the real underlying construction accepts 12 bytes. The key isn't generated like this. The AEAD_xchacha20_poly1305 construction does it correctly. +- Plug some subtle allocation leaks in the kx code. +- Plug some subtle memory leaks in the public API. ## [Unreleased] diff --git a/c_src/enacl_nif.c b/c_src/enacl_nif.c index 60142d3..8655eb9 100644 --- a/c_src/enacl_nif.c +++ b/c_src/enacl_nif.c @@ -7,8 +7,11 @@ #include "enacl.h" #include "generichash.h" #include "hash.h" +#include "kx.h" +#include "public.h" #include "pwhash.h" #include "randombytes.h" +#include "secret.h" #include "sign.h" #define CRYPTO_SIGN_STATE_RESOURCE "crypto_sign_state" @@ -36,6 +39,12 @@ static int enacl_crypto_load(ErlNifEnv *env, void **priv_data, return sodium_init(); } +/* GENERAL ROUTINES + * + * These don't generally fit somewhere else nicely, so we keep them in the main + * file + * + */ static ERL_NIF_TERM enacl_crypto_verify_16(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) { ErlNifBinary x, y; @@ -159,708 +168,6 @@ enacl_crypto_curve25519_scalarmult_base(ErlNifEnv *env, int argc, return result; } -/* Public-key cryptography */ -static ERL_NIF_TERM enacl_crypto_box_NONCEBYTES(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - return enif_make_int64(env, crypto_box_NONCEBYTES); -} - -static ERL_NIF_TERM enacl_crypto_box_ZEROBYTES(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - return enif_make_int64(env, crypto_box_ZEROBYTES); -} - -static ERL_NIF_TERM enacl_crypto_box_BOXZEROBYTES(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - return enif_make_int64(env, crypto_box_BOXZEROBYTES); -} - -static ERL_NIF_TERM enacl_crypto_box_PUBLICKEYBYTES(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - return enif_make_int64(env, crypto_box_PUBLICKEYBYTES); -} - -static ERL_NIF_TERM enacl_crypto_box_SECRETKEYBYTES(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - return enif_make_int64(env, crypto_box_SECRETKEYBYTES); -} - -static ERL_NIF_TERM enacl_crypto_box_BEFORENMBYTES(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - return enif_make_int64(env, crypto_box_BEFORENMBYTES); -} - -static ERL_NIF_TERM enacl_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_tuple2(env, enif_make_binary(env, &pk), - enif_make_binary(env, &sk)); -} - -static ERL_NIF_TERM enacl_crypto_box(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - ErlNifBinary padded_msg, nonce, pk, sk, result; - - if ((argc != 4) || - (!enif_inspect_iolist_as_binary(env, argv[0], &padded_msg)) || - (!enif_inspect_binary(env, argv[1], &nonce)) || - (!enif_inspect_binary(env, argv[2], &pk)) || - (!enif_inspect_binary(env, argv[3], &sk))) { - return enif_make_badarg(env); - } - - if ((nonce.size != crypto_box_NONCEBYTES) || - (pk.size != crypto_box_PUBLICKEYBYTES) || - (sk.size != crypto_box_SECRETKEYBYTES) || - (padded_msg.size < crypto_box_ZEROBYTES)) { - return enif_make_badarg(env); - } - - if (!enif_alloc_binary(padded_msg.size, &result)) { - return nacl_error_tuple(env, "alloc_failed"); - } - - if (0 != crypto_box(result.data, padded_msg.data, padded_msg.size, nonce.data, - pk.data, sk.data)) { - return nacl_error_tuple(env, "box_error"); - } - - return enif_make_sub_binary(env, enif_make_binary(env, &result), - crypto_box_BOXZEROBYTES, - padded_msg.size - crypto_box_BOXZEROBYTES); -} - -static ERL_NIF_TERM enacl_crypto_box_open(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - ErlNifBinary padded_ciphertext, nonce, pk, sk, result; - - if ((argc != 4) || - (!enif_inspect_iolist_as_binary(env, argv[0], &padded_ciphertext)) || - (!enif_inspect_binary(env, argv[1], &nonce)) || - (!enif_inspect_binary(env, argv[2], &pk)) || - (!enif_inspect_binary(env, argv[3], &sk))) { - return enif_make_badarg(env); - } - - if ((nonce.size != crypto_box_NONCEBYTES) || - (pk.size != crypto_box_PUBLICKEYBYTES) || - (sk.size != crypto_box_SECRETKEYBYTES) || - (padded_ciphertext.size < crypto_box_BOXZEROBYTES)) { - return enif_make_badarg(env); - } - - if (!enif_alloc_binary(padded_ciphertext.size, &result)) { - return nacl_error_tuple(env, "alloc_failed"); - } - - if (0 != crypto_box_open(result.data, padded_ciphertext.data, - padded_ciphertext.size, nonce.data, pk.data, - sk.data)) { - enif_release_binary(&result); - return nacl_error_tuple(env, "failed_verification"); - } - - return enif_make_sub_binary(env, enif_make_binary(env, &result), - crypto_box_ZEROBYTES, - padded_ciphertext.size - crypto_box_ZEROBYTES); -} - -/* Precomputed crypto boxes */ - -static ERL_NIF_TERM enacl_crypto_box_beforenm(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - ErlNifBinary k, pk, sk; - - if ((argc != 2) || (!enif_inspect_binary(env, argv[0], &pk)) || - (!enif_inspect_binary(env, argv[1], &sk)) || - (pk.size != crypto_box_PUBLICKEYBYTES) || - (sk.size != crypto_box_SECRETKEYBYTES)) { - return enif_make_badarg(env); - } - - if (!enif_alloc_binary(crypto_box_BEFORENMBYTES, &k)) { - return nacl_error_tuple(env, "alloc_failed"); - } - - if (0 != crypto_box_beforenm(k.data, pk.data, sk.data)) { - // error - return nacl_error_tuple(env, "error_gen_shared_secret"); - } - - return enif_make_binary(env, &k); -} - -static ERL_NIF_TERM enacl_crypto_box_afternm(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - ErlNifBinary result, m, nonce, k; - - if ((argc != 3) || (!enif_inspect_iolist_as_binary(env, argv[0], &m)) || - (!enif_inspect_binary(env, argv[1], &nonce)) || - (!enif_inspect_binary(env, argv[2], &k)) || - (m.size < crypto_box_ZEROBYTES) || - (nonce.size != crypto_box_NONCEBYTES) || - (k.size != crypto_box_BEFORENMBYTES)) { - return enif_make_badarg(env); - } - - if (!enif_alloc_binary(m.size, &result)) { - return nacl_error_tuple(env, "alloc_failed"); - } - - crypto_box_afternm(result.data, m.data, m.size, nonce.data, k.data); - - return enif_make_sub_binary(env, enif_make_binary(env, &result), - crypto_box_BOXZEROBYTES, - m.size - crypto_box_BOXZEROBYTES); -} - -static ERL_NIF_TERM enacl_crypto_box_open_afternm(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - ErlNifBinary result, m, nonce, k; - - if ((argc != 3) || (!enif_inspect_iolist_as_binary(env, argv[0], &m)) || - (!enif_inspect_binary(env, argv[1], &nonce)) || - (!enif_inspect_binary(env, argv[2], &k)) || - (m.size < crypto_box_BOXZEROBYTES) || - (nonce.size != crypto_box_NONCEBYTES) || - (k.size != crypto_box_BEFORENMBYTES)) { - return enif_make_badarg(env); - } - - if (!enif_alloc_binary(m.size, &result)) { - return nacl_error_tuple(env, "alloc_failed"); - } - - if (0 != crypto_box_open_afternm(result.data, m.data, m.size, nonce.data, - k.data)) { - enif_release_binary(&result); - return nacl_error_tuple(env, "failed_verification"); - } - - return enif_make_sub_binary(env, enif_make_binary(env, &result), - crypto_box_ZEROBYTES, - m.size - crypto_box_ZEROBYTES); -} - -/* Sealed box functions */ - -static ERL_NIF_TERM enacl_crypto_box_SEALBYTES(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - return enif_make_int64(env, crypto_box_SEALBYTES); -} - -static ERL_NIF_TERM enacl_crypto_box_seal(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - ErlNifBinary key, msg, ciphertext; - - if ((argc != 2) || (!enif_inspect_iolist_as_binary(env, argv[0], &msg)) || - (!enif_inspect_binary(env, argv[1], &key))) { - return enif_make_badarg(env); - } - - if (!enif_alloc_binary(msg.size + crypto_box_SEALBYTES, &ciphertext)) { - return nacl_error_tuple(env, "alloc_failed"); - } - - crypto_box_seal(ciphertext.data, msg.data, msg.size, key.data); - - return enif_make_binary(env, &ciphertext); -} - -static ERL_NIF_TERM enacl_crypto_box_seal_open(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - ErlNifBinary pk, sk, ciphertext, msg; - - if ((argc != 3) || - (!enif_inspect_iolist_as_binary(env, argv[0], &ciphertext)) || - (!enif_inspect_binary(env, argv[1], &pk)) || - (!enif_inspect_binary(env, argv[2], &sk))) { - return enif_make_badarg(env); - } - - if (ciphertext.size < crypto_box_SEALBYTES) { - return enif_make_badarg(env); - } - - if (!enif_alloc_binary(ciphertext.size - crypto_box_SEALBYTES, &msg)) { - return nacl_error_tuple(env, "alloc_failed"); - } - - if (crypto_box_seal_open(msg.data, ciphertext.data, ciphertext.size, pk.data, - sk.data) != 0) { - enif_release_binary(&msg); - return nacl_error_tuple(env, "failed_verification"); - } - - return enif_make_binary(env, &msg); -} - -/* Secret key cryptography */ - -static ERL_NIF_TERM -enacl_crypto_secretbox_NONCEBYTES(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - return enif_make_int64(env, crypto_secretbox_NONCEBYTES); -} - -static ERL_NIF_TERM enacl_crypto_secretbox_KEYBYTES(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - return enif_make_int64(env, crypto_secretbox_KEYBYTES); -} - -static ERL_NIF_TERM -enacl_crypto_secretbox_ZEROBYTES(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - return enif_make_int64(env, crypto_secretbox_ZEROBYTES); -} - -static ERL_NIF_TERM -enacl_crypto_secretbox_BOXZEROBYTES(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - return enif_make_int64(env, crypto_secretbox_BOXZEROBYTES); -} - -static ERL_NIF_TERM -enacl_crypto_stream_chacha20_KEYBYTES(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - return enif_make_int64(env, crypto_stream_chacha20_KEYBYTES); -} - -static ERL_NIF_TERM -enacl_crypto_stream_chacha20_NONCEBYTES(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - return enif_make_int64(env, crypto_stream_chacha20_NONCEBYTES); -} - -static ERL_NIF_TERM enacl_crypto_stream_KEYBYTES(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - return enif_make_int64(env, crypto_stream_KEYBYTES); -} - -static ERL_NIF_TERM enacl_crypto_stream_NONCEBYTES(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - return enif_make_int64(env, crypto_stream_NONCEBYTES); -} - -static ERL_NIF_TERM enacl_crypto_auth_BYTES(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - return enif_make_int64(env, crypto_auth_BYTES); -} - -static ERL_NIF_TERM enacl_crypto_auth_KEYBYTES(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - return enif_make_int64(env, crypto_auth_KEYBYTES); -} - -static ERL_NIF_TERM enacl_crypto_shorthash_BYTES(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - return enif_make_int64(env, crypto_shorthash_BYTES); -} - -static ERL_NIF_TERM enacl_crypto_shorthash_KEYBYTES(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - return enif_make_int64(env, crypto_shorthash_KEYBYTES); -} - -static ERL_NIF_TERM enacl_crypto_onetimeauth_BYTES(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - return enif_make_int64(env, crypto_onetimeauth_BYTES); -} - -static ERL_NIF_TERM -enacl_crypto_onetimeauth_KEYBYTES(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - return enif_make_int64(env, crypto_onetimeauth_KEYBYTES); -} - -static ERL_NIF_TERM enacl_crypto_secretbox(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - ErlNifBinary key, nonce, padded_msg, padded_ciphertext; - - if ((argc != 3) || - (!enif_inspect_iolist_as_binary(env, argv[0], &padded_msg)) || - (!enif_inspect_binary(env, argv[1], &nonce)) || - (!enif_inspect_binary(env, argv[2], &key))) { - return enif_make_badarg(env); - } - - if ((key.size != crypto_secretbox_KEYBYTES) || - (nonce.size != crypto_secretbox_NONCEBYTES) || - (padded_msg.size < crypto_secretbox_ZEROBYTES)) { - return enif_make_badarg(env); - } - - if (!enif_alloc_binary(padded_msg.size, &padded_ciphertext)) { - return nacl_error_tuple(env, "alloc_failed"); - } - - crypto_secretbox(padded_ciphertext.data, padded_msg.data, padded_msg.size, - nonce.data, key.data); - - return enif_make_sub_binary(env, enif_make_binary(env, &padded_ciphertext), - crypto_secretbox_BOXZEROBYTES, - padded_msg.size - crypto_secretbox_BOXZEROBYTES); -} - -static ERL_NIF_TERM enacl_crypto_secretbox_open(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - ErlNifBinary key, nonce, padded_ciphertext, padded_msg; - - if ((argc != 3) || - (!enif_inspect_iolist_as_binary(env, argv[0], &padded_ciphertext)) || - (!enif_inspect_binary(env, argv[1], &nonce)) || - (!enif_inspect_binary(env, argv[2], &key))) { - return enif_make_badarg(env); - } - - if ((key.size != crypto_secretbox_KEYBYTES) || - (nonce.size != crypto_secretbox_NONCEBYTES) || - (padded_ciphertext.size < crypto_secretbox_BOXZEROBYTES)) { - return enif_make_badarg(env); - } - - if (!enif_alloc_binary(padded_ciphertext.size, &padded_msg)) { - return nacl_error_tuple(env, "alloc_failed"); - } - - if (crypto_secretbox_open(padded_msg.data, padded_ciphertext.data, - padded_ciphertext.size, nonce.data, - key.data) != 0) { - enif_release_binary(&padded_msg); - return nacl_error_tuple(env, "failed_verification"); - } - - return enif_make_sub_binary( - env, enif_make_binary(env, &padded_msg), crypto_secretbox_ZEROBYTES, - padded_ciphertext.size - crypto_secretbox_ZEROBYTES); -} - -static ERL_NIF_TERM enacl_crypto_stream_chacha20(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - ErlNifBinary c, n, k; - ErlNifUInt64 clen; - - if ((argc != 3) || (!enif_get_uint64(env, argv[0], &clen)) || - (!enif_inspect_binary(env, argv[1], &n)) || - (!enif_inspect_binary(env, argv[2], &k))) { - return enif_make_badarg(env); - } - - if ((k.size != crypto_stream_chacha20_KEYBYTES) || - (n.size != crypto_stream_chacha20_NONCEBYTES)) { - return enif_make_badarg(env); - } - - if (!enif_alloc_binary(clen, &c)) { - return nacl_error_tuple(env, "alloc_failed"); - } - - crypto_stream_chacha20(c.data, c.size, n.data, k.data); - - return enif_make_binary(env, &c); -} - -static ERL_NIF_TERM -enacl_crypto_stream_chacha20_xor(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - ErlNifBinary c, m, n, k; - - if ((argc != 3) || (!enif_inspect_iolist_as_binary(env, argv[0], &m)) || - (!enif_inspect_binary(env, argv[1], &n)) || - (!enif_inspect_binary(env, argv[2], &k))) { - return enif_make_badarg(env); - } - - if ((k.size != crypto_stream_chacha20_KEYBYTES) || - (n.size != crypto_stream_chacha20_NONCEBYTES)) { - return enif_make_badarg(env); - } - - if (!enif_alloc_binary(m.size, &c)) { - return nacl_error_tuple(env, "alloc_failed"); - } - - crypto_stream_chacha20_xor(c.data, m.data, m.size, n.data, k.data); - - return enif_make_binary(env, &c); -} - -static ERL_NIF_TERM enacl_crypto_stream(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - ErlNifBinary c, n, k; - ErlNifUInt64 clen; - - if ((argc != 3) || (!enif_get_uint64(env, argv[0], &clen)) || - (!enif_inspect_binary(env, argv[1], &n)) || - (!enif_inspect_binary(env, argv[2], &k))) { - return enif_make_badarg(env); - } - - if ((k.size != crypto_stream_KEYBYTES) || - (n.size != crypto_stream_NONCEBYTES)) { - return enif_make_badarg(env); - } - - if (!enif_alloc_binary(clen, &c)) { - return nacl_error_tuple(env, "alloc_failed"); - } - - crypto_stream(c.data, c.size, n.data, k.data); - - return enif_make_binary(env, &c); -} - -static ERL_NIF_TERM enacl_crypto_stream_xor(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - ErlNifBinary c, m, n, k; - - if ((argc != 3) || (!enif_inspect_iolist_as_binary(env, argv[0], &m)) || - (!enif_inspect_binary(env, argv[1], &n)) || - (!enif_inspect_binary(env, argv[2], &k))) { - return enif_make_badarg(env); - } - - if ((k.size != crypto_stream_KEYBYTES) || - (n.size != crypto_stream_NONCEBYTES)) { - return enif_make_badarg(env); - } - - if (!enif_alloc_binary(m.size, &c)) { - return nacl_error_tuple(env, "alloc_failed"); - } - - crypto_stream_xor(c.data, m.data, m.size, n.data, k.data); - - return enif_make_binary(env, &c); -} - -static ERL_NIF_TERM enacl_crypto_auth(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - ErlNifBinary a, m, k; - - if ((argc != 2) || (!enif_inspect_iolist_as_binary(env, argv[0], &m)) || - (!enif_inspect_binary(env, argv[1], &k))) { - return enif_make_badarg(env); - } - - if (k.size != crypto_auth_KEYBYTES) { - return enif_make_badarg(env); - } - - if (!enif_alloc_binary(crypto_auth_BYTES, &a)) { - return nacl_error_tuple(env, "alloc_failed"); - } - - crypto_auth(a.data, m.data, m.size, k.data); - - return enif_make_binary(env, &a); -} - -static ERL_NIF_TERM enacl_crypto_auth_verify(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - ErlNifBinary a, m, k; - - if ((argc != 3) || (!enif_inspect_binary(env, argv[0], &a)) || - (!enif_inspect_iolist_as_binary(env, argv[1], &m)) || - (!enif_inspect_binary(env, argv[2], &k))) { - return enif_make_badarg(env); - } - - if ((k.size != crypto_auth_KEYBYTES) || (a.size != crypto_auth_BYTES)) { - return enif_make_badarg(env); - } - - if (0 == crypto_auth_verify(a.data, m.data, m.size, k.data)) { - return enif_make_atom(env, "true"); - } else { - return enif_make_atom(env, "false"); - } -} - -static ERL_NIF_TERM enacl_crypto_shorthash(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - ErlNifBinary a, m, k; - - if ((argc != 2) || (!enif_inspect_iolist_as_binary(env, argv[0], &m)) || - (!enif_inspect_binary(env, argv[1], &k))) { - return enif_make_badarg(env); - } - - if (k.size != crypto_shorthash_KEYBYTES) { - return enif_make_badarg(env); - } - - if (!enif_alloc_binary(crypto_shorthash_BYTES, &a)) { - return nacl_error_tuple(env, "alloc_failed"); - } - - crypto_shorthash(a.data, m.data, m.size, k.data); - - return enif_make_binary(env, &a); -} - -static ERL_NIF_TERM enacl_crypto_onetimeauth(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - ErlNifBinary a, m, k; - - if ((argc != 2) || (!enif_inspect_iolist_as_binary(env, argv[0], &m)) || - (!enif_inspect_binary(env, argv[1], &k))) { - return enif_make_badarg(env); - } - - if (k.size != crypto_onetimeauth_KEYBYTES) { - return enif_make_badarg(env); - } - - if (!enif_alloc_binary(crypto_onetimeauth_BYTES, &a)) { - return nacl_error_tuple(env, "alloc_failed"); - } - - crypto_onetimeauth(a.data, m.data, m.size, k.data); - - return enif_make_binary(env, &a); -} - -static ERL_NIF_TERM enacl_crypto_onetimeauth_verify(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - ErlNifBinary a, m, k; - - if ((argc != 3) || (!enif_inspect_binary(env, argv[0], &a)) || - (!enif_inspect_iolist_as_binary(env, argv[1], &m)) || - (!enif_inspect_binary(env, argv[2], &k))) { - return enif_make_badarg(env); - } - - if ((k.size != crypto_onetimeauth_KEYBYTES) || - (a.size != crypto_onetimeauth_BYTES)) { - return enif_make_badarg(env); - } - - if (0 == crypto_onetimeauth_verify(a.data, m.data, m.size, k.data)) { - return enif_make_atom(env, "true"); - } else { - return enif_make_atom(env, "false"); - } -} - -/* Key exchange */ - -static ERL_NIF_TERM enacl_crypto_kx_SECRETKEYBYTES(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - return enif_make_int64(env, crypto_kx_SECRETKEYBYTES); -} - -static ERL_NIF_TERM enacl_crypto_kx_PUBLICKEYBYTES(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - return enif_make_int64(env, crypto_kx_PUBLICKEYBYTES); -} - -static ERL_NIF_TERM enacl_crypto_kx_SESSIONKEYBYTES(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - return enif_make_int64(env, crypto_kx_SESSIONKEYBYTES); -} - -static ERL_NIF_TERM enacl_crypto_kx_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_kx_PUBLICKEYBYTES, &pk)) { - return nacl_error_tuple(env, "alloc_failed"); - } - - if (!enif_alloc_binary(crypto_kx_SECRETKEYBYTES, &sk)) { - return nacl_error_tuple(env, "alloc_failed"); - } - - crypto_kx_keypair(pk.data, sk.data); - - return enif_make_tuple2(env, enif_make_binary(env, &pk), - enif_make_binary(env, &sk)); -} - -static ERL_NIF_TERM -enacl_crypto_kx_server_session_keys(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - ErlNifBinary rx, tx, server_pk, server_sk, client_pk; - - if ((argc != 3) || (!enif_inspect_binary(env, argv[0], &server_pk)) || - (!enif_inspect_binary(env, argv[1], &server_sk)) || - (!enif_inspect_binary(env, argv[2], &client_pk)) || - (server_pk.size != crypto_kx_PUBLICKEYBYTES) || - (server_sk.size != crypto_kx_SECRETKEYBYTES) || - (client_pk.size != crypto_kx_PUBLICKEYBYTES)) { - return enif_make_badarg(env); - } - - if (!enif_alloc_binary(crypto_kx_SESSIONKEYBYTES, &rx)) { - return nacl_error_tuple(env, "alloc_failed"); - } - - if (!enif_alloc_binary(crypto_kx_SESSIONKEYBYTES, &tx)) { - return nacl_error_tuple(env, "alloc_failed"); - } - - if (0 != crypto_kx_server_session_keys(rx.data, tx.data, server_pk.data, - server_sk.data, client_pk.data)) { - // suspicious client public key - return nacl_error_tuple(env, "invalid_client_public_key"); - } - - return enif_make_tuple2(env, enif_make_binary(env, &rx), - enif_make_binary(env, &tx)); -} - -static ERL_NIF_TERM -enacl_crypto_kx_client_session_keys(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - ErlNifBinary rx, tx, client_pk, client_sk, server_pk; - - if ((argc != 3) || (!enif_inspect_binary(env, argv[0], &client_pk)) || - (!enif_inspect_binary(env, argv[1], &client_sk)) || - (!enif_inspect_binary(env, argv[2], &server_pk)) || - (client_pk.size != crypto_kx_PUBLICKEYBYTES) || - (client_sk.size != crypto_kx_SECRETKEYBYTES) || - (server_pk.size != crypto_kx_PUBLICKEYBYTES)) { - return enif_make_badarg(env); - } - - if (!enif_alloc_binary(crypto_kx_SESSIONKEYBYTES, &rx)) { - return nacl_error_tuple(env, "alloc_failed"); - } - - if (!enif_alloc_binary(crypto_kx_SESSIONKEYBYTES, &tx)) { - return nacl_error_tuple(env, "alloc_failed"); - } - - if (0 != crypto_kx_client_session_keys(rx.data, tx.data, client_pk.data, - client_sk.data, server_pk.data)) { - // suspicious server public key - return nacl_error_tuple(env, "invalid_server_public_key"); - } - - return enif_make_tuple2(env, enif_make_binary(env, &rx), - enif_make_binary(env, &tx)); -} - /* Various other helper functions */ static void uint64_pack(unsigned char *y, ErlNifUInt64 x) { *y++ = x; @@ -1078,6 +385,10 @@ static ErlNifFunc nif_funcs[] = { // Linux might block here if early in the boot sequence, so get it off the // main scheduler. Otherwise, it it would probably be fine to run on the // main scheduler. This plays it safe, albeit with a performance hit. + // + // However: you shouldn't use a CSPRNG unless you need one. So it is + // probably fine to do the dirty-scheduler dance. Using the random + // material should dwarf the extraction of random material. erl_nif_dirty_job_cpu_bound_macro("randombytes", 1, enif_randombytes), erl_nif_dirty_job_cpu_bound_macro("randombytes_uint32", 0, enif_randombytes_uint32), diff --git a/c_src/hash.c b/c_src/hash.c index ac08f45..6475596 100644 --- a/c_src/hash.c +++ b/c_src/hash.c @@ -4,6 +4,38 @@ #include "hash.h" +ERL_NIF_TERM enacl_crypto_shorthash_BYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + return enif_make_int64(env, crypto_shorthash_BYTES); +} + +ERL_NIF_TERM enacl_crypto_shorthash_KEYBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + return enif_make_int64(env, crypto_shorthash_KEYBYTES); +} + +ERL_NIF_TERM enacl_crypto_shorthash(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ErlNifBinary a, m, k; + + if ((argc != 2) || (!enif_inspect_iolist_as_binary(env, argv[0], &m)) || + (!enif_inspect_binary(env, argv[1], &k))) { + return enif_make_badarg(env); + } + + if (k.size != crypto_shorthash_KEYBYTES) { + return enif_make_badarg(env); + } + + if (!enif_alloc_binary(crypto_shorthash_BYTES, &a)) { + return nacl_error_tuple(env, "alloc_failed"); + } + + crypto_shorthash(a.data, m.data, m.size, k.data); + + return enif_make_binary(env, &a); +} + ERL_NIF_TERM enacl_crypto_hash(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) { ErlNifBinary input; diff --git a/c_src/hash.h b/c_src/hash.h index 9f5b721..080b7bf 100644 --- a/c_src/hash.h +++ b/c_src/hash.h @@ -3,6 +3,15 @@ #include +ERL_NIF_TERM enacl_crypto_shorthash_BYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_shorthash_KEYBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_shorthash(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + ERL_NIF_TERM enacl_crypto_hash(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); #endif \ No newline at end of file diff --git a/c_src/kx.c b/c_src/kx.c new file mode 100644 index 0000000..283328b --- /dev/null +++ b/c_src/kx.c @@ -0,0 +1,110 @@ +#include + +#include + +#include "enacl.h" +#include "kx.h" + +/* Key exchange */ + +ERL_NIF_TERM enacl_crypto_kx_SECRETKEYBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + return enif_make_int64(env, crypto_kx_SECRETKEYBYTES); +} + +ERL_NIF_TERM enacl_crypto_kx_PUBLICKEYBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + return enif_make_int64(env, crypto_kx_PUBLICKEYBYTES); +} + +ERL_NIF_TERM enacl_crypto_kx_SESSIONKEYBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + return enif_make_int64(env, crypto_kx_SESSIONKEYBYTES); +} + +ERL_NIF_TERM enacl_crypto_kx_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_kx_PUBLICKEYBYTES, &pk)) { + return nacl_error_tuple(env, "alloc_failed"); + } + + if (!enif_alloc_binary(crypto_kx_SECRETKEYBYTES, &sk)) { + enif_release_binary(&pk); + return nacl_error_tuple(env, "alloc_failed"); + } + + crypto_kx_keypair(pk.data, sk.data); + + return enif_make_tuple2(env, enif_make_binary(env, &pk), + enif_make_binary(env, &sk)); +} + +ERL_NIF_TERM +enacl_crypto_kx_server_session_keys(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ErlNifBinary rx, tx, server_pk, server_sk, client_pk; + + if ((argc != 3) || (!enif_inspect_binary(env, argv[0], &server_pk)) || + (!enif_inspect_binary(env, argv[1], &server_sk)) || + (!enif_inspect_binary(env, argv[2], &client_pk)) || + (server_pk.size != crypto_kx_PUBLICKEYBYTES) || + (server_sk.size != crypto_kx_SECRETKEYBYTES) || + (client_pk.size != crypto_kx_PUBLICKEYBYTES)) { + return enif_make_badarg(env); + } + + if (!enif_alloc_binary(crypto_kx_SESSIONKEYBYTES, &rx)) { + return nacl_error_tuple(env, "alloc_failed"); + } + + if (!enif_alloc_binary(crypto_kx_SESSIONKEYBYTES, &tx)) { + return nacl_error_tuple(env, "alloc_failed"); + } + + if (0 != crypto_kx_server_session_keys(rx.data, tx.data, server_pk.data, + server_sk.data, client_pk.data)) { + // suspicious client public key + return nacl_error_tuple(env, "invalid_client_public_key"); + } + + return enif_make_tuple2(env, enif_make_binary(env, &rx), + enif_make_binary(env, &tx)); +} + +ERL_NIF_TERM +enacl_crypto_kx_client_session_keys(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ErlNifBinary rx, tx, client_pk, client_sk, server_pk; + + if ((argc != 3) || (!enif_inspect_binary(env, argv[0], &client_pk)) || + (!enif_inspect_binary(env, argv[1], &client_sk)) || + (!enif_inspect_binary(env, argv[2], &server_pk)) || + (client_pk.size != crypto_kx_PUBLICKEYBYTES) || + (client_sk.size != crypto_kx_SECRETKEYBYTES) || + (server_pk.size != crypto_kx_PUBLICKEYBYTES)) { + return enif_make_badarg(env); + } + + if (!enif_alloc_binary(crypto_kx_SESSIONKEYBYTES, &rx)) { + return nacl_error_tuple(env, "alloc_failed"); + } + + if (!enif_alloc_binary(crypto_kx_SESSIONKEYBYTES, &tx)) { + return nacl_error_tuple(env, "alloc_failed"); + } + + if (0 != crypto_kx_client_session_keys(rx.data, tx.data, client_pk.data, + client_sk.data, server_pk.data)) { + // suspicious server public key + return nacl_error_tuple(env, "invalid_server_public_key"); + } + + return enif_make_tuple2(env, enif_make_binary(env, &rx), + enif_make_binary(env, &tx)); +} \ No newline at end of file diff --git a/c_src/kx.h b/c_src/kx.h new file mode 100644 index 0000000..79a7c21 --- /dev/null +++ b/c_src/kx.h @@ -0,0 +1,24 @@ +#ifndef ENACL_KX_H +#define ENACL_KX_H + +#include + +ERL_NIF_TERM enacl_crypto_kx_SECRETKEYBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_kx_PUBLICKEYBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_kx_SESSIONKEYBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_kx_keypair(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_kx_server_session_keys(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_kx_client_session_keys(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +#endif diff --git a/c_src/public.c b/c_src/public.c new file mode 100644 index 0000000..ef83f7e --- /dev/null +++ b/c_src/public.c @@ -0,0 +1,257 @@ +#include + +#include + +#include "enacl.h" +#include "public.h" + +/* Public-key cryptography */ +ERL_NIF_TERM enacl_crypto_box_NONCEBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + return enif_make_int64(env, crypto_box_NONCEBYTES); +} + +ERL_NIF_TERM enacl_crypto_box_ZEROBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + return enif_make_int64(env, crypto_box_ZEROBYTES); +} + +ERL_NIF_TERM enacl_crypto_box_BOXZEROBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + return enif_make_int64(env, crypto_box_BOXZEROBYTES); +} + +ERL_NIF_TERM enacl_crypto_box_PUBLICKEYBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + return enif_make_int64(env, crypto_box_PUBLICKEYBYTES); +} + +ERL_NIF_TERM enacl_crypto_box_SECRETKEYBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + return enif_make_int64(env, crypto_box_SECRETKEYBYTES); +} + +ERL_NIF_TERM enacl_crypto_box_BEFORENMBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + return enif_make_int64(env, crypto_box_BEFORENMBYTES); +} + +ERL_NIF_TERM enacl_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_tuple2(env, enif_make_binary(env, &pk), + enif_make_binary(env, &sk)); +} + +ERL_NIF_TERM enacl_crypto_box(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ErlNifBinary padded_msg, nonce, pk, sk, result; + + if ((argc != 4) || + (!enif_inspect_iolist_as_binary(env, argv[0], &padded_msg)) || + (!enif_inspect_binary(env, argv[1], &nonce)) || + (!enif_inspect_binary(env, argv[2], &pk)) || + (!enif_inspect_binary(env, argv[3], &sk))) { + return enif_make_badarg(env); + } + + if ((nonce.size != crypto_box_NONCEBYTES) || + (pk.size != crypto_box_PUBLICKEYBYTES) || + (sk.size != crypto_box_SECRETKEYBYTES) || + (padded_msg.size < crypto_box_ZEROBYTES)) { + return enif_make_badarg(env); + } + + if (!enif_alloc_binary(padded_msg.size, &result)) { + return nacl_error_tuple(env, "alloc_failed"); + } + + if (0 != crypto_box(result.data, padded_msg.data, padded_msg.size, nonce.data, + pk.data, sk.data)) { + return nacl_error_tuple(env, "box_error"); + } + + return enif_make_sub_binary(env, enif_make_binary(env, &result), + crypto_box_BOXZEROBYTES, + padded_msg.size - crypto_box_BOXZEROBYTES); +} + +ERL_NIF_TERM enacl_crypto_box_open(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ErlNifBinary padded_ciphertext, nonce, pk, sk, result; + + if ((argc != 4) || + (!enif_inspect_iolist_as_binary(env, argv[0], &padded_ciphertext)) || + (!enif_inspect_binary(env, argv[1], &nonce)) || + (!enif_inspect_binary(env, argv[2], &pk)) || + (!enif_inspect_binary(env, argv[3], &sk))) { + return enif_make_badarg(env); + } + + if ((nonce.size != crypto_box_NONCEBYTES) || + (pk.size != crypto_box_PUBLICKEYBYTES) || + (sk.size != crypto_box_SECRETKEYBYTES) || + (padded_ciphertext.size < crypto_box_BOXZEROBYTES)) { + return enif_make_badarg(env); + } + + if (!enif_alloc_binary(padded_ciphertext.size, &result)) { + return nacl_error_tuple(env, "alloc_failed"); + } + + if (0 != crypto_box_open(result.data, padded_ciphertext.data, + padded_ciphertext.size, nonce.data, pk.data, + sk.data)) { + enif_release_binary(&result); + return nacl_error_tuple(env, "failed_verification"); + } + + return enif_make_sub_binary(env, enif_make_binary(env, &result), + crypto_box_ZEROBYTES, + padded_ciphertext.size - crypto_box_ZEROBYTES); +} + +/* Precomputed crypto boxes */ + +ERL_NIF_TERM enacl_crypto_box_beforenm(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ErlNifBinary k, pk, sk; + + if ((argc != 2) || (!enif_inspect_binary(env, argv[0], &pk)) || + (!enif_inspect_binary(env, argv[1], &sk)) || + (pk.size != crypto_box_PUBLICKEYBYTES) || + (sk.size != crypto_box_SECRETKEYBYTES)) { + return enif_make_badarg(env); + } + + if (!enif_alloc_binary(crypto_box_BEFORENMBYTES, &k)) { + return nacl_error_tuple(env, "alloc_failed"); + } + + if (0 != crypto_box_beforenm(k.data, pk.data, sk.data)) { + // error + return nacl_error_tuple(env, "error_gen_shared_secret"); + } + + return enif_make_binary(env, &k); +} + +ERL_NIF_TERM enacl_crypto_box_afternm(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ErlNifBinary result, m, nonce, k; + + if ((argc != 3) || (!enif_inspect_iolist_as_binary(env, argv[0], &m)) || + (!enif_inspect_binary(env, argv[1], &nonce)) || + (!enif_inspect_binary(env, argv[2], &k)) || + (m.size < crypto_box_ZEROBYTES) || + (nonce.size != crypto_box_NONCEBYTES) || + (k.size != crypto_box_BEFORENMBYTES)) { + return enif_make_badarg(env); + } + + if (!enif_alloc_binary(m.size, &result)) { + return nacl_error_tuple(env, "alloc_failed"); + } + + crypto_box_afternm(result.data, m.data, m.size, nonce.data, k.data); + + return enif_make_sub_binary(env, enif_make_binary(env, &result), + crypto_box_BOXZEROBYTES, + m.size - crypto_box_BOXZEROBYTES); +} + +ERL_NIF_TERM enacl_crypto_box_open_afternm(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ErlNifBinary result, m, nonce, k; + + if ((argc != 3) || (!enif_inspect_iolist_as_binary(env, argv[0], &m)) || + (!enif_inspect_binary(env, argv[1], &nonce)) || + (!enif_inspect_binary(env, argv[2], &k)) || + (m.size < crypto_box_BOXZEROBYTES) || + (nonce.size != crypto_box_NONCEBYTES) || + (k.size != crypto_box_BEFORENMBYTES)) { + return enif_make_badarg(env); + } + + if (!enif_alloc_binary(m.size, &result)) { + return nacl_error_tuple(env, "alloc_failed"); + } + + if (0 != crypto_box_open_afternm(result.data, m.data, m.size, nonce.data, + k.data)) { + enif_release_binary(&result); + return nacl_error_tuple(env, "failed_verification"); + } + + return enif_make_sub_binary(env, enif_make_binary(env, &result), + crypto_box_ZEROBYTES, + m.size - crypto_box_ZEROBYTES); +} + +/* Sealed box functions */ + +ERL_NIF_TERM enacl_crypto_box_SEALBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + return enif_make_int64(env, crypto_box_SEALBYTES); +} + +ERL_NIF_TERM enacl_crypto_box_seal(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ErlNifBinary key, msg, ciphertext; + + if ((argc != 2) || (!enif_inspect_iolist_as_binary(env, argv[0], &msg)) || + (!enif_inspect_binary(env, argv[1], &key))) { + return enif_make_badarg(env); + } + + if (!enif_alloc_binary(msg.size + crypto_box_SEALBYTES, &ciphertext)) { + return nacl_error_tuple(env, "alloc_failed"); + } + + crypto_box_seal(ciphertext.data, msg.data, msg.size, key.data); + + return enif_make_binary(env, &ciphertext); +} + +ERL_NIF_TERM enacl_crypto_box_seal_open(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ErlNifBinary pk, sk, ciphertext, msg; + + if ((argc != 3) || + (!enif_inspect_iolist_as_binary(env, argv[0], &ciphertext)) || + (!enif_inspect_binary(env, argv[1], &pk)) || + (!enif_inspect_binary(env, argv[2], &sk))) { + return enif_make_badarg(env); + } + + if (ciphertext.size < crypto_box_SEALBYTES) { + return enif_make_badarg(env); + } + + if (!enif_alloc_binary(ciphertext.size - crypto_box_SEALBYTES, &msg)) { + return nacl_error_tuple(env, "alloc_failed"); + } + + if (crypto_box_seal_open(msg.data, ciphertext.data, ciphertext.size, pk.data, + sk.data) != 0) { + enif_release_binary(&msg); + return nacl_error_tuple(env, "failed_verification"); + } + + return enif_make_binary(env, &msg); +} diff --git a/c_src/public.h b/c_src/public.h new file mode 100644 index 0000000..b750eb1 --- /dev/null +++ b/c_src/public.h @@ -0,0 +1,49 @@ +#ifndef ENACL_PUBLIC_H +#define ENACL_PUBLIC_H + +ERL_NIF_TERM enacl_crypto_box_NONCEBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_box_ZEROBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_box_BOXZEROBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_box_PUBLICKEYBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_box_SECRETKEYBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_box_BEFORENMBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_box_keypair(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_box(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_box_open(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_box_beforenm(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_box_afternm(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_box_open_afternm(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_box_SEALBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_box_seal(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_box_seal_open(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +#endif \ No newline at end of file diff --git a/c_src/secret.c b/c_src/secret.c new file mode 100644 index 0000000..dc72a92 --- /dev/null +++ b/c_src/secret.c @@ -0,0 +1,322 @@ +#include + +#include + +#include "enacl.h" +#include "secret.h" + +/* Secret key cryptography */ + +ERL_NIF_TERM +enacl_crypto_secretbox_NONCEBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + return enif_make_int64(env, crypto_secretbox_NONCEBYTES); +} + +ERL_NIF_TERM enacl_crypto_secretbox_KEYBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + return enif_make_int64(env, crypto_secretbox_KEYBYTES); +} + +ERL_NIF_TERM +enacl_crypto_secretbox_ZEROBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + return enif_make_int64(env, crypto_secretbox_ZEROBYTES); +} + +ERL_NIF_TERM +enacl_crypto_secretbox_BOXZEROBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + return enif_make_int64(env, crypto_secretbox_BOXZEROBYTES); +} + +ERL_NIF_TERM +enacl_crypto_stream_chacha20_KEYBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + return enif_make_int64(env, crypto_stream_chacha20_KEYBYTES); +} + +ERL_NIF_TERM +enacl_crypto_stream_chacha20_NONCEBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + return enif_make_int64(env, crypto_stream_chacha20_NONCEBYTES); +} + +ERL_NIF_TERM enacl_crypto_stream_KEYBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + return enif_make_int64(env, crypto_stream_KEYBYTES); +} + +ERL_NIF_TERM enacl_crypto_stream_NONCEBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + return enif_make_int64(env, crypto_stream_NONCEBYTES); +} + +ERL_NIF_TERM enacl_crypto_auth_BYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + return enif_make_int64(env, crypto_auth_BYTES); +} + +ERL_NIF_TERM enacl_crypto_auth_KEYBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + return enif_make_int64(env, crypto_auth_KEYBYTES); +} + +ERL_NIF_TERM enacl_crypto_onetimeauth_BYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + return enif_make_int64(env, crypto_onetimeauth_BYTES); +} + +ERL_NIF_TERM +enacl_crypto_onetimeauth_KEYBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + return enif_make_int64(env, crypto_onetimeauth_KEYBYTES); +} + +ERL_NIF_TERM enacl_crypto_secretbox(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ErlNifBinary key, nonce, padded_msg, padded_ciphertext; + + if ((argc != 3) || + (!enif_inspect_iolist_as_binary(env, argv[0], &padded_msg)) || + (!enif_inspect_binary(env, argv[1], &nonce)) || + (!enif_inspect_binary(env, argv[2], &key))) { + return enif_make_badarg(env); + } + + if ((key.size != crypto_secretbox_KEYBYTES) || + (nonce.size != crypto_secretbox_NONCEBYTES) || + (padded_msg.size < crypto_secretbox_ZEROBYTES)) { + return enif_make_badarg(env); + } + + if (!enif_alloc_binary(padded_msg.size, &padded_ciphertext)) { + return nacl_error_tuple(env, "alloc_failed"); + } + + crypto_secretbox(padded_ciphertext.data, padded_msg.data, padded_msg.size, + nonce.data, key.data); + + return enif_make_sub_binary(env, enif_make_binary(env, &padded_ciphertext), + crypto_secretbox_BOXZEROBYTES, + padded_msg.size - crypto_secretbox_BOXZEROBYTES); +} + +ERL_NIF_TERM enacl_crypto_secretbox_open(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ErlNifBinary key, nonce, padded_ciphertext, padded_msg; + + if ((argc != 3) || + (!enif_inspect_iolist_as_binary(env, argv[0], &padded_ciphertext)) || + (!enif_inspect_binary(env, argv[1], &nonce)) || + (!enif_inspect_binary(env, argv[2], &key))) { + return enif_make_badarg(env); + } + + if ((key.size != crypto_secretbox_KEYBYTES) || + (nonce.size != crypto_secretbox_NONCEBYTES) || + (padded_ciphertext.size < crypto_secretbox_BOXZEROBYTES)) { + return enif_make_badarg(env); + } + + if (!enif_alloc_binary(padded_ciphertext.size, &padded_msg)) { + return nacl_error_tuple(env, "alloc_failed"); + } + + if (crypto_secretbox_open(padded_msg.data, padded_ciphertext.data, + padded_ciphertext.size, nonce.data, + key.data) != 0) { + enif_release_binary(&padded_msg); + return nacl_error_tuple(env, "failed_verification"); + } + + return enif_make_sub_binary( + env, enif_make_binary(env, &padded_msg), crypto_secretbox_ZEROBYTES, + padded_ciphertext.size - crypto_secretbox_ZEROBYTES); +} + +ERL_NIF_TERM enacl_crypto_stream_chacha20(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ErlNifBinary c, n, k; + ErlNifUInt64 clen; + + if ((argc != 3) || (!enif_get_uint64(env, argv[0], &clen)) || + (!enif_inspect_binary(env, argv[1], &n)) || + (!enif_inspect_binary(env, argv[2], &k))) { + return enif_make_badarg(env); + } + + if ((k.size != crypto_stream_chacha20_KEYBYTES) || + (n.size != crypto_stream_chacha20_NONCEBYTES)) { + return enif_make_badarg(env); + } + + if (!enif_alloc_binary(clen, &c)) { + return nacl_error_tuple(env, "alloc_failed"); + } + + crypto_stream_chacha20(c.data, c.size, n.data, k.data); + + return enif_make_binary(env, &c); +} + +ERL_NIF_TERM +enacl_crypto_stream_chacha20_xor(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ErlNifBinary c, m, n, k; + + if ((argc != 3) || (!enif_inspect_iolist_as_binary(env, argv[0], &m)) || + (!enif_inspect_binary(env, argv[1], &n)) || + (!enif_inspect_binary(env, argv[2], &k))) { + return enif_make_badarg(env); + } + + if ((k.size != crypto_stream_chacha20_KEYBYTES) || + (n.size != crypto_stream_chacha20_NONCEBYTES)) { + return enif_make_badarg(env); + } + + if (!enif_alloc_binary(m.size, &c)) { + return nacl_error_tuple(env, "alloc_failed"); + } + + crypto_stream_chacha20_xor(c.data, m.data, m.size, n.data, k.data); + + return enif_make_binary(env, &c); +} + +ERL_NIF_TERM enacl_crypto_stream(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ErlNifBinary c, n, k; + ErlNifUInt64 clen; + + if ((argc != 3) || (!enif_get_uint64(env, argv[0], &clen)) || + (!enif_inspect_binary(env, argv[1], &n)) || + (!enif_inspect_binary(env, argv[2], &k))) { + return enif_make_badarg(env); + } + + if ((k.size != crypto_stream_KEYBYTES) || + (n.size != crypto_stream_NONCEBYTES)) { + return enif_make_badarg(env); + } + + if (!enif_alloc_binary(clen, &c)) { + return nacl_error_tuple(env, "alloc_failed"); + } + + crypto_stream(c.data, c.size, n.data, k.data); + + return enif_make_binary(env, &c); +} + +ERL_NIF_TERM enacl_crypto_stream_xor(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ErlNifBinary c, m, n, k; + + if ((argc != 3) || (!enif_inspect_iolist_as_binary(env, argv[0], &m)) || + (!enif_inspect_binary(env, argv[1], &n)) || + (!enif_inspect_binary(env, argv[2], &k))) { + return enif_make_badarg(env); + } + + if ((k.size != crypto_stream_KEYBYTES) || + (n.size != crypto_stream_NONCEBYTES)) { + return enif_make_badarg(env); + } + + if (!enif_alloc_binary(m.size, &c)) { + return nacl_error_tuple(env, "alloc_failed"); + } + + crypto_stream_xor(c.data, m.data, m.size, n.data, k.data); + + return enif_make_binary(env, &c); +} + +ERL_NIF_TERM enacl_crypto_auth(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ErlNifBinary a, m, k; + + if ((argc != 2) || (!enif_inspect_iolist_as_binary(env, argv[0], &m)) || + (!enif_inspect_binary(env, argv[1], &k))) { + return enif_make_badarg(env); + } + + if (k.size != crypto_auth_KEYBYTES) { + return enif_make_badarg(env); + } + + if (!enif_alloc_binary(crypto_auth_BYTES, &a)) { + return nacl_error_tuple(env, "alloc_failed"); + } + + crypto_auth(a.data, m.data, m.size, k.data); + + return enif_make_binary(env, &a); +} + +ERL_NIF_TERM enacl_crypto_auth_verify(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ErlNifBinary a, m, k; + + if ((argc != 3) || (!enif_inspect_binary(env, argv[0], &a)) || + (!enif_inspect_iolist_as_binary(env, argv[1], &m)) || + (!enif_inspect_binary(env, argv[2], &k))) { + return enif_make_badarg(env); + } + + if ((k.size != crypto_auth_KEYBYTES) || (a.size != crypto_auth_BYTES)) { + return enif_make_badarg(env); + } + + if (0 == crypto_auth_verify(a.data, m.data, m.size, k.data)) { + return enif_make_atom(env, "true"); + } else { + return enif_make_atom(env, "false"); + } +} + +ERL_NIF_TERM enacl_crypto_onetimeauth(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ErlNifBinary a, m, k; + + if ((argc != 2) || (!enif_inspect_iolist_as_binary(env, argv[0], &m)) || + (!enif_inspect_binary(env, argv[1], &k))) { + return enif_make_badarg(env); + } + + if (k.size != crypto_onetimeauth_KEYBYTES) { + return enif_make_badarg(env); + } + + if (!enif_alloc_binary(crypto_onetimeauth_BYTES, &a)) { + return nacl_error_tuple(env, "alloc_failed"); + } + + crypto_onetimeauth(a.data, m.data, m.size, k.data); + + return enif_make_binary(env, &a); +} + +ERL_NIF_TERM enacl_crypto_onetimeauth_verify(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ErlNifBinary a, m, k; + + if ((argc != 3) || (!enif_inspect_binary(env, argv[0], &a)) || + (!enif_inspect_iolist_as_binary(env, argv[1], &m)) || + (!enif_inspect_binary(env, argv[2], &k))) { + return enif_make_badarg(env); + } + + if ((k.size != crypto_onetimeauth_KEYBYTES) || + (a.size != crypto_onetimeauth_BYTES)) { + return enif_make_badarg(env); + } + + if (0 == crypto_onetimeauth_verify(a.data, m.data, m.size, k.data)) { + return enif_make_atom(env, "true"); + } else { + return enif_make_atom(env, "false"); + } +} diff --git a/c_src/secret.h b/c_src/secret.h new file mode 100644 index 0000000..6c0a4c8 --- /dev/null +++ b/c_src/secret.h @@ -0,0 +1,70 @@ +#ifndef ENACL_SECRET_H +#define ENACL_SECRET_H + +ERL_NIF_TERM enacl_crypto_secretbox_NONCEBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_secretbox_KEYBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_secretbox_ZEROBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_secretbox_BOXZEROBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_stream_chacha20_KEYBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_stream_chacha20_NONCEBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_stream_KEYBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_stream_NONCEBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_auth_BYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_auth_KEYBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_onetimeauth_BYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_onetimeauth_KEYBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_secretbox(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_secretbox_open(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_stream_chacha20(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_stream_chacha20_xor(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_stream(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_stream_xor(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_auth(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_auth_verify(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_onetimeauth(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +ERL_NIF_TERM enacl_crypto_onetimeauth_verify(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]); + +#endif