Packages

FIPS-202 compliant SHA-3 hash function NIF

Current section

Files

Jump to
sha3 c_src sha3_nifs.c
Raw

c_src/sha3_nifs.c

#include "erl_nif.h"
#include "erl_nif_compat.h"
#include "KeccakNISTInterface.h"
static ErlNifResourceType* keccak_hashstate;
typedef struct
{
} keccak_handle;
// Prototypes
ERL_NIF_TERM keccak_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM keccak_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM keccak_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM keccak_hash(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
// lifecycle
int load(ErlNifEnv* env, void ** priv_data, ERL_NIF_TERM load_info);
int reload(ErlNifEnv* env, void** priv, ERL_NIF_TERM load_info);
int upgrade(ErlNifEnv* env, void** priv, void** old_priv, ERL_NIF_TERM load_info);
void unload(ErlNifEnv* env, void* priv);
static ErlNifFunc nif_funcs[] =
{
{"init", 1, keccak_init},
{"update", 3, keccak_update},
{"final", 1, keccak_final},
{"hash", 3, keccak_hash}
};
ERL_NIF_INIT(sha3, nif_funcs, load, NULL, NULL, NULL);
static char *hash_return_strings[] = {"success", "fail", "bad_hashlen"};
int valid_length(int bits, int bufbytes)
{
int numbytes = bits / 8;
if (bits % 8 > 0)
{
numbytes++;
}
if (numbytes <= bufbytes)
{
return 0;
}
return -1;
}
int load(ErlNifEnv* env, void ** priv_data, ERL_NIF_TERM load_info)
{
keccak_hashstate = enif_open_resource_type_compat(env, "hashstate", NULL, ERL_NIF_RT_CREATE, NULL);
return 0;
}
int reload(ErlNifEnv* env, void** priv, ERL_NIF_TERM load_info)
{
return 0;
}
int upgrade(ErlNifEnv* env, void** priv, void** old_priv, ERL_NIF_TERM load_info)
{
return 0;
}
void unload(ErlNifEnv* env, void* priv)
{
return;
}
ERL_NIF_TERM keccak_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ERL_NIF_TERM hash_state_term;
int bits = 0;
if(!enif_get_int(env, argv[0], &bits))
return enif_make_badarg(env);
hashState *state = (hashState*) enif_alloc_resource_compat(env, keccak_hashstate, sizeof(hashState));
HashReturn r = Init(state, bits);
if (r == SUCCESS) {
hash_state_term = enif_make_resource(env, state);
enif_release_resource_compat(env, state);
return enif_make_tuple2(env, enif_make_atom(env, "ok"), hash_state_term);
} else {
enif_release_resource_compat(env, state);
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, hash_return_strings[r]));
}
}
ERL_NIF_TERM keccak_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
hashState *state = NULL;
enif_get_resource(env, argv[0], keccak_hashstate, (void**)&state);
ErlNifBinary bin;
enif_inspect_binary(env, argv[1], &bin);
int bitlength = 0;
if(!enif_get_int(env, argv[2], &bitlength))
return enif_make_badarg(env);
if (valid_length(bitlength, bin.size) < 0)
{
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, "invalid_length"));
}
HashReturn r = Update(state, (BitSequence *)(bin.data), bitlength);
if (r == SUCCESS)
{
return enif_make_tuple2(env, enif_make_atom(env, "ok"), enif_make_resource(env, state));
} else {
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, hash_return_strings[r]));
}
}
ERL_NIF_TERM keccak_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
hashState *state = NULL;
enif_get_resource(env, argv[0], keccak_hashstate, (void**)&state);
ErlNifBinary out;
enif_alloc_binary_compat(env, (size_t)(state->fixedOutputLength/8), &out);
HashReturn r = Final(state, (BitSequence *)out.data);
if (r == SUCCESS) {
return enif_make_tuple2(env, enif_make_atom(env, "ok"), enif_make_binary(env, &out));
} else {
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, hash_return_strings[r]));
}
}
ERL_NIF_TERM keccak_hash(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
int bits = 0;
enif_get_int(env, argv[0], &bits);
ErlNifBinary bin, out;
enif_inspect_binary(env, argv[1], &bin);
enif_alloc_binary_compat(env, (size_t)(bits/8), &out);
int bitlength = 0;
if(!enif_get_int(env, argv[2], &bitlength))
return enif_make_badarg(env);
if (valid_length(bitlength, bin.size) < 0)
{
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, "invalid_length"));
}
HashReturn r = Hash(bits, (BitSequence *)(bin.data), bitlength, (BitSequence *)out.data);
if (r == SUCCESS) {
return enif_make_tuple2(env, enif_make_atom(env, "ok"), enif_make_binary(env, &out));
} else {
return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, hash_return_strings[r]));
}
}