Streamline generichash and pwhash
This commit is contained in:
parent
59b94439d1
commit
b637ba307b
@ -10,18 +10,18 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|||||||
- Go through all calls and make them return streamlined exceptions if applicable.
|
- Go through all calls and make them return streamlined exceptions if applicable.
|
||||||
Pretty large change, but OTOH, this ought to happen before a 1.0 release as well.
|
Pretty large change, but OTOH, this ought to happen before a 1.0 release as well.
|
||||||
- AEAD
|
- AEAD
|
||||||
- enacl
|
|
||||||
- hash
|
- hash
|
||||||
- kx
|
- kx
|
||||||
- generichash
|
|
||||||
- pwhash
|
|
||||||
- randombytes
|
- randombytes
|
||||||
- secret
|
- secret
|
||||||
- sign
|
- sign
|
||||||
|
- enacl_nif
|
||||||
|
|
||||||
- Implement missing EQC tests
|
- Implement missing EQC tests
|
||||||
- Generichash
|
- Generichash
|
||||||
- Multi-part generic hash
|
- Multi-part generic hash
|
||||||
|
- pwhash
|
||||||
|
- Extend with limit for ops and memory as well.
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
@ -98,8 +98,7 @@ ERL_NIF_TERM enacl_crypto_generichash(ErlNifEnv *env, int argc,
|
|||||||
// crypto_generichash_BYTES/crypto_generichash_BYTES_MIN/crypto_generichash_BYTES_MAX
|
// crypto_generichash_BYTES/crypto_generichash_BYTES_MIN/crypto_generichash_BYTES_MAX
|
||||||
if ((hash_size <= crypto_generichash_BYTES_MIN) ||
|
if ((hash_size <= crypto_generichash_BYTES_MIN) ||
|
||||||
(hash_size >= crypto_generichash_BYTES_MAX)) {
|
(hash_size >= crypto_generichash_BYTES_MAX)) {
|
||||||
ret = enacl_error_tuple(env, "invalid_hash_size");
|
goto bad_arg;
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate key size
|
// validate key size
|
||||||
@ -108,33 +107,29 @@ ERL_NIF_TERM enacl_crypto_generichash(ErlNifEnv *env, int argc,
|
|||||||
k = NULL;
|
k = NULL;
|
||||||
} else if (key.size <= crypto_generichash_KEYBYTES_MIN ||
|
} else if (key.size <= crypto_generichash_KEYBYTES_MIN ||
|
||||||
key.size >= crypto_generichash_KEYBYTES_MAX) {
|
key.size >= crypto_generichash_KEYBYTES_MAX) {
|
||||||
ret = enacl_error_tuple(env, "invalid_key_size");
|
goto bad_arg;
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// allocate memory for hash
|
// allocate memory for hash
|
||||||
if (!enif_alloc_binary(hash_size, &hash)) {
|
if (!enif_alloc_binary(hash_size, &hash)) {
|
||||||
ret = enacl_error_tuple(env, "alloc_failed");
|
goto err;
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate hash
|
// calculate hash
|
||||||
if (0 != crypto_generichash(hash.data, hash.size, message.data, message.size,
|
if (0 != crypto_generichash(hash.data, hash.size, message.data, message.size,
|
||||||
k, key.size)) {
|
k, key.size)) {
|
||||||
ret = enacl_error_tuple(env, "hash_error");
|
|
||||||
goto release;
|
goto release;
|
||||||
}
|
}
|
||||||
|
|
||||||
ERL_NIF_TERM ok = enif_make_atom(env, ATOM_OK);
|
ret = enif_make_binary(env, &hash);
|
||||||
ERL_NIF_TERM ret_hash = enif_make_binary(env, &hash);
|
|
||||||
|
|
||||||
ret = enif_make_tuple2(env, ok, ret_hash);
|
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
bad_arg:
|
bad_arg:
|
||||||
return enif_make_badarg(env);
|
return enif_make_badarg(env);
|
||||||
release:
|
release:
|
||||||
enif_release_binary(&hash);
|
enif_release_binary(&hash);
|
||||||
|
err:
|
||||||
|
ret = enacl_internal_error(env);
|
||||||
done:
|
done:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -208,7 +203,7 @@ ERL_NIF_TERM enacl_crypto_generichash_init(ErlNifEnv *env, int argc,
|
|||||||
bad_arg:
|
bad_arg:
|
||||||
return enif_make_badarg(env);
|
return enif_make_badarg(env);
|
||||||
err:
|
err:
|
||||||
ret = enif_make_atom(env, "notsup");
|
ret = enacl_internal_error(env);
|
||||||
if (obj != NULL) {
|
if (obj != NULL) {
|
||||||
if (obj->alive) {
|
if (obj->alive) {
|
||||||
sodium_free(obj->ctx);
|
sodium_free(obj->ctx);
|
||||||
@ -256,7 +251,7 @@ ERL_NIF_TERM enacl_crypto_generichash_update(ErlNifEnv *env, int argc,
|
|||||||
bad_arg:
|
bad_arg:
|
||||||
return enif_make_badarg(env);
|
return enif_make_badarg(env);
|
||||||
err:
|
err:
|
||||||
ret = enif_make_badarg(env);
|
ret = enacl_internal_error(env);
|
||||||
done:
|
done:
|
||||||
enif_mutex_unlock(obj->mtx);
|
enif_mutex_unlock(obj->mtx);
|
||||||
return ret;
|
return ret;
|
||||||
@ -276,11 +271,11 @@ ERL_NIF_TERM enacl_crypto_generichash_final(ErlNifEnv *env, int argc,
|
|||||||
|
|
||||||
enif_mutex_lock(obj->mtx);
|
enif_mutex_lock(obj->mtx);
|
||||||
if (!obj->alive) {
|
if (!obj->alive) {
|
||||||
goto err;
|
goto bad_arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!enif_alloc_binary(obj->outlen, &hash)) {
|
if (!enif_alloc_binary(obj->outlen, &hash)) {
|
||||||
goto done;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 != crypto_generichash_final(obj->ctx, hash.data, hash.size)) {
|
if (0 != crypto_generichash_final(obj->ctx, hash.data, hash.size)) {
|
||||||
@ -292,18 +287,15 @@ ERL_NIF_TERM enacl_crypto_generichash_final(ErlNifEnv *env, int argc,
|
|||||||
sodium_free(obj->ctx);
|
sodium_free(obj->ctx);
|
||||||
obj->alive = 0;
|
obj->alive = 0;
|
||||||
|
|
||||||
ERL_NIF_TERM ok = enif_make_atom(env, ATOM_OK);
|
ret = enif_make_binary(env, &hash);
|
||||||
ERL_NIF_TERM h = enif_make_binary(env, &hash);
|
|
||||||
|
|
||||||
ret = enif_make_tuple2(env, ok, h);
|
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
bad_arg:
|
bad_arg:
|
||||||
return enif_make_badarg(env);
|
return enif_make_badarg(env);
|
||||||
err:
|
|
||||||
ret = enif_make_badarg(env);
|
|
||||||
release:
|
release:
|
||||||
enif_release_binary(&hash);
|
enif_release_binary(&hash);
|
||||||
|
err:
|
||||||
|
ret = enif_make_badarg(env);
|
||||||
done:
|
done:
|
||||||
enif_mutex_unlock(obj->mtx);
|
enif_mutex_unlock(obj->mtx);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -78,25 +78,22 @@ ERL_NIF_TERM enacl_crypto_pwhash(ErlNifEnv *env, int argc,
|
|||||||
|
|
||||||
// Check Salt size
|
// Check Salt size
|
||||||
if (s.size != crypto_pwhash_SALTBYTES) {
|
if (s.size != crypto_pwhash_SALTBYTES) {
|
||||||
return enacl_error_tuple(env, "invalid_salt_size");
|
return enif_make_badarg(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate memory for return binary
|
// Allocate memory for return binary
|
||||||
if (!enif_alloc_binary(crypto_box_SEEDBYTES, &h)) {
|
if (!enif_alloc_binary(crypto_box_SEEDBYTES, &h)) {
|
||||||
return enacl_error_tuple(env, "alloc_failed");
|
return enacl_internal_error(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (crypto_pwhash(h.data, h.size, (char *)p.data, p.size, s.data, o, m,
|
if (crypto_pwhash(h.data, h.size, (char *)p.data, p.size, s.data, o, m,
|
||||||
crypto_pwhash_ALG_DEFAULT) != 0) {
|
crypto_pwhash_ALG_DEFAULT) != 0) {
|
||||||
/* out of memory */
|
/* out of memory */
|
||||||
enif_release_binary(&h);
|
enif_release_binary(&h);
|
||||||
return enacl_error_tuple(env, "out_of_memory");
|
return enacl_internal_error(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
ERL_NIF_TERM ok = enif_make_atom(env, ATOM_OK);
|
return enif_make_binary(env, &h);
|
||||||
ERL_NIF_TERM ret = enif_make_binary(env, &h);
|
|
||||||
|
|
||||||
return enif_make_tuple2(env, ok, ret);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ERL_NIF_TERM enacl_crypto_pwhash_str(ErlNifEnv *env, int argc,
|
ERL_NIF_TERM enacl_crypto_pwhash_str(ErlNifEnv *env, int argc,
|
||||||
@ -119,19 +116,16 @@ ERL_NIF_TERM enacl_crypto_pwhash_str(ErlNifEnv *env, int argc,
|
|||||||
|
|
||||||
// Allocate memory for return binary
|
// Allocate memory for return binary
|
||||||
if (!enif_alloc_binary(crypto_pwhash_STRBYTES, &h)) {
|
if (!enif_alloc_binary(crypto_pwhash_STRBYTES, &h)) {
|
||||||
return enacl_error_tuple(env, "alloc_failed");
|
return enacl_internal_error(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (crypto_pwhash_str((char *)h.data, (char *)p.data, p.size, o, m) != 0) {
|
if (crypto_pwhash_str((char *)h.data, (char *)p.data, p.size, o, m) != 0) {
|
||||||
/* out of memory */
|
/* out of memory */
|
||||||
enif_release_binary(&h);
|
enif_release_binary(&h);
|
||||||
return enacl_error_tuple(env, "out_of_memory");
|
return enacl_internal_error(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
ERL_NIF_TERM ok = enif_make_atom(env, ATOM_OK);
|
return enif_make_binary(env, &h);
|
||||||
ERL_NIF_TERM ret = enif_make_binary(env, &h);
|
|
||||||
|
|
||||||
return enif_make_tuple2(env, ok, ret);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ERL_NIF_TERM enacl_crypto_pwhash_str_verify(ErlNifEnv *env, int argc,
|
ERL_NIF_TERM enacl_crypto_pwhash_str_verify(ErlNifEnv *env, int argc,
|
||||||
|
@ -726,7 +726,7 @@ prop_pwhash_str_verify() ->
|
|||||||
begin
|
begin
|
||||||
case v_iodata(Passwd) of
|
case v_iodata(Passwd) of
|
||||||
true ->
|
true ->
|
||||||
{ok, Ascii} = enacl:pwhash_str(Passwd),
|
Ascii = enacl:pwhash_str(Passwd),
|
||||||
S = enacl:pwhash_str_verify(Ascii, Passwd),
|
S = enacl:pwhash_str_verify(Ascii, Passwd),
|
||||||
equals(S, true);
|
equals(S, true);
|
||||||
false ->
|
false ->
|
||||||
|
@ -338,7 +338,7 @@ unsafe_memzero(_) ->
|
|||||||
%% either 16, 32 or 64 bytes
|
%% either 16, 32 or 64 bytes
|
||||||
%% @end
|
%% @end
|
||||||
-type generichash_bytes() :: 10..64.
|
-type generichash_bytes() :: 10..64.
|
||||||
-spec generichash(generichash_bytes(), iodata(), binary()) -> {ok, binary()} | {error, term()}.
|
-spec generichash(generichash_bytes(), iodata(), binary()) -> binary().
|
||||||
generichash(HashSize, Message, Key) ->
|
generichash(HashSize, Message, Key) ->
|
||||||
enacl_nif:crypto_generichash(HashSize, Message, Key).
|
enacl_nif:crypto_generichash(HashSize, Message, Key).
|
||||||
|
|
||||||
@ -347,13 +347,13 @@ generichash(HashSize, Message, Key) ->
|
|||||||
%% This function generates a hash of the message. The hash size is
|
%% This function generates a hash of the message. The hash size is
|
||||||
%% either 16, 32 or 64 bytes
|
%% either 16, 32 or 64 bytes
|
||||||
%% @end
|
%% @end
|
||||||
-spec generichash(generichash_bytes(), iodata()) -> {ok, binary()} | {error, term()}.
|
-spec generichash(generichash_bytes(), iodata()) -> binary().
|
||||||
generichash(HashSize, Message) ->
|
generichash(HashSize, Message) ->
|
||||||
enacl_nif:crypto_generichash(HashSize, Message, <<>>).
|
enacl_nif:crypto_generichash(HashSize, Message, <<>>).
|
||||||
|
|
||||||
%% @doc generichash_init/2 initializes a multi-part hash.
|
%% @doc generichash_init/2 initializes a multi-part hash.
|
||||||
%% @end
|
%% @end
|
||||||
-spec generichash_init(generichash_bytes(), binary()) -> reference() | notsup.
|
-spec generichash_init(generichash_bytes(), binary()) -> reference().
|
||||||
generichash_init(HashSize, Key) ->
|
generichash_init(HashSize, Key) ->
|
||||||
enacl_nif:crypto_generichash_init(HashSize, Key).
|
enacl_nif:crypto_generichash_init(HashSize, Key).
|
||||||
|
|
||||||
@ -374,7 +374,7 @@ generichash_final(State) ->
|
|||||||
%% This function generates a fixed size salted hash of a user defined password.
|
%% This function generates a fixed size salted hash of a user defined password.
|
||||||
%% Defaults to interactive/interactive limits.
|
%% Defaults to interactive/interactive limits.
|
||||||
%% @end
|
%% @end
|
||||||
-spec pwhash(iodata(), binary()) -> {ok, binary()} | {error, term()}.
|
-spec pwhash(iodata(), binary()) -> binary().
|
||||||
pwhash(Password, Salt) ->
|
pwhash(Password, Salt) ->
|
||||||
pwhash(Password, Salt, interactive, interactive).
|
pwhash(Password, Salt, interactive, interactive).
|
||||||
|
|
||||||
@ -383,7 +383,7 @@ pwhash(Password, Salt) ->
|
|||||||
%% This function generates a fixed size salted hash of a user defined password given Ops and Mem
|
%% This function generates a fixed size salted hash of a user defined password given Ops and Mem
|
||||||
%% limits.
|
%% limits.
|
||||||
%% @end
|
%% @end
|
||||||
-spec pwhash(Password, Salt, Ops, Mem) -> {ok, binary()} | {error, term()}
|
-spec pwhash(Password, Salt, Ops, Mem) -> binary()
|
||||||
when
|
when
|
||||||
Password :: iodata(),
|
Password :: iodata(),
|
||||||
Salt :: binary(),
|
Salt :: binary(),
|
||||||
@ -397,7 +397,7 @@ pwhash(Password, Salt, Ops, Mem) ->
|
|||||||
%% This function generates a fixed size, salted, ASCII encoded hash of a user defined password.
|
%% This function generates a fixed size, salted, ASCII encoded hash of a user defined password.
|
||||||
%% Defaults to interactive/interactive limits.
|
%% Defaults to interactive/interactive limits.
|
||||||
%% @end
|
%% @end
|
||||||
-spec pwhash_str(iodata()) -> {ok, iodata()} | {error, term()}.
|
-spec pwhash_str(iodata()) -> iodata().
|
||||||
pwhash_str(Password) ->
|
pwhash_str(Password) ->
|
||||||
pwhash_str(Password, interactive, interactive).
|
pwhash_str(Password, interactive, interactive).
|
||||||
|
|
||||||
@ -406,18 +406,13 @@ pwhash_str(Password) ->
|
|||||||
%% This function generates a fixed size, salted, ASCII encoded hash of a user defined password
|
%% This function generates a fixed size, salted, ASCII encoded hash of a user defined password
|
||||||
%% given Ops and Mem limits.
|
%% given Ops and Mem limits.
|
||||||
%% @end
|
%% @end
|
||||||
-spec pwhash_str(Password, Ops, Mem) -> {ok, iodata()} | {error, term()}
|
-spec pwhash_str(Password, Ops, Mem) -> iodata()
|
||||||
when
|
when
|
||||||
Password :: iodata(),
|
Password :: iodata(),
|
||||||
Ops :: pwhash_limit(),
|
Ops :: pwhash_limit(),
|
||||||
Mem :: pwhash_limit().
|
Mem :: pwhash_limit().
|
||||||
pwhash_str(Password, Ops, Mem) ->
|
pwhash_str(Password, Ops, Mem) ->
|
||||||
case enacl_nif:crypto_pwhash_str(Password, Ops, Mem) of
|
strip_null_terminate(enacl_nif:crypto_pwhash_str(Password, Ops, Mem)).
|
||||||
{ok, ASCII} ->
|
|
||||||
{ok, strip_null_terminate(ASCII)};
|
|
||||||
{error, Reason} ->
|
|
||||||
{error, Reason}
|
|
||||||
end.
|
|
||||||
|
|
||||||
strip_null_terminate(Binary) ->
|
strip_null_terminate(Binary) ->
|
||||||
[X, _] = binary:split(Binary, <<0>>),
|
[X, _] = binary:split(Binary, <<0>>),
|
||||||
|
@ -59,9 +59,9 @@ generichash_basic_neg(_Config) ->
|
|||||||
"I've watched C-beams glitter in the dark near the Tannhäuser Gate. "
|
"I've watched C-beams glitter in the dark near the Tannhäuser Gate. "
|
||||||
"All those... moments... will be lost... in time, like... tears... in rain">>,
|
"All those... moments... will be lost... in time, like... tears... in rain">>,
|
||||||
Key = <<"Hash Key 123456789">>,
|
Key = <<"Hash Key 123456789">>,
|
||||||
{error, invalid_hash_size} = enacl:generichash(9, Msg, Key),
|
{'EXIT', {badarg, _}} = (catch enacl:generichash(9, Msg, Key)),
|
||||||
{error, invalid_hash_size} = enacl:generichash(65, Msg, Key),
|
{'EXIT', {badarg, _}} = (catch enacl:generichash(65, Msg, Key)),
|
||||||
{error, invalid_key_size} = enacl:generichash(32, Msg, <<"Small">>),
|
{'EXIT', {badarg, _}} = (catch enacl:generichash(32, Msg, <<"Small">>)),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
generichash_basic_pos(_Config) ->
|
generichash_basic_pos(_Config) ->
|
||||||
@ -69,8 +69,8 @@ generichash_basic_pos(_Config) ->
|
|||||||
"I've watched C-beams glitter in the dark near the Tannhäuser Gate. "
|
"I've watched C-beams glitter in the dark near the Tannhäuser Gate. "
|
||||||
"All those... moments... will be lost... in time, like... tears... in rain">>,
|
"All those... moments... will be lost... in time, like... tears... in rain">>,
|
||||||
Key = <<"Hash Key 123456789">>,
|
Key = <<"Hash Key 123456789">>,
|
||||||
{ok,<<189,104,45,187,170,229,212,4,121,43,137,74,241,173,181,77,
|
<<189,104,45,187,170,229,212,4,121,43,137,74,241,173,181,77,
|
||||||
67,211,133,70,196,6,128,97>>} = enacl:generichash(24, Msg, Key),
|
67,211,133,70,196,6,128,97>> = enacl:generichash(24, Msg, Key),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
generichash_chunked(_Config) ->
|
generichash_chunked(_Config) ->
|
||||||
@ -82,7 +82,7 @@ generichash_chunked(_Config) ->
|
|||||||
State = generichash_chunked(State, Msg, 10000),
|
State = generichash_chunked(State, Msg, 10000),
|
||||||
Expected = <<46,49,32,18,13,186,182,105,106,122,253,139,89,176,169,141,
|
Expected = <<46,49,32,18,13,186,182,105,106,122,253,139,89,176,169,141,
|
||||||
73,93,99,6,41,216,110,41>>,
|
73,93,99,6,41,216,110,41>>,
|
||||||
{ok, Expected} = enacl:generichash_final(State),
|
Expected = enacl:generichash_final(State),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
generichash_chunked(State, _Msg, 0) -> State;
|
generichash_chunked(State, _Msg, 0) -> State;
|
||||||
@ -119,8 +119,8 @@ pwhash(_Config) ->
|
|||||||
Salt = <<"1234567890abcdef">>,
|
Salt = <<"1234567890abcdef">>,
|
||||||
Hash1 = <<164,75,127,151,168,101,55,77,48,77,240,204,64,20,43,23,88,
|
Hash1 = <<164,75,127,151,168,101,55,77,48,77,240,204,64,20,43,23,88,
|
||||||
18,133,11,53,151,2,113,232,95,84,165,50,7,60,20>>,
|
18,133,11,53,151,2,113,232,95,84,165,50,7,60,20>>,
|
||||||
{ok, Hash1} = enacl:pwhash(PW, Salt),
|
Hash1 = enacl:pwhash(PW, Salt),
|
||||||
{ok, Str1} = enacl:pwhash_str(PW),
|
Str1 = enacl:pwhash_str(PW),
|
||||||
true = enacl:pwhash_str_verify(Str1, PW),
|
true = enacl:pwhash_str_verify(Str1, PW),
|
||||||
false = enacl:pwhash_str_verify(Str1, <<PW/binary, 1>>),
|
false = enacl:pwhash_str_verify(Str1, <<PW/binary, 1>>),
|
||||||
ok.
|
ok.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user