Add support for multi-part signatures
This commit is contained in:
parent
885662c069
commit
279c2c32c8
@ -10,6 +10,7 @@
|
||||
#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
|
||||
#define erl_nif_dirty_job_cpu_bound_macro(a,b,c) {a,b,c,ERL_NIF_DIRTY_JOB_CPU_BOUND}
|
||||
@ -20,8 +21,9 @@
|
||||
//{"crypto_box_keypair", 0, enif_crypto_box_keypair, ERL_NIF_DIRTY_JOB_CPU_BOUND}
|
||||
/* Errors */
|
||||
|
||||
/* This is a global variable for resource type */
|
||||
/* 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) {
|
||||
@ -35,6 +37,10 @@ int enif_crypto_load(ErlNifEnv *env, void **priv_data, ERL_NIF_TERM load_info) {
|
||||
if( !(generichash_state_type = enif_open_resource_type(env, NULL, CRYPTO_GENERICHASH_STATE_RESOURCE, NULL, ERL_NIF_RT_CREATE, NULL)) ) {
|
||||
return -1;
|
||||
}
|
||||
// Create a new resource type for crypto_sign_state
|
||||
if( !(sign_state_type = enif_open_resource_type(env, NULL, CRYPTO_SIGN_STATE_RESOURCE, NULL, ERL_NIF_RT_CREATE, NULL)) ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return sodium_init();
|
||||
}
|
||||
@ -620,6 +626,139 @@ ERL_NIF_TERM enif_crypto_sign_verify_detached(ErlNifEnv* env, int argc, ERL_NIF_
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
int crypto_sign_init(crypto_sign_state *state)
|
||||
*/
|
||||
|
||||
static
|
||||
ERL_NIF_TERM enif_crypto_sign_init(ErlNifEnv* env, int argc, ERL_NIF_TERM const argv[]) {
|
||||
if( (argc != 0) ) {
|
||||
return enif_make_badarg(env);
|
||||
}
|
||||
|
||||
void* state = enif_alloc_resource(sign_state_type, crypto_sign_statebytes());
|
||||
|
||||
if( !state ) {
|
||||
return nacl_error_tuple(env, "alloc_failed");
|
||||
}
|
||||
|
||||
if( 0 != crypto_sign_init(state) ) {
|
||||
return nacl_error_tuple(env, "sign_init_error");
|
||||
}
|
||||
|
||||
// Create return values
|
||||
ERL_NIF_TERM e1 = enif_make_atom(env, "signstate");
|
||||
ERL_NIF_TERM e2 = enif_make_resource(env, state);
|
||||
|
||||
// release dynamically allocated memory to erlang to mange
|
||||
enif_release_resource(state);
|
||||
|
||||
// return a tuple
|
||||
return enif_make_tuple2(env, e1, e2);
|
||||
}
|
||||
|
||||
/*
|
||||
int crypto_sign_update(crypto_sign_state *state,
|
||||
const unsigned char *m,
|
||||
unsigned long long mlen);
|
||||
*/
|
||||
|
||||
static
|
||||
ERL_NIF_TERM enif_crypto_sign_update(ErlNifEnv* env, int argc, ERL_NIF_TERM const argv[]) {
|
||||
ErlNifBinary data;
|
||||
|
||||
void *state;
|
||||
|
||||
// Validate the arguments
|
||||
if( (argc != 2) ||
|
||||
(!enif_get_resource(env, argv[0], sign_state_type, (void **)&state)) ||
|
||||
(!enif_inspect_binary(env, argv[1], &data)) ) {
|
||||
return enif_make_badarg(env);
|
||||
}
|
||||
|
||||
if( 0 != crypto_sign_update(state, data.data, data.size) ) {
|
||||
return nacl_error_tuple(env, "sign_update_error");
|
||||
}
|
||||
|
||||
// Generate return value
|
||||
ERL_NIF_TERM e1 = enif_make_atom(env, "signstate");
|
||||
ERL_NIF_TERM e2 = enif_make_resource(env, state);
|
||||
|
||||
// return a tuple
|
||||
return enif_make_tuple2(env, e1, e2);
|
||||
}
|
||||
|
||||
/*
|
||||
int crypto_sign_final_create(crypto_sign_state *state,
|
||||
unsigned char *sig,
|
||||
unsigned long long *siglen_p,
|
||||
const unsigned char *sk);
|
||||
*/
|
||||
|
||||
static
|
||||
ERL_NIF_TERM enif_crypto_sign_final_create(ErlNifEnv* env, int argc, ERL_NIF_TERM const argv[]) {
|
||||
ErlNifBinary sk, sig;
|
||||
|
||||
void *state;
|
||||
|
||||
unsigned long long siglen;
|
||||
|
||||
if( (argc != 2) ||
|
||||
(!enif_get_resource(env, argv[0], sign_state_type, (void **)&state)) ||
|
||||
(!enif_inspect_binary(env, argv[1], &sk)) ) {
|
||||
return enif_make_badarg(env);
|
||||
}
|
||||
|
||||
if( sk.size != crypto_sign_SECRETKEYBYTES ) {
|
||||
return enif_make_badarg(env);
|
||||
}
|
||||
|
||||
if( !enif_alloc_binary(crypto_sign_BYTES, &sig) ) {
|
||||
return nacl_error_tuple(env, "alloc_failed");
|
||||
}
|
||||
|
||||
if( 0 != crypto_sign_final_create(state, sig.data, &siglen, sk.data) ) {
|
||||
enif_release_binary(&sig);
|
||||
return nacl_error_tuple(env, "sign_error");
|
||||
}
|
||||
|
||||
ERL_NIF_TERM ok = enif_make_atom(env, ATOM_OK);
|
||||
ERL_NIF_TERM ret = enif_make_binary(env, &sig);
|
||||
|
||||
return enif_make_tuple2(env, ok, ret);
|
||||
}
|
||||
|
||||
/*
|
||||
int crypto_sign_final_verify(crypto_sign_state *state,
|
||||
unsigned char *sig,
|
||||
const unsigned char *pk);
|
||||
*/
|
||||
|
||||
static
|
||||
ERL_NIF_TERM enif_crypto_sign_final_verify(ErlNifEnv* env, int argc, ERL_NIF_TERM const argv[]) {
|
||||
ErlNifBinary pk, sig;
|
||||
|
||||
void *state;
|
||||
|
||||
if( (argc != 3) ||
|
||||
(!enif_get_resource(env, argv[0], sign_state_type, (void **)&state)) ||
|
||||
(!enif_inspect_binary(env, argv[1], &sig)) ||
|
||||
(!enif_inspect_binary(env, argv[2], &pk)) ) {
|
||||
return enif_make_badarg(env);
|
||||
}
|
||||
|
||||
if( pk.size != crypto_sign_PUBLICKEYBYTES ) {
|
||||
return enif_make_badarg(env);
|
||||
}
|
||||
|
||||
if( 0 == crypto_sign_final_verify(state, sig.data, pk.data) ) {
|
||||
return enif_make_atom(env, ATOM_OK);
|
||||
}
|
||||
|
||||
return nacl_error_tuple(env, "failed_verification");
|
||||
}
|
||||
|
||||
|
||||
/* Sealed box functions */
|
||||
|
||||
static
|
||||
@ -1675,6 +1814,11 @@ static ErlNifFunc nif_funcs[] = {
|
||||
erl_nif_dirty_job_cpu_bound_macro("crypto_sign_detached", 2, enif_crypto_sign_detached),
|
||||
erl_nif_dirty_job_cpu_bound_macro("crypto_sign_verify_detached", 3, enif_crypto_sign_verify_detached),
|
||||
|
||||
{"crypto_sign_init", 0, enif_crypto_sign_init},
|
||||
{"crypto_sign_update", 2, enif_crypto_sign_update},
|
||||
erl_nif_dirty_job_cpu_bound_macro("crypto_sign_final_create", 2, enif_crypto_sign_final_create),
|
||||
erl_nif_dirty_job_cpu_bound_macro("crypto_sign_final_verify", 3, enif_crypto_sign_final_verify),
|
||||
|
||||
{"crypto_box_SEALBYTES", 0, enif_crypto_box_SEALBYTES},
|
||||
|
||||
erl_nif_dirty_job_cpu_bound_macro("crypto_box_seal", 2, enif_crypto_box_seal),
|
||||
|
@ -39,6 +39,11 @@
|
||||
sign_detached/2,
|
||||
sign_verify_detached/3,
|
||||
|
||||
sign_init/0,
|
||||
sign_update/2,
|
||||
sign_final_create/2,
|
||||
sign_final_verify/3,
|
||||
|
||||
%% EQC
|
||||
box_seal/2,
|
||||
box_seal_open/3
|
||||
@ -579,6 +584,47 @@ sign_verify_detached(SIG, M, PK) ->
|
||||
false -> {error, failed_verification}
|
||||
end.
|
||||
|
||||
-type sign_state() :: {signstate, reference()}.
|
||||
|
||||
%% @doc sign_init/0 initialize a multi-part signature state.
|
||||
%%
|
||||
%% This state must be passed to all future calls to `sign_update/2`,
|
||||
%% `sign_final_create/2` and `sign_final_verify/3`.
|
||||
%% @end
|
||||
-spec sign_init() -> sign_state().
|
||||
sign_init() ->
|
||||
enacl_nif:crypto_sign_init().
|
||||
|
||||
%% @doc sign_update/2 update the signature state `S` with a new chunk of data `M`.
|
||||
%% @end
|
||||
-spec sign_update(S, M) -> sign_state() | {error, sign_update_error}
|
||||
when S :: sign_state(),
|
||||
M :: iodata().
|
||||
sign_update({signstate, SignState}, M) ->
|
||||
enacl_nif:crypto_sign_update(SignState, M).
|
||||
|
||||
|
||||
%% @doc sign_final_create/2 computes the signature for the previously supplied
|
||||
%% message(s) using the secret key `SK`.
|
||||
%% @end
|
||||
-spec sign_final_create(S, SK) -> {ok, binary()} | {error, atom()}
|
||||
when S :: sign_state(),
|
||||
SK :: iodata().
|
||||
sign_final_create({signstate, SignState}, SK) ->
|
||||
enacl_nif:crypto_sign_final_create(SignState, SK).
|
||||
|
||||
%% @doc sign_final_verify/3 verify a chunked signature
|
||||
%%
|
||||
%% Verifies that `SIG` is a valid signature for the message whose content has
|
||||
%% been previously supplied using `sign_update/2` using the public key `PK.`
|
||||
%% @end
|
||||
-spec sign_final_verify(S, SIG, PK) -> ok | {error, failed_verification}
|
||||
when S :: sign_state(),
|
||||
SIG :: binary(),
|
||||
PK :: iodata().
|
||||
sign_final_verify({signstate, SignState}, SIG, PK) ->
|
||||
enacl_nif:crypto_sign_final_verify(SignState, SIG, PK).
|
||||
|
||||
%% @private
|
||||
-spec box_secret_key_bytes() -> pos_integer().
|
||||
box_secret_key_bytes() ->
|
||||
|
@ -34,6 +34,11 @@
|
||||
crypto_sign_detached/2,
|
||||
crypto_sign_verify_detached/3,
|
||||
|
||||
crypto_sign_init/0,
|
||||
crypto_sign_update/2,
|
||||
crypto_sign_final_create/2,
|
||||
crypto_sign_final_verify/3,
|
||||
|
||||
crypto_box_seal/2,
|
||||
crypto_box_seal_open/3,
|
||||
crypto_box_SEALBYTES/0
|
||||
@ -220,6 +225,11 @@ crypto_sign_detached(_M, _SK) -> erlang:nif_error(nif_not_loaded).
|
||||
|
||||
crypto_sign_verify_detached(_Sig, _M, _PK) -> erlang:nif_error(nif_not_loaded).
|
||||
|
||||
crypto_sign_init() -> erlang:nif_error(nif_not_loaded).
|
||||
crypto_sign_update(_S, _M) -> erlang:nif_error(nif_not_loaded).
|
||||
crypto_sign_final_create(_S, _SK) -> erlang:nif_error(nif_not_loaded).
|
||||
crypto_sign_final_verify(_S, _S, _PK) -> erlang:nif_error(nif_not_loaded).
|
||||
|
||||
crypto_box_seal(_Msg, _PK) -> erlang:nif_error(nif_not_loaded).
|
||||
crypto_box_seal_open(_CipherText, _PK, _SK) -> erlang:nif_error(nif_not_loaded).
|
||||
crypto_box_SEALBYTES() -> erlang:nif_error(nif_not_loaded).
|
||||
|
Loading…
x
Reference in New Issue
Block a user