Start splitting the library into its parts
This commit is contained in:
parent
a25b9a2684
commit
d5bb24e671
3
.gitignore
vendored
3
.gitignore
vendored
@ -15,4 +15,5 @@ _build
|
|||||||
priv/enacl_nif.dll
|
priv/enacl_nif.dll
|
||||||
priv/enacl_nif.exp
|
priv/enacl_nif.exp
|
||||||
priv/enacl_nif.lib
|
priv/enacl_nif.lib
|
||||||
c_src/enacl_nif.d
|
c_src/*.d
|
||||||
|
|
||||||
|
7
c_src/enacl.c
Normal file
7
c_src/enacl.c
Normal file
@ -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));
|
||||||
|
}
|
13
c_src/enacl.h
Normal file
13
c_src/enacl.h
Normal file
@ -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
|
@ -1,15 +1,11 @@
|
|||||||
#include "erl_nif.h"
|
#include "erl_nif.h"
|
||||||
|
|
||||||
|
#include <sodium.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <sodium.h>
|
#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"
|
#define CRYPTO_SIGN_STATE_RESOURCE "crypto_sign_state"
|
||||||
|
|
||||||
#ifdef ERL_NIF_DIRTY_JOB_CPU_BOUND
|
#ifdef ERL_NIF_DIRTY_JOB_CPU_BOUND
|
||||||
@ -25,21 +21,13 @@
|
|||||||
/* Errors */
|
/* Errors */
|
||||||
|
|
||||||
/* These are global variables for resource types */
|
/* These are global variables for resource types */
|
||||||
static ErlNifResourceType *generichash_state_type = NULL;
|
|
||||||
static ErlNifResourceType *sign_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 */
|
/* Initialization */
|
||||||
static int enif_crypto_load(ErlNifEnv *env, void **priv_data,
|
static int enif_crypto_load(ErlNifEnv *env, void **priv_data,
|
||||||
ERL_NIF_TERM load_info) {
|
ERL_NIF_TERM load_info) {
|
||||||
// Create a new resource type for crypto_generichash_state
|
// Create a new resource type for crypto_generichash_state
|
||||||
if (!(generichash_state_type = enif_open_resource_type(
|
if (!enacl_init_generic_hash_ctx(env)) {
|
||||||
env, NULL, CRYPTO_GENERICHASH_STATE_RESOURCE, NULL,
|
|
||||||
ERL_NIF_RT_CREATE, NULL))) {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
// Create a new resource type for crypto_sign_state
|
// 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();
|
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,
|
static ERL_NIF_TERM enif_crypto_verify_16(ErlNifEnv *env, int argc,
|
||||||
ERL_NIF_TERM const argv[]) {
|
ERL_NIF_TERM const argv[]) {
|
||||||
ErlNifBinary x, y;
|
ErlNifBinary x, y;
|
||||||
@ -1764,227 +1733,6 @@ enif_crypto_aead_xchacha20poly1305_decrypt(ErlNifEnv *env, int argc,
|
|||||||
return enif_make_binary(env, &message);
|
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 */
|
/* Tie the knot to the Erlang world */
|
||||||
static ErlNifFunc nif_funcs[] = {
|
static ErlNifFunc nif_funcs[] = {
|
||||||
{"crypto_box_NONCEBYTES", 0, enif_crypto_box_NONCEBYTES},
|
{"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,
|
erl_nif_dirty_job_cpu_bound_macro("crypto_onetimeauth_verify", 3,
|
||||||
enif_crypto_onetimeauth_verify),
|
enif_crypto_onetimeauth_verify),
|
||||||
|
|
||||||
{"crypto_hash_b", 1, enif_crypto_hash},
|
{"crypto_hash_b", 1, enacl_crypto_hash},
|
||||||
erl_nif_dirty_job_cpu_bound_macro("crypto_hash", 1, enif_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_16", 2, enif_crypto_verify_16},
|
||||||
{"crypto_verify_32", 2, enif_crypto_verify_32},
|
{"crypto_verify_32", 2, enif_crypto_verify_32},
|
||||||
{"sodium_memzero", 1, enif_sodium_memzero},
|
{"sodium_memzero", 1, enif_sodium_memzero},
|
||||||
@ -2178,10 +1926,10 @@ static ErlNifFunc nif_funcs[] = {
|
|||||||
enif_crypto_generichash_KEYBYTES_MIN},
|
enif_crypto_generichash_KEYBYTES_MIN},
|
||||||
{"crypto_generichash_KEYBYTES_MAX", 0,
|
{"crypto_generichash_KEYBYTES_MAX", 0,
|
||||||
enif_crypto_generichash_KEYBYTES_MAX},
|
enif_crypto_generichash_KEYBYTES_MAX},
|
||||||
{"crypto_generichash", 3, enif_crypto_generichash},
|
{"crypto_generichash", 3, enacl_crypto_generichash},
|
||||||
{"crypto_generichash_init", 2, enif_crypto_generichash_init},
|
{"crypto_generichash_init", 2, enacl_crypto_generichash_init},
|
||||||
{"crypto_generichash_update", 3, enif_crypto_generichash_update},
|
{"crypto_generichash_update", 3, enacl_crypto_generichash_update},
|
||||||
{"crypto_generichash_final", 2, enif_crypto_generichash_final}
|
{"crypto_generichash_final", 2, enacl_crypto_generichash_final}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
295
c_src/generichash.c
Normal file
295
c_src/generichash.c
Normal file
@ -0,0 +1,295 @@
|
|||||||
|
#include "erl_nif.h"
|
||||||
|
|
||||||
|
#include <sodium.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
30
c_src/generichash.h
Normal file
30
c_src/generichash.h
Normal file
@ -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
|
30
c_src/hash.c
Normal file
30
c_src/hash.c
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#include "erl_nif.h"
|
||||||
|
|
||||||
|
#include <sodium.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
6
c_src/hash.h
Normal file
6
c_src/hash.h
Normal file
@ -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
|
Loading…
x
Reference in New Issue
Block a user