Introduce tests for authentication verification and provide basis for signatures.
This commit is contained in:
parent
ec0cc1afaa
commit
57bb93683b
4
.gitignore
vendored
4
.gitignore
vendored
@ -6,3 +6,7 @@ ebin
|
|||||||
*.eqc
|
*.eqc
|
||||||
*.so
|
*.so
|
||||||
eqc_test/.eqc-info
|
eqc_test/.eqc-info
|
||||||
|
doc/edoc-info
|
||||||
|
doc/*.html
|
||||||
|
doc/*.png
|
||||||
|
doc/*.css
|
||||||
|
@ -304,11 +304,21 @@ ERL_NIF_TERM enif_crypto_stream_NONCEBYTES(ErlNifEnv *env, int argc, ERL_NIF_TER
|
|||||||
return enif_make_int64(env, crypto_stream_NONCEBYTES);
|
return enif_make_int64(env, crypto_stream_NONCEBYTES);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
ERL_NIF_TERM enif_crypto_auth_BYTES(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
|
||||||
|
return enif_make_int64(env, crypto_auth_BYTES);
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
ERL_NIF_TERM enif_crypto_auth_KEYBYTES(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
|
ERL_NIF_TERM enif_crypto_auth_KEYBYTES(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
|
||||||
return enif_make_int64(env, crypto_auth_KEYBYTES);
|
return enif_make_int64(env, crypto_auth_KEYBYTES);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
ERL_NIF_TERM enif_crypto_onetimeauth_BYTES(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
|
||||||
|
return enif_make_int64(env, crypto_onetimeauth_BYTES);
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
ERL_NIF_TERM enif_crypto_onetimeauth_KEYBYTES(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
|
ERL_NIF_TERM enif_crypto_onetimeauth_KEYBYTES(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
|
||||||
return enif_make_int64(env, crypto_onetimeauth_KEYBYTES);
|
return enif_make_int64(env, crypto_onetimeauth_KEYBYTES);
|
||||||
@ -571,10 +581,12 @@ static ErlNifFunc nif_funcs[] = {
|
|||||||
{"crypto_stream", 3, enif_crypto_stream, ERL_NIF_DIRTY_JOB_CPU_BOUND},
|
{"crypto_stream", 3, enif_crypto_stream, ERL_NIF_DIRTY_JOB_CPU_BOUND},
|
||||||
{"crypto_stream_xor", 3, enif_crypto_stream_xor, ERL_NIF_DIRTY_JOB_CPU_BOUND},
|
{"crypto_stream_xor", 3, enif_crypto_stream_xor, ERL_NIF_DIRTY_JOB_CPU_BOUND},
|
||||||
|
|
||||||
|
{"crypto_auth_BYTES", 0, enif_crypto_auth_BYTES},
|
||||||
{"crypto_auth_KEYBYTES", 0, enif_crypto_auth_KEYBYTES},
|
{"crypto_auth_KEYBYTES", 0, enif_crypto_auth_KEYBYTES},
|
||||||
{"crypto_auth", 2, enif_crypto_auth, ERL_NIF_DIRTY_JOB_CPU_BOUND},
|
{"crypto_auth", 2, enif_crypto_auth, ERL_NIF_DIRTY_JOB_CPU_BOUND},
|
||||||
{"crypto_auth_verify", 3, enif_crypto_auth_verify, ERL_NIF_DIRTY_JOB_CPU_BOUND},
|
{"crypto_auth_verify", 3, enif_crypto_auth_verify, ERL_NIF_DIRTY_JOB_CPU_BOUND},
|
||||||
|
|
||||||
|
{"crypto_onetimeauth_BYTES", 0, enif_crypto_onetimeauth_BYTES},
|
||||||
{"crypto_onetimeauth_KEYBYTES", 0, enif_crypto_onetimeauth_KEYBYTES},
|
{"crypto_onetimeauth_KEYBYTES", 0, enif_crypto_onetimeauth_KEYBYTES},
|
||||||
{"crypto_onetimeauth", 2, enif_crypto_onetimeauth, ERL_NIF_DIRTY_JOB_CPU_BOUND},
|
{"crypto_onetimeauth", 2, enif_crypto_onetimeauth, ERL_NIF_DIRTY_JOB_CPU_BOUND},
|
||||||
{"crypto_onetimeauth_verify", 3, enif_crypto_onetimeauth_verify, ERL_NIF_DIRTY_JOB_CPU_BOUND},
|
{"crypto_onetimeauth_verify", 3, enif_crypto_onetimeauth_verify, ERL_NIF_DIRTY_JOB_CPU_BOUND},
|
||||||
|
@ -236,6 +236,45 @@ prop_auth_correct() ->
|
|||||||
badargs(fun() -> enacl:auth(Msg, Key) end)
|
badargs(fun() -> enacl:auth(Msg, Key) end)
|
||||||
end).
|
end).
|
||||||
|
|
||||||
|
authenticator_bad() ->
|
||||||
|
oneof([a, int(), ?SUCHTHAT(X, binary(), byte_size(X) /= enacl:auth_size())]).
|
||||||
|
|
||||||
|
authenticator_good(Msg, Key) when is_binary(Key) ->
|
||||||
|
Sz = enacl:secretbox_key_size(),
|
||||||
|
case byte_size(Key) == Sz of
|
||||||
|
true ->
|
||||||
|
frequency([{1, ?LAZY({invalid, binary(enacl:auth_size())})},
|
||||||
|
{3, return({valid, enacl:auth(Msg, Key)})}]);
|
||||||
|
false ->
|
||||||
|
binary(enacl:auth_size())
|
||||||
|
end;
|
||||||
|
authenticator_good(_Msg, _Key) ->
|
||||||
|
binary(enacl:auth_size()).
|
||||||
|
|
||||||
|
authenticator(Msg, Key) ->
|
||||||
|
fault(authenticator_bad(), authenticator_good(Msg, Key)).
|
||||||
|
|
||||||
|
authenticator_valid({valid, _}) -> true;
|
||||||
|
authenticator_valid({invalid, _}) -> true;
|
||||||
|
authenticator_valid(_) -> false.
|
||||||
|
|
||||||
|
prop_auth_verify_correct() ->
|
||||||
|
?FORALL({Msg, Key},
|
||||||
|
{binary(),
|
||||||
|
fault_rate(1, 40, secret_key())},
|
||||||
|
?FORALL(Authenticator, authenticator(Msg, Key),
|
||||||
|
case secret_key_valid(Key) andalso authenticator_valid(Authenticator) of
|
||||||
|
true ->
|
||||||
|
case Authenticator of
|
||||||
|
{valid, A} ->
|
||||||
|
equals(true, enacl:auth_verify(A, Msg, Key));
|
||||||
|
{invalid, A} ->
|
||||||
|
equals(false, enacl:auth_verify(A, Msg, Key))
|
||||||
|
end;
|
||||||
|
false ->
|
||||||
|
badargs(fun() -> enacl:auth_verify(Authenticator, Msg, Key) end)
|
||||||
|
end)).
|
||||||
|
|
||||||
%% CRYPTO ONETIME AUTH
|
%% CRYPTO ONETIME AUTH
|
||||||
prop_onetimeauth_correct() ->
|
prop_onetimeauth_correct() ->
|
||||||
?FORALL({Msg, Key},
|
?FORALL({Msg, Key},
|
||||||
@ -249,6 +288,45 @@ prop_onetimeauth_correct() ->
|
|||||||
badargs(fun() -> enacl:onetime_auth(Msg, Key) end)
|
badargs(fun() -> enacl:onetime_auth(Msg, Key) end)
|
||||||
end).
|
end).
|
||||||
|
|
||||||
|
ot_authenticator_bad() ->
|
||||||
|
oneof([a, int(), ?SUCHTHAT(X, binary(), byte_size(X) /= enacl:onetime_auth_size())]).
|
||||||
|
|
||||||
|
ot_authenticator_good(Msg, Key) when is_binary(Key) ->
|
||||||
|
Sz = enacl:secretbox_key_size(),
|
||||||
|
case byte_size(Key) == Sz of
|
||||||
|
true ->
|
||||||
|
frequency([{1, ?LAZY({invalid, binary(enacl:onetime_auth_size())})},
|
||||||
|
{3, return({valid, enacl:onetime_auth(Msg, Key)})}]);
|
||||||
|
false ->
|
||||||
|
binary(enacl:onetime_auth_size())
|
||||||
|
end;
|
||||||
|
ot_authenticator_good(_Msg, _Key) ->
|
||||||
|
binary(enacl:auth_size()).
|
||||||
|
|
||||||
|
ot_authenticator(Msg, Key) ->
|
||||||
|
fault(ot_authenticator_bad(), ot_authenticator_good(Msg, Key)).
|
||||||
|
|
||||||
|
ot_authenticator_valid({valid, _}) -> true;
|
||||||
|
ot_authenticator_valid({invalid, _}) -> true;
|
||||||
|
ot_authenticator_valid(_) -> false.
|
||||||
|
|
||||||
|
prop_onetime_auth_verify_correct() ->
|
||||||
|
?FORALL({Msg, Key},
|
||||||
|
{binary(),
|
||||||
|
fault_rate(1, 40, secret_key())},
|
||||||
|
?FORALL(Authenticator, ot_authenticator(Msg, Key),
|
||||||
|
case secret_key_valid(Key) andalso ot_authenticator_valid(Authenticator) of
|
||||||
|
true ->
|
||||||
|
case Authenticator of
|
||||||
|
{valid, A} ->
|
||||||
|
equals(true, enacl:onetime_auth_verify(A, Msg, Key));
|
||||||
|
{invalid, A} ->
|
||||||
|
equals(false, enacl:onetime_auth_verify(A, Msg, Key))
|
||||||
|
end;
|
||||||
|
false ->
|
||||||
|
badargs(fun() -> enacl:onetime_auth_verify(Authenticator, Msg, Key) end)
|
||||||
|
end)).
|
||||||
|
|
||||||
%% HASHING
|
%% HASHING
|
||||||
%% ---------------------------
|
%% ---------------------------
|
||||||
diff_pair(Sz) ->
|
diff_pair(Sz) ->
|
||||||
|
@ -23,7 +23,11 @@
|
|||||||
box_open/4,
|
box_open/4,
|
||||||
box_nonce_size/0,
|
box_nonce_size/0,
|
||||||
box_public_key_bytes/0,
|
box_public_key_bytes/0,
|
||||||
box_secret_key_bytes/0
|
box_secret_key_bytes/0,
|
||||||
|
|
||||||
|
sign_keypair/0,
|
||||||
|
sign/2,
|
||||||
|
sign_open/2
|
||||||
]).
|
]).
|
||||||
|
|
||||||
%% Secret key crypto
|
%% Secret key crypto
|
||||||
@ -39,10 +43,12 @@
|
|||||||
stream_xor/3,
|
stream_xor/3,
|
||||||
|
|
||||||
auth_key_size/0,
|
auth_key_size/0,
|
||||||
|
auth_size/0,
|
||||||
auth/2,
|
auth/2,
|
||||||
auth_verify/3,
|
auth_verify/3,
|
||||||
|
|
||||||
onetime_auth_key_size/0,
|
onetime_auth_key_size/0,
|
||||||
|
onetime_auth_size/0,
|
||||||
onetime_auth/2,
|
onetime_auth/2,
|
||||||
onetime_auth_verify/3
|
onetime_auth_verify/3
|
||||||
]).
|
]).
|
||||||
@ -139,6 +145,38 @@ box_nonce_size() ->
|
|||||||
box_public_key_bytes() ->
|
box_public_key_bytes() ->
|
||||||
enacl_nif:crypto_box_PUBLICKEYBYTES().
|
enacl_nif:crypto_box_PUBLICKEYBYTES().
|
||||||
|
|
||||||
|
%% Signatures
|
||||||
|
|
||||||
|
%% @doc sign_keypair/0 returns a signature keypair for signing
|
||||||
|
%% The returned value is a map in order to make it harder to misuse keys.
|
||||||
|
%% @end
|
||||||
|
-spec sign_keypair() -> KeyMap
|
||||||
|
when KeyMap :: maps:map(atom(), binary()).
|
||||||
|
sign_keypair() ->
|
||||||
|
{PK, SK} = enacl_nif:sign_keypair(),
|
||||||
|
#{ public => PK, secret => SK}.
|
||||||
|
|
||||||
|
%% @doc sign/2 signs a message with a digital signature identified by a secret key.
|
||||||
|
%% Given a message `M' and a secret key `SK' the function will sign the message and return a signed message `SM'.
|
||||||
|
%% @end
|
||||||
|
-spec sign(M, SK) -> SM
|
||||||
|
when
|
||||||
|
M :: binary(),
|
||||||
|
SK :: binary(),
|
||||||
|
SM :: binary().
|
||||||
|
sign(M, SK) -> enacl_nif:sign(M, SK).
|
||||||
|
|
||||||
|
%% @doc sign_open/2 opens a digital signature
|
||||||
|
%% Given a signed message `SM' and a public key `PK', verify that the message has the right signature. Returns either
|
||||||
|
%% `{ok, M}' or `{error, failed_verification}' depending on the correctness of the signature.
|
||||||
|
%% @end
|
||||||
|
-spec sign_open(SM, PK) -> {ok, M} | {error, failed_verification}
|
||||||
|
when
|
||||||
|
SM :: binary(),
|
||||||
|
PK :: binary(),
|
||||||
|
M :: binary().
|
||||||
|
sign_open(SM, PK) -> enacl_nif:sign_open(SM, PK).
|
||||||
|
|
||||||
%% @private
|
%% @private
|
||||||
-spec box_secret_key_bytes() -> pos_integer().
|
-spec box_secret_key_bytes() -> pos_integer().
|
||||||
box_secret_key_bytes() ->
|
box_secret_key_bytes() ->
|
||||||
@ -204,6 +242,11 @@ stream_xor(Msg, Nonce, Key) ->
|
|||||||
-spec auth_key_size() -> pos_integer().
|
-spec auth_key_size() -> pos_integer().
|
||||||
auth_key_size() -> enacl_nif:crypto_auth_KEYBYTES().
|
auth_key_size() -> enacl_nif:crypto_auth_KEYBYTES().
|
||||||
|
|
||||||
|
%% @doc auth_size/0 returns the byte-size of the authenticator
|
||||||
|
%% @end
|
||||||
|
-spec auth_size() -> pos_integer().
|
||||||
|
auth_size() -> enacl_nif:crypto_auth_BYTES().
|
||||||
|
|
||||||
%% @doc auth/2 produces an authenticator (MAC) for a message
|
%% @doc auth/2 produces an authenticator (MAC) for a message
|
||||||
%% Given a `Msg' and a `Key' produce a MAC/Authenticator for that message. The key can be reused for several such Msg/Authenticator pairs.
|
%% Given a `Msg' and a `Key' produce a MAC/Authenticator for that message. The key can be reused for several such Msg/Authenticator pairs.
|
||||||
%% An eavesdropper will not learn anything extra about the message structure.
|
%% An eavesdropper will not learn anything extra about the message structure.
|
||||||
@ -239,7 +282,7 @@ onetime_auth(Msg, Key) -> enacl_nif:crypto_onetimeauth(Msg, Key).
|
|||||||
|
|
||||||
%% @doc onetime_auth_verify/3 verifies an ONE-TIME authenticator for a message
|
%% @doc onetime_auth_verify/3 verifies an ONE-TIME authenticator for a message
|
||||||
%% Given an `Authenticator', a `Msg' and a `Key'; verify that the MAC for the pair `{Msg, Key}' is really `Authenticator'. Returns
|
%% Given an `Authenticator', a `Msg' and a `Key'; verify that the MAC for the pair `{Msg, Key}' is really `Authenticator'. Returns
|
||||||
%% the value `true' if the verfication passes. Upon failure, the function returns `false'. Note the caveat from {@link onetime_auth/2}
|
%% the value `true' if the verification passes. Upon failure, the function returns `false'. Note the caveat from {@link onetime_auth/2}
|
||||||
%% applies: you are not allowed to ever use the same key again for another message.
|
%% applies: you are not allowed to ever use the same key again for another message.
|
||||||
%% @end
|
%% @end
|
||||||
-spec onetime_auth_verify(Authenticator, Msg, Key) -> boolean()
|
-spec onetime_auth_verify(Authenticator, Msg, Key) -> boolean()
|
||||||
@ -249,6 +292,11 @@ onetime_auth(Msg, Key) -> enacl_nif:crypto_onetimeauth(Msg, Key).
|
|||||||
Key :: binary().
|
Key :: binary().
|
||||||
onetime_auth_verify(A, M, K) -> enacl_nif:crypto_onetimeauth_verify(A, M, K).
|
onetime_auth_verify(A, M, K) -> enacl_nif:crypto_onetimeauth_verify(A, M, K).
|
||||||
|
|
||||||
|
%% @doc onetime_auth_size/0 returns the number of bytes of the one-time authenticator
|
||||||
|
%% @end
|
||||||
|
-spec onetime_auth_size() -> pos_integer().
|
||||||
|
onetime_auth_size() -> enacl_nif:crypto_onetimeauth_BYTES().
|
||||||
|
|
||||||
%% @doc onetime_auth_key_size/0 returns the byte-size of the onetime authentication key
|
%% @doc onetime_auth_key_size/0 returns the byte-size of the onetime authentication key
|
||||||
%% @end
|
%% @end
|
||||||
-spec onetime_auth_key_size() -> pos_integer().
|
-spec onetime_auth_key_size() -> pos_integer().
|
||||||
|
@ -35,10 +35,12 @@
|
|||||||
crypto_stream/3,
|
crypto_stream/3,
|
||||||
crypto_stream_xor/3,
|
crypto_stream_xor/3,
|
||||||
|
|
||||||
|
crypto_auth_BYTES/0,
|
||||||
crypto_auth_KEYBYTES/0,
|
crypto_auth_KEYBYTES/0,
|
||||||
crypto_auth/2,
|
crypto_auth/2,
|
||||||
crypto_auth_verify/3,
|
crypto_auth_verify/3,
|
||||||
|
|
||||||
|
crypto_onetimeauth_BYTES/0,
|
||||||
crypto_onetimeauth_KEYBYTES/0,
|
crypto_onetimeauth_KEYBYTES/0,
|
||||||
crypto_onetimeauth/2,
|
crypto_onetimeauth/2,
|
||||||
crypto_onetimeauth_verify/3
|
crypto_onetimeauth_verify/3
|
||||||
@ -93,10 +95,12 @@ crypto_stream_NONCEBYTES() -> not_loaded().
|
|||||||
crypto_stream(_Bytes, _Nonce, _Key) -> not_loaded().
|
crypto_stream(_Bytes, _Nonce, _Key) -> not_loaded().
|
||||||
crypto_stream_xor(_M, _Nonce, _Key) -> not_loaded().
|
crypto_stream_xor(_M, _Nonce, _Key) -> not_loaded().
|
||||||
|
|
||||||
|
crypto_auth_BYTES() -> not_loaded().
|
||||||
crypto_auth_KEYBYTES() -> not_loaded().
|
crypto_auth_KEYBYTES() -> not_loaded().
|
||||||
crypto_auth(_Msg, _Key) -> not_loaded().
|
crypto_auth(_Msg, _Key) -> not_loaded().
|
||||||
crypto_auth_verify(_Authenticator, _Msg, _Key) -> not_loaded().
|
crypto_auth_verify(_Authenticator, _Msg, _Key) -> not_loaded().
|
||||||
|
|
||||||
|
crypto_onetimeauth_BYTES() -> not_loaded().
|
||||||
crypto_onetimeauth_KEYBYTES() -> not_loaded().
|
crypto_onetimeauth_KEYBYTES() -> not_loaded().
|
||||||
crypto_onetimeauth(_Msg, _Key) -> not_loaded().
|
crypto_onetimeauth(_Msg, _Key) -> not_loaded().
|
||||||
crypto_onetimeauth_verify(_Authenticator, _Msg, _Key) -> not_loaded().
|
crypto_onetimeauth_verify(_Authenticator, _Msg, _Key) -> not_loaded().
|
||||||
|
Loading…
x
Reference in New Issue
Block a user