diff --git a/.gitignore b/.gitignore index a0ca3ba..870be65 100644 --- a/.gitignore +++ b/.gitignore @@ -15,4 +15,5 @@ _build priv/enacl_nif.dll priv/enacl_nif.exp priv/enacl_nif.lib -c_src/enacl_nif.d +c_src/*.d + diff --git a/c_src/enacl.c b/c_src/enacl.c new file mode 100644 index 0000000..e762bb4 --- /dev/null +++ b/c_src/enacl.c @@ -0,0 +1,7 @@ +#include "enacl.h" +#include "erl_nif.h" + +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)); +} diff --git a/c_src/enacl.h b/c_src/enacl.h new file mode 100644 index 0000000..e1fc1af --- /dev/null +++ b/c_src/enacl.h @@ -0,0 +1,13 @@ +#ifndef ENACL_H +#define ENACL_H + +#include "erl_nif.h" + +#define ATOM_OK "ok" +#define ATOM_ERROR "error" +#define ATOM_TRUE "true" +#define ATOM_FALSE "false" + +ERL_NIF_TERM nacl_error_tuple(ErlNifEnv *, char *); + +#endif diff --git a/c_src/enacl_nif.c b/c_src/enacl_nif.c index 079246f..ccc6ebe 100644 --- a/c_src/enacl_nif.c +++ b/c_src/enacl_nif.c @@ -1,15 +1,11 @@ #include "erl_nif.h" +#include #include -#include +#include "enacl.h" +#include "generichash.h" -#define ATOM_OK "ok" -#define ATOM_ERROR "error" -#define ATOM_TRUE "true" -#define ATOM_FALSE "false" - -#define CRYPTO_GENERICHASH_STATE_RESOURCE "crypto_generichash_state" #define CRYPTO_SIGN_STATE_RESOURCE "crypto_sign_state" #ifdef ERL_NIF_DIRTY_JOB_CPU_BOUND @@ -25,21 +21,13 @@ /* Errors */ /* These are global variables for resource types */ -static ErlNifResourceType *generichash_state_type = NULL; static ErlNifResourceType *sign_state_type = NULL; -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)); -} - /* Initialization */ static int enif_crypto_load(ErlNifEnv *env, void **priv_data, ERL_NIF_TERM load_info) { // Create a new resource type for crypto_generichash_state - if (!(generichash_state_type = enif_open_resource_type( - env, NULL, CRYPTO_GENERICHASH_STATE_RESOURCE, NULL, - ERL_NIF_RT_CREATE, NULL))) { + if (!enacl_init_generic_hash_ctx(env)) { return -1; } // Create a new resource type for crypto_sign_state @@ -52,25 +40,6 @@ static int enif_crypto_load(ErlNifEnv *env, void **priv_data, return sodium_init(); } -/* Low-level functions (Hashing, String Equality, ...) */ -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_verify_16(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) { ErlNifBinary x, y; @@ -1764,227 +1733,6 @@ enif_crypto_aead_xchacha20poly1305_decrypt(ErlNifEnv *env, int argc, return enif_make_binary(env, &message); } -/* - * Generic hash - */ -static ERL_NIF_TERM enif_crypto_generichash_BYTES(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - return enif_make_int64(env, crypto_generichash_BYTES); -} - -static ERL_NIF_TERM -enif_crypto_generichash_BYTES_MIN(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - return enif_make_int64(env, crypto_generichash_BYTES_MIN); -} - -static ERL_NIF_TERM -enif_crypto_generichash_BYTES_MAX(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - return enif_make_int64(env, crypto_generichash_BYTES_MAX); -} - -static ERL_NIF_TERM -enif_crypto_generichash_KEYBYTES(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - return enif_make_int64(env, crypto_generichash_KEYBYTES); -} - -static ERL_NIF_TERM -enif_crypto_generichash_KEYBYTES_MIN(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - return enif_make_int64(env, crypto_generichash_KEYBYTES_MIN); -} - -static ERL_NIF_TERM -enif_crypto_generichash_KEYBYTES_MAX(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - return enif_make_int64(env, crypto_generichash_KEYBYTES_MAX); -} - -static ERL_NIF_TERM enif_crypto_generichash(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - ErlNifBinary hash, message, key; - - unsigned hashSize; - - // Validate the arguments - if ((argc != 3) || (!enif_get_uint(env, argv[0], &hashSize)) || - (!enif_inspect_binary(env, argv[1], &message)) || - (!enif_inspect_binary(env, argv[2], &key))) { - return enif_make_badarg(env); - } - - // Verify that hash size is - // crypto_generichash_BYTES/crypto_generichash_BYTES_MIN/crypto_generichash_BYTES_MAX - if ((hashSize < crypto_generichash_BYTES_MIN) || - (hashSize > crypto_generichash_BYTES_MAX)) { - return nacl_error_tuple(env, "invalid_hash_size"); - } - - // validate key size - unsigned char *k = key.data; - if (0 == key.size) { - k = NULL; - } else if (key.size < crypto_generichash_KEYBYTES_MIN || - key.size > crypto_generichash_KEYBYTES_MAX) { - return nacl_error_tuple(env, "invalid_key_size"); - } - - // allocate memory for hash - if (!enif_alloc_binary(hashSize, &hash)) { - return nacl_error_tuple(env, "alloc_failed"); - } - - // calculate hash - if (0 != crypto_generichash(hash.data, hash.size, message.data, message.size, - k, key.size)) { - enif_release_binary(&hash); - return nacl_error_tuple(env, "hash_error"); - } - - ERL_NIF_TERM ok = enif_make_atom(env, ATOM_OK); - ERL_NIF_TERM ret = enif_make_binary(env, &hash); - - return enif_make_tuple2(env, ok, ret); -} - -static crypto_generichash_state *align64(void *ptr) { - if ((unsigned long)ptr % 64 == 0) - return ptr; - return (unsigned long)ptr + (64 - ((unsigned long)ptr % 64)); -} - -static ERL_NIF_TERM enif_crypto_generichash_init(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - ErlNifBinary key; - - unsigned hashSize; - - // Validate the arguments - if ((argc != 2) || (!enif_get_uint(env, argv[0], &hashSize)) || - (!enif_inspect_binary(env, argv[1], &key))) { - return enif_make_badarg(env); - } - - // Verify that hash size is - // crypto_generichash_BYTES/crypto_generichash_BYTES_MIN/crypto_generichash_BYTES_MAX - if ((hashSize < crypto_generichash_BYTES_MIN) || - (hashSize > crypto_generichash_BYTES_MAX)) { - return nacl_error_tuple(env, "invalid_hash_size"); - } - - // validate key size - unsigned char *k = key.data; - if (0 == key.size) { - k = NULL; - } else if (key.size < crypto_generichash_KEYBYTES_MIN || - key.size > crypto_generichash_KEYBYTES_MAX) { - return nacl_error_tuple(env, "invalid_key_size"); - } - - // Create a resource for hash state (+ 60 to make room for 64-byte alignment) - void *state = enif_alloc_resource(generichash_state_type, - crypto_generichash_statebytes() + 60); - if (!state) { - return nacl_error_tuple(env, "alloc_failed"); - } - - // Call the library function - if (0 != crypto_generichash_init(align64(state), k, key.size, hashSize)) { - enif_release_resource(state); - return nacl_error_tuple(env, "hash_init_error"); - } - - // Create return values - ERL_NIF_TERM e1 = enif_make_atom(env, "hashstate"); - ERL_NIF_TERM e2 = argv[0]; - ERL_NIF_TERM e3 = enif_make_resource(env, state); - - // release dynamically allocated memory to erlang to mange - enif_release_resource(state); - - // return a tuple - return enif_make_tuple3(env, e1, e2, e3); -} - -static ERL_NIF_TERM enif_crypto_generichash_update(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - ErlNifBinary message; - - unsigned hashSize; - - void *state; - - // Validate the arguments - if ((argc != 3) || (!enif_get_uint(env, argv[0], &hashSize)) || - (!enif_get_resource(env, argv[1], generichash_state_type, - (void **)&state)) || - (!enif_inspect_binary(env, argv[2], &message))) { - return enif_make_badarg(env); - } - - // Verify that hash size is - // crypto_generichash_BYTES/crypto_generichash_BYTES_MIN/crypto_generichash_BYTES_MAX - if ((hashSize < crypto_generichash_BYTES_MIN) || - (hashSize > crypto_generichash_BYTES_MAX)) { - return nacl_error_tuple(env, "invalid_hash_size"); - } - - // Update hash state - if (0 != - crypto_generichash_update(align64(state), message.data, message.size)) { - return nacl_error_tuple(env, "hash_update_error"); - } - - // Generate return value - ERL_NIF_TERM e1 = enif_make_atom(env, "hashstate"); - ERL_NIF_TERM e2 = argv[0]; - ERL_NIF_TERM e3 = enif_make_resource(env, state); - - // return a tuple - return enif_make_tuple3(env, e1, e2, e3); -} - -static ERL_NIF_TERM enif_crypto_generichash_final(ErlNifEnv *env, int argc, - ERL_NIF_TERM const argv[]) { - ErlNifBinary hash; - - unsigned hashSize; - - void *state; - - // Validate the arguments - if ((argc != 2) || (!enif_get_uint(env, argv[0], &hashSize)) || - (!enif_get_resource(env, argv[1], generichash_state_type, - (void **)&state))) { - return enif_make_badarg(env); - } - - // Verify that hash size is - // crypto_generichash_BYTES/crypto_generichash_BYTES_MIN/crypto_generichash_BYTES_MAX - if ((hashSize < crypto_generichash_BYTES_MIN) || - (hashSize > crypto_generichash_BYTES_MAX)) { - return nacl_error_tuple(env, "invalid_hash_size"); - } - - // allocate memory for hash - if (!enif_alloc_binary(hashSize, &hash)) { - return nacl_error_tuple(env, "alloc_failed"); - } - - // calculate hash - if (0 != crypto_generichash_final(align64(state), hash.data, hash.size)) { - enif_release_binary(&hash); - return nacl_error_tuple(env, "hash_error"); - } - - ERL_NIF_TERM ok = enif_make_atom(env, ATOM_OK); - ERL_NIF_TERM ret = enif_make_binary(env, &hash); - - return enif_make_tuple2(env, ok, ret); -} - /* Tie the knot to the Erlang world */ static ErlNifFunc nif_funcs[] = { {"crypto_box_NONCEBYTES", 0, enif_crypto_box_NONCEBYTES}, @@ -2091,8 +1839,8 @@ static ErlNifFunc nif_funcs[] = { erl_nif_dirty_job_cpu_bound_macro("crypto_onetimeauth_verify", 3, enif_crypto_onetimeauth_verify), - {"crypto_hash_b", 1, enif_crypto_hash}, - erl_nif_dirty_job_cpu_bound_macro("crypto_hash", 1, enif_crypto_hash), + {"crypto_hash_b", 1, enacl_crypto_hash}, + erl_nif_dirty_job_cpu_bound_macro("crypto_hash", 1, enacl_crypto_hash), {"crypto_verify_16", 2, enif_crypto_verify_16}, {"crypto_verify_32", 2, enif_crypto_verify_32}, {"sodium_memzero", 1, enif_sodium_memzero}, @@ -2178,10 +1926,10 @@ static ErlNifFunc nif_funcs[] = { enif_crypto_generichash_KEYBYTES_MIN}, {"crypto_generichash_KEYBYTES_MAX", 0, enif_crypto_generichash_KEYBYTES_MAX}, - {"crypto_generichash", 3, enif_crypto_generichash}, - {"crypto_generichash_init", 2, enif_crypto_generichash_init}, - {"crypto_generichash_update", 3, enif_crypto_generichash_update}, - {"crypto_generichash_final", 2, enif_crypto_generichash_final} + {"crypto_generichash", 3, enacl_crypto_generichash}, + {"crypto_generichash_init", 2, enacl_crypto_generichash_init}, + {"crypto_generichash_update", 3, enacl_crypto_generichash_update}, + {"crypto_generichash_final", 2, enacl_crypto_generichash_final} }; diff --git a/c_src/generichash.c b/c_src/generichash.c new file mode 100644 index 0000000..8823adf --- /dev/null +++ b/c_src/generichash.c @@ -0,0 +1,295 @@ +#include "erl_nif.h" + +#include + +#include "enacl.h" +#include "generichash.h" + +typedef struct enacl_generichash_ctx { + // The hash state + crypto_generichash_state *ctx; + // Is the context alive? + int alive; +} enacl_generichash_ctx; + +static ErlNifResourceType *enacl_generic_hash_ctx_rtype; + +static void enacl_generic_hash_ctx_dtor(ErlNifEnv *env, + enacl_generichash_ctx *); + +int enacl_init_generic_hash_ctx(ErlNifEnv *env) { + enacl_generic_hash_ctx_rtype = + enif_open_resource_type(env, NULL, "enacl_generichash_context", + (ErlNifResourceDtor *)enacl_generic_hash_ctx_dtor, + ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER, NULL); + + if (enacl_generic_hash_ctx_rtype == NULL) + goto err; + + return 1; + +err: + return 0; +} + +static void enacl_generic_hash_ctx_dtor(ErlNifEnv *env, + enacl_generichash_ctx *obj) { + if (!obj->alive) { + return; + } + + sodium_free(obj->ctx); + return; +} + +/* + * Generic hash + */ +ERL_NIF_TERM enif_crypto_generichash_BYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + return enif_make_int64(env, crypto_generichash_BYTES); +} + +ERL_NIF_TERM enif_crypto_generichash_BYTES_MIN(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + return enif_make_int64(env, crypto_generichash_BYTES_MIN); +} + +ERL_NIF_TERM enif_crypto_generichash_BYTES_MAX(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + return enif_make_int64(env, crypto_generichash_BYTES_MAX); +} + +ERL_NIF_TERM enif_crypto_generichash_KEYBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + return enif_make_int64(env, crypto_generichash_KEYBYTES); +} + +ERL_NIF_TERM enif_crypto_generichash_KEYBYTES_MIN(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + return enif_make_int64(env, crypto_generichash_KEYBYTES_MIN); +} + +ERL_NIF_TERM enif_crypto_generichash_KEYBYTES_MAX(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + return enif_make_int64(env, crypto_generichash_KEYBYTES_MAX); +} + +ERL_NIF_TERM enacl_crypto_generichash(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ErlNifBinary hash, message, key; + unsigned hashSize; + ERL_NIF_TERM ret; + + // Validate the arguments + if ((argc != 3) || (!enif_get_uint(env, argv[0], &hashSize)) || + (!enif_inspect_binary(env, argv[1], &message)) || + (!enif_inspect_binary(env, argv[2], &key))) + goto bad_arg; + + // Verify that hash size is + // crypto_generichash_BYTES/crypto_generichash_BYTES_MIN/crypto_generichash_BYTES_MAX + if ((hashSize < crypto_generichash_BYTES_MIN) || + (hashSize > crypto_generichash_BYTES_MAX)) { + ret = nacl_error_tuple(env, "invalid_hash_size"); + goto done; + } + + // validate key size + unsigned char *k = key.data; + if (0 == key.size) { + k = NULL; + } else if (key.size < crypto_generichash_KEYBYTES_MIN || + key.size > crypto_generichash_KEYBYTES_MAX) { + ret = nacl_error_tuple(env, "invalid_key_size"); + goto done; + } + + // allocate memory for hash + if (!enif_alloc_binary(hashSize, &hash)) { + ret = nacl_error_tuple(env, "alloc_failed"); + goto done; + } + + // calculate hash + if (0 != crypto_generichash(hash.data, hash.size, message.data, message.size, + k, key.size)) { + ret = nacl_error_tuple(env, "hash_error"); + goto release; + } + + ERL_NIF_TERM ok = enif_make_atom(env, ATOM_OK); + ERL_NIF_TERM ret_hash = enif_make_binary(env, &hash); + + ret = enif_make_tuple2(env, ok, ret_hash); + goto done; + +bad_arg: + return enif_make_badarg(env); +release: + enif_release_binary(&hash); +done: + return ret; +} + +ERL_NIF_TERM enacl_crypto_generichash_init(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ErlNifBinary key; + unsigned hash_size; + enacl_generichash_ctx *obj = NULL; + ERL_NIF_TERM ret; + + // Validate the arguments + if ((argc != 2) || (!enif_get_uint(env, argv[0], &hash_size)) || + (!enif_inspect_binary(env, argv[1], &key))) { + goto bad_arg; + } + + // Verify that hash size is + // crypto_generichash_BYTES/crypto_generichash_BYTES_MIN/crypto_generichash_BYTES_MAX + if ((hash_size <= crypto_generichash_BYTES_MIN) || + (hash_size >= crypto_generichash_BYTES_MAX)) { + ret = nacl_error_tuple(env, "invalid_hash_size"); + goto done; + } + + // validate key size + unsigned char *k = key.data; + if (0 == key.size) { + k = NULL; + } else if (key.size <= crypto_generichash_KEYBYTES_MIN || + key.size >= crypto_generichash_KEYBYTES_MAX) { + ret = nacl_error_tuple(env, "invalid_key_size"); + goto done; + } + + // Create the resource + if ((obj = enif_alloc_resource(enacl_generic_hash_ctx_rtype, + sizeof(enacl_generichash_ctx))) == NULL) { + goto err; + } + + // Allocate the state context via libsodium + // Note that this ensures a 64byte alignment for the resource + // And also protects the resource via guardpages + obj->ctx = NULL; + obj->alive = 0; + obj->ctx = (crypto_generichash_state *)sodium_malloc( + crypto_generichash_statebytes()); + if (obj->ctx == NULL) { + goto err; + } + obj->alive = 1; + + // Call the library function + if (0 != crypto_generichash_init(obj->ctx, k, key.size, hash_size)) { + ret = nacl_error_tuple(env, "hash_init_error"); + goto done; + } + + // Create return values + ERL_NIF_TERM e1 = enif_make_atom(env, "hashstate"); + ERL_NIF_TERM e2 = argv[0]; + ERL_NIF_TERM e3 = enif_make_resource(env, obj); + + ret = enif_make_tuple3(env, e1, e2, e3); + goto done; +bad_arg: + return enif_make_badarg(env); + +err: + ret = nacl_error_tuple(env, "internal_error"); + if (obj != NULL) { + if (obj->alive) { + sodium_free(obj->ctx); + } + } +done: + if (obj != NULL) { + enif_release_resource(obj); + } + return ret; +} + +ERL_NIF_TERM enacl_crypto_generichash_update(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ERL_NIF_TERM ret; + ErlNifBinary data; + unsigned int data_size; + enacl_generichash_ctx *obj = NULL; + + // Validate the arguments + if (argc != 3) + goto bad_arg; + if (!enif_get_uint(env, argv[0], &data_size)) + goto bad_arg; + if (!enif_get_resource(env, argv[1], + (ErlNifResourceType *)enacl_generic_hash_ctx_rtype, + (void **)&obj)) + goto bad_arg; + if (!enif_inspect_binary(env, argv[2], &data)) + goto bad_arg; + + // Update hash state + if (0 != crypto_generichash_update(obj->ctx, data.data, data.size)) { + ret = nacl_error_tuple(env, "hash_update_error"); + goto done; + } + + ERL_NIF_TERM e1 = enif_make_atom(env, "hashstate"); + ERL_NIF_TERM e2 = argv[0]; + ERL_NIF_TERM e3 = argv[1]; + + ret = enif_make_tuple3(env, e1, e2, e3); + goto done; + +bad_arg: + return enif_make_badarg(env); +done: + return ret; +} + +ERL_NIF_TERM enacl_crypto_generichash_final(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ERL_NIF_TERM ret; + ErlNifBinary hash; + unsigned int hash_size; + enacl_generichash_ctx *obj = NULL; + + if (argc != 2) + goto bad_arg; + if (!enif_get_uint(env, argv[0], &hash_size)) + goto bad_arg; + if (!enif_get_resource(env, argv[1], enacl_generic_hash_ctx_rtype, + (void **)&obj)) + goto bad_arg; + + if ((hash_size <= crypto_generichash_BYTES_MIN) || + (hash_size >= crypto_generichash_BYTES_MAX)) { + ret = nacl_error_tuple(env, "invalid_hash_size"); + goto done; + } + + if (!enif_alloc_binary(hash_size, &hash)) { + ret = nacl_error_tuple(env, "alloc_failed"); + goto done; + } + + if (0 != crypto_generichash_final(obj->ctx, hash.data, hash.size)) { + ret = nacl_error_tuple(env, "hash_error"); + goto release; + } + + ERL_NIF_TERM ok = enif_make_atom(env, ATOM_OK); + ERL_NIF_TERM h = enif_make_binary(env, &hash); + + ret = enif_make_tuple2(env, ok, h); + goto done; + +bad_arg: + return enif_make_badarg(env); +release: + enif_release_binary(&hash); +done: + return ret; +} diff --git a/c_src/generichash.h b/c_src/generichash.h new file mode 100644 index 0000000..a348893 --- /dev/null +++ b/c_src/generichash.h @@ -0,0 +1,30 @@ +#ifndef ENACL_GENERICHASH_H +#define ENACL_GENERICHASH_H + +int enacl_init_generic_hash_ctx(ErlNifEnv *env); + +ERL_NIF_TERM enif_crypto_generichash_BYTES(ErlNifEnv *env, int argc, + const ERL_NIF_TERM argv[]); +ERL_NIF_TERM enif_crypto_generichash_BYTES_MIN(ErlNifEnv *env, int argc, + const ERL_NIF_TERM argv[]); +ERL_NIF_TERM enif_crypto_generichash_BYTES_MAX(ErlNifEnv *env, int argc, + const ERL_NIF_TERM argv[]); + +ERL_NIF_TERM enif_crypto_generichash_KEYBYTES(ErlNifEnv *env, int argc, + const ERL_NIF_TERM argv[]); +ERL_NIF_TERM enif_crypto_generichash_KEYBYTES_MIN(ErlNifEnv *env, int argc, + const ERL_NIF_TERM argv[]); +ERL_NIF_TERM enif_crypto_generichash_KEYBYTES_MAX(ErlNifEnv *env, int argc, + const ERL_NIF_TERM argv[]); + +ERL_NIF_TERM enacl_crypto_generichash(ErlNifEnv *env, int argc, + const ERL_NIF_TERM argv[]); + +ERL_NIF_TERM enacl_crypto_generichash_init(ErlNifEnv *env, int argc, + const ERL_NIF_TERM argv[]); +ERL_NIF_TERM enacl_crypto_generichash_update(ErlNifEnv *env, int argc, + const ERL_NIF_TERM argv[]); +ERL_NIF_TERM enacl_crypto_generichash_final(ErlNifEnv *env, int argc, + const ERL_NIF_TERM argv[]); + +#endif \ No newline at end of file diff --git a/c_src/hash.c b/c_src/hash.c new file mode 100644 index 0000000..5f9be56 --- /dev/null +++ b/c_src/hash.c @@ -0,0 +1,30 @@ +#include "erl_nif.h" + +#include + +#include "hash.h" + +ERL_NIF_TERM enacl_crypto_hash_nif(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ErlNifBinary input; + ErlNifBinary result; + ERL_NIF_TERM ret; + + if ((argc != 1) || (!enif_inspect_iolist_as_binary(env, argv[0], &input))) + goto bad_arg; + + if (!enif_alloc_binary(crypto_hash_BYTES, &result)) + goto err; + + crypto_hash(result.data, input.data, input.size); + ret = enif_make_binary(env, &result); + goto done; + +bad_arg: + return enif_make_badarg(env); + +err: + ret = nacl_error_tuple(env, "alloc_failed"); +done: + return ret; +} diff --git a/c_src/hash.h b/c_src/hash.h new file mode 100644 index 0000000..7ade398 --- /dev/null +++ b/c_src/hash.h @@ -0,0 +1,6 @@ +#ifndef ENACL_HASH_H +#define ENACL_HASH_H + +ERL_NIF_TERM enacl_crypto_hash(ErlNifEnv *env, int argc, + const ERL_NIF_TERM argv[]); +#endif \ No newline at end of file