reduction handling, iodata() conversion.
This commit is contained in:
parent
d9dbabf736
commit
90509026ce
@ -39,7 +39,7 @@ static
|
|||||||
ERL_NIF_TERM enif_crypto_verify_16(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
|
ERL_NIF_TERM enif_crypto_verify_16(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
|
||||||
ErlNifBinary x,y;
|
ErlNifBinary x,y;
|
||||||
|
|
||||||
if ((argc != 2) || (!enif_inspect_iolist_as_binary(env, argv[0], &x))
|
if ((argc != 2) || (!enif_inspect_binary(env, argv[0], &x))
|
||||||
|| (!enif_inspect_iolist_as_binary(env, argv[1], &y))) {
|
|| (!enif_inspect_iolist_as_binary(env, argv[1], &y))) {
|
||||||
return enif_make_badarg(env);
|
return enif_make_badarg(env);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{application, enacl,
|
{application, enacl,
|
||||||
[
|
[
|
||||||
{description, "Erlang NaCl bindings"},
|
{description, "Erlang NaCl bindings"},
|
||||||
{vsn, "0.0.1"},
|
{vsn, "0.9.0"},
|
||||||
{registered, []},
|
{registered, []},
|
||||||
{applications, [kernel, stdlib]},
|
{applications, [kernel, stdlib]},
|
||||||
{env, []}
|
{env, []}
|
||||||
|
184
src/enacl.erl
184
src/enacl.erl
@ -68,12 +68,23 @@
|
|||||||
]).
|
]).
|
||||||
|
|
||||||
%% Definitions of system budgets
|
%% Definitions of system budgets
|
||||||
|
%% To get a grip for these, call `enacl_timing:all/0' on your system. The numbers here are
|
||||||
|
%% described in the README.md file.
|
||||||
-define(HASH_SIZE, 32 * 1024).
|
-define(HASH_SIZE, 32 * 1024).
|
||||||
-define(HASH_REDUCTIONS, 2 * 200).
|
-define(HASH_REDUCTIONS, 104 * 2 * 2).
|
||||||
-define(BOX_SIZE, 32 * 1024).
|
-define(BOX_SIZE, 32 * 1024).
|
||||||
-define(BOX_REDUCTIONS, 2 * 250).
|
-define(BOX_REDUCTIONS, 115 *2 *2).
|
||||||
-define(SIGN_SIZE, 16 * 1024).
|
-define(SIGN_SIZE, 16 * 1024).
|
||||||
-define(SIGN_REDUCTIONS, 2 * 350).
|
-define(SIGN_REDUCTIONS, 160 * 2 *2).
|
||||||
|
-define(SECRETBOX_SIZE, 64 * 1024).
|
||||||
|
-define(SECRETBOX_REDUCTIONS, 107 * 2 * 2).
|
||||||
|
-define(SECRETBOX_OPEN_REDUCTIONS, 51 * 2 * 2).
|
||||||
|
-define(STREAM_SIZE, 128 * 1024).
|
||||||
|
-define(STREAM_REDUCTIONS, 120 * 2 * 2).
|
||||||
|
-define(AUTH_SIZE, 32 * 1024).
|
||||||
|
-define(AUTH_REDUCTIONS, 102 * 2 * 2).
|
||||||
|
-define(ONETIME_AUTH_SIZE, 128 * 1024).
|
||||||
|
-define(ONETIME_AUTH_REDUCTIONS, 105 * 2 * 2).
|
||||||
|
|
||||||
%% Count reductions and number of scheduler yields for Fun. Fun is assumed
|
%% Count reductions and number of scheduler yields for Fun. Fun is assumed
|
||||||
%% to be one of the above exor variants.
|
%% to be one of the above exor variants.
|
||||||
@ -96,39 +107,41 @@ reds(Fun) ->
|
|||||||
%% -----------------
|
%% -----------------
|
||||||
|
|
||||||
%% @doc hash/1 hashes data into a cryptographically secure checksum.
|
%% @doc hash/1 hashes data into a cryptographically secure checksum.
|
||||||
%% <p>Given a binary, `Data' of any size, run a cryptographically secure hash algorithm to
|
%% <p>Given an iodata(), `Data' of any size, run a cryptographically secure hash algorithm to
|
||||||
%% produce a checksum of the data. This can be used to verify the integrity of a data block
|
%% produce a checksum of the data. This can be used to verify the integrity of a data block
|
||||||
%% since the checksum have the properties of cryptographic hashes in general.</p>
|
%% since the checksum have the properties of cryptographic hashes in general.</p>
|
||||||
%% <p>The currently selected primitive (Nov. 2014) is SHA-512</p>
|
%% <p>The currently selected primitive (Nov. 2014) is SHA-512</p>
|
||||||
%% @end
|
%% @end
|
||||||
-spec hash(Data) -> Checksum
|
-spec hash(Data) -> Checksum
|
||||||
when Data :: binary(),
|
when Data :: iodata(),
|
||||||
Checksum :: binary().
|
Checksum :: binary().
|
||||||
|
|
||||||
hash(Bin) when byte_size(Bin) =< ?HASH_SIZE ->
|
|
||||||
R = enacl_nif:crypto_hash_b(Bin),
|
|
||||||
bump(?HASH_REDUCTIONS, ?HASH_SIZE, byte_size(Bin)),
|
|
||||||
R;
|
|
||||||
hash(Bin) ->
|
hash(Bin) ->
|
||||||
enacl_nif:crypto_hash(Bin).
|
case iolist_size(Bin) of
|
||||||
|
K when K =< ?HASH_SIZE -> bump(enacl_nif:crypto_hash_b(Bin), ?HASH_REDUCTIONS, ?HASH_SIZE, K);
|
||||||
|
_ -> enacl_nif:crypto_hash(Bin)
|
||||||
|
end.
|
||||||
|
|
||||||
%% @doc verify_16/2 implements constant time 16-byte string verification
|
%% @doc verify_16/2 implements constant time 16-byte binary() verification
|
||||||
%% <p>A subtle problem in cryptographic software are timing attacks where an attacker exploits
|
%% <p>A subtle problem in cryptographic software are timing attacks where an attacker exploits
|
||||||
%% early exist in string verification if the strings happen to mismatch. This allows the
|
%% early exist in string verification if the strings happen to mismatch. This allows the
|
||||||
%% attacker to time how long verification took and thus learn the structure of the desired
|
%% attacker to time how long verification took and thus learn the structure of the desired
|
||||||
%% string to use. The verify_16/2 call will check two 16 byte strings for equality while
|
%% string to use. The verify_16/2 call will check two 16 byte strings for equality while
|
||||||
%% guaranteeing the equality operation is constant time.</p>
|
%% guaranteeing the equality operation is constant time.</p>
|
||||||
%% <p>If the strings are not exactly 16 bytes, the comparison function will fail with badarg.</p>
|
%% <p>If the strings are not exactly 16 bytes, the comparison function will fail with badarg.</p>
|
||||||
|
%% <p>The functions take binary() values and not iolist() values since the latter would convert in non-constant time</p>
|
||||||
%% <p>Verification returns a boolean. `true' if the strings match, `false' otherwise.</p>
|
%% <p>Verification returns a boolean. `true' if the strings match, `false' otherwise.</p>
|
||||||
%% @end
|
%% @end
|
||||||
-spec verify_16(binary(), binary()) -> boolean().
|
-spec verify_16(binary(), binary()) -> boolean().
|
||||||
verify_16(X, Y) -> enacl_nif:crypto_verify_16(X, Y).
|
verify_16(X, Y) when is_binary(X), is_binary(Y) -> enacl_nif:crypto_verify_16(X, Y);
|
||||||
|
verify_16(_, _) -> error(badarg).
|
||||||
|
|
||||||
%% @doc verify_32/2 implements constant time 32-byte string verification
|
%% @doc verify_32/2 implements constant time 32-byte iolist() verification
|
||||||
%% This function works as {@link verify_16/2} but does so on 32 byte strings.
|
%% This function works as {@link verify_16/2} but does so on 32 byte strings. Same caveats apply.
|
||||||
%% @end
|
%% @end
|
||||||
-spec verify_32(binary(), binary()) -> boolean().
|
-spec verify_32(binary(), binary()) -> boolean().
|
||||||
verify_32(X, Y) -> enacl_nif:crypto_verify_32(X, Y).
|
verify_32(X, Y) when is_binary(X), is_binary(Y) -> enacl_nif:crypto_verify_32(X, Y);
|
||||||
|
verify_32(_, _) -> error(badarg).
|
||||||
|
|
||||||
%% Public Key Crypto
|
%% Public Key Crypto
|
||||||
%% ---------------------
|
%% ---------------------
|
||||||
@ -146,39 +159,43 @@ box_keypair() ->
|
|||||||
%% authenticate yourself. Requires a `Nonce` in addition. Returns the ciphered message.
|
%% authenticate yourself. Requires a `Nonce` in addition. Returns the ciphered message.
|
||||||
%% @end
|
%% @end
|
||||||
-spec box(Msg, Nonce, PK, SK) -> CipherText
|
-spec box(Msg, Nonce, PK, SK) -> CipherText
|
||||||
when Msg :: binary(),
|
when Msg :: iodata(),
|
||||||
Nonce :: binary(),
|
Nonce :: binary(),
|
||||||
PK :: binary(),
|
PK :: binary(),
|
||||||
SK :: binary(),
|
SK :: binary(),
|
||||||
CipherText :: binary().
|
CipherText :: binary().
|
||||||
box(Msg, Nonce, PK, SK) when byte_size(Msg) =< ?BOX_SIZE ->
|
|
||||||
R = enacl_nif:crypto_box_b([p_zerobytes(), Msg], Nonce, PK, SK),
|
|
||||||
bump(?BOX_REDUCTIONS, ?BOX_SIZE, byte_size(Msg)),
|
|
||||||
R;
|
|
||||||
box(Msg, Nonce, PK, SK) ->
|
box(Msg, Nonce, PK, SK) ->
|
||||||
enacl_nif:crypto_box([p_zerobytes(), Msg], Nonce, PK, SK).
|
case iolist_size(Msg) of
|
||||||
|
K when K =< ?BOX_SIZE ->
|
||||||
|
bump(enacl_nif:crypto_box_b([p_zerobytes(), Msg], Nonce, PK, SK), ?BOX_REDUCTIONS, ?BOX_SIZE, K);
|
||||||
|
_ ->
|
||||||
|
enacl_nif:crypto_box([p_zerobytes(), Msg], Nonce, PK, SK)
|
||||||
|
end.
|
||||||
|
|
||||||
%% @doc box_open/4 decrypts+verifies a message from another party.
|
%% @doc box_open/4 decrypts+verifies a message from another party.
|
||||||
%% Decrypt a `CipherText` into a `Msg` given the other partys public key `PK` and your secret
|
%% Decrypt a `CipherText` into a `Msg` given the other partys public key `PK` and your secret
|
||||||
%% key `SK`. Also requires the same nonce as was used by the other party. Returns the plaintext
|
%% key `SK`. Also requires the same nonce as was used by the other party. Returns the plaintext
|
||||||
%% message.
|
%% message.
|
||||||
-spec box_open(CipherText, Nonce, PK, SK) -> Msg
|
-spec box_open(CipherText, Nonce, PK, SK) -> Msg
|
||||||
when CipherText :: binary(),
|
when CipherText :: iodata(),
|
||||||
Nonce :: binary(),
|
Nonce :: binary(),
|
||||||
PK :: binary(),
|
PK :: binary(),
|
||||||
SK :: binary(),
|
SK :: binary(),
|
||||||
Msg :: binary().
|
Msg :: binary().
|
||||||
box_open(CipherText, Nonce, PK, SK) when byte_size(CipherText) =< ?BOX_SIZE ->
|
|
||||||
R = case enacl_nif:crypto_box_open_b([p_box_zerobytes(), CipherText], Nonce, PK, SK) of
|
|
||||||
{error, Err} -> {error, Err};
|
|
||||||
Bin when is_binary(Bin) -> {ok, Bin}
|
|
||||||
end,
|
|
||||||
bump(?BOX_REDUCTIONS, ?BOX_SIZE, byte_size(CipherText)),
|
|
||||||
R;
|
|
||||||
box_open(CipherText, Nonce, PK, SK) ->
|
box_open(CipherText, Nonce, PK, SK) ->
|
||||||
case enacl_nif:crypto_box_open([p_box_zerobytes(), CipherText], Nonce, PK, SK) of
|
case iolist_size(CipherText) of
|
||||||
{error, Err} -> {error, Err};
|
K when K =< ?BOX_SIZE ->
|
||||||
Bin when is_binary(Bin) -> {ok, Bin}
|
R =
|
||||||
|
case enacl_nif:crypto_box_open_b([p_box_zerobytes(), CipherText], Nonce, PK, SK) of
|
||||||
|
{error, Err} -> {error, Err};
|
||||||
|
Bin when is_binary(Bin) -> {ok, Bin}
|
||||||
|
end,
|
||||||
|
bump(R, ?BOX_REDUCTIONS, ?BOX_SIZE, K);
|
||||||
|
_ ->
|
||||||
|
case enacl_nif:crypto_box_open([p_box_zerobytes(), CipherText], Nonce, PK, SK) of
|
||||||
|
{error, Err} -> {error, Err};
|
||||||
|
Bin when is_binary(Bin) -> {ok, Bin}
|
||||||
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% @doc box_nonce_size/0 return the byte-size of the nonce
|
%% @doc box_nonce_size/0 return the byte-size of the nonce
|
||||||
@ -217,36 +234,40 @@ sign_keypair() ->
|
|||||||
%% @end
|
%% @end
|
||||||
-spec sign(M, SK) -> SM
|
-spec sign(M, SK) -> SM
|
||||||
when
|
when
|
||||||
M :: binary(),
|
M :: iodata(),
|
||||||
SK :: binary(),
|
SK :: binary(),
|
||||||
SM :: binary().
|
SM :: binary().
|
||||||
sign(M, SK) when byte_size(M) =< ?SIGN_SIZE ->
|
|
||||||
R = enacl_nif:crypto_sign_b(M, SK),
|
|
||||||
bump(?SIGN_REDUCTIONS, ?SIGN_SIZE, byte_size(M)),
|
|
||||||
R;
|
|
||||||
sign(M, SK) ->
|
sign(M, SK) ->
|
||||||
enacl_nif:crypto_sign(M, SK).
|
case iolist_size(M) of
|
||||||
|
K when K =< ?SIGN_SIZE ->
|
||||||
|
bump(enacl_nif:crypto_sign_b(M, SK), ?SIGN_REDUCTIONS, ?SIGN_SIZE, K);
|
||||||
|
_ ->
|
||||||
|
enacl_nif:crypto_sign(M, SK)
|
||||||
|
end.
|
||||||
|
|
||||||
%% @doc sign_open/2 opens a digital signature
|
%% @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
|
%% Given a signed message `SM' and a public key `PK', verify that the message has the
|
||||||
%% `{ok, M}' or `{error, failed_verification}' depending on the correctness of the signature.
|
%% right signature. Returns either `{ok, M}' or `{error, failed_verification}' depending
|
||||||
|
%% on the correctness of the signature.
|
||||||
%% @end
|
%% @end
|
||||||
-spec sign_open(SM, PK) -> {ok, M} | {error, failed_verification}
|
-spec sign_open(SM, PK) -> {ok, M} | {error, failed_verification}
|
||||||
when
|
when
|
||||||
SM :: binary(),
|
SM :: iodata(),
|
||||||
PK :: binary(),
|
PK :: binary(),
|
||||||
M :: binary().
|
M :: binary().
|
||||||
sign_open(SM, PK) when byte_size(SM) =< ?SIGN_SIZE ->
|
|
||||||
R = case enacl_nif:crypto_sign_open(SM, PK) of
|
|
||||||
M when is_binary(M) -> {ok, M};
|
|
||||||
{error, Err} -> {error, Err}
|
|
||||||
end,
|
|
||||||
bump(?SIGN_REDUCTIONS, ?SIGN_SIZE, byte_size(SM)),
|
|
||||||
R;
|
|
||||||
sign_open(SM, PK) ->
|
sign_open(SM, PK) ->
|
||||||
case enacl_nif:crypto_sign_open(SM, PK) of
|
case iolist_size(SM) of
|
||||||
M when is_binary(M) -> {ok, M};
|
K when K =< ?SIGN_SIZE ->
|
||||||
{error, Err} -> {error, Err}
|
R = case enacl_nif:crypto_sign_open(SM, PK) of
|
||||||
|
M when is_binary(M) -> {ok, M};
|
||||||
|
{error, Err} -> {error, Err}
|
||||||
|
end,
|
||||||
|
bump(R, ?SIGN_REDUCTIONS, ?SIGN_SIZE, byte_size(SM));
|
||||||
|
_ ->
|
||||||
|
case enacl_nif:crypto_sign_open(SM, PK) of
|
||||||
|
M when is_binary(M) -> {ok, M};
|
||||||
|
{error, Err} -> {error, Err}
|
||||||
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% @private
|
%% @private
|
||||||
@ -254,15 +275,53 @@ sign_open(SM, PK) ->
|
|||||||
box_secret_key_bytes() ->
|
box_secret_key_bytes() ->
|
||||||
enacl_nif:crypto_box_SECRETKEYBYTES().
|
enacl_nif:crypto_box_SECRETKEYBYTES().
|
||||||
|
|
||||||
|
%% @doc secretbox/3 encrypts a message with a key
|
||||||
|
%% Given a `Msg', a `Nonce' and a `Key' encrypt the message with the Key while taking the
|
||||||
|
%% nonce into consideration. The function returns the Box obtained from the encryption.
|
||||||
|
%% @end
|
||||||
|
-spec secretbox(Msg, Nonce, Key) -> Box
|
||||||
|
when
|
||||||
|
Msg :: iodata(),
|
||||||
|
Nonce :: binary(),
|
||||||
|
Key :: binary(),
|
||||||
|
Box :: binary().
|
||||||
|
|
||||||
secretbox(Msg, Nonce, Key) ->
|
secretbox(Msg, Nonce, Key) ->
|
||||||
enacl_nif:crypto_secretbox([s_zerobytes(), Msg], Nonce, Key).
|
case iolist_size(Msg) of
|
||||||
|
K when K =< ?SECRETBOX_SIZE ->
|
||||||
secretbox_open(CipherText, Nonce, Key) ->
|
bump(enacl_nif:crypto_secretbox_b([s_zerobytes(), Msg], Nonce, Key),
|
||||||
case enacl_nif:crypto_secretbox_open([s_box_zerobytes(), CipherText], Nonce, Key) of
|
?SECRETBOX_REDUCTIONS,
|
||||||
{error, Err} -> {error, Err};
|
?SECRETBOX_SIZE,
|
||||||
Bin when is_binary(Bin) -> {ok, Bin}
|
K);
|
||||||
|
_ ->
|
||||||
|
enacl_nif:crypto_secretbox([s_zerobytes(), Msg], Nonce, Key)
|
||||||
end.
|
end.
|
||||||
|
%% @doc secretbox_open/3 opens a sealed box.
|
||||||
|
%% Given a boxed `CipherText' and given we know the used `Nonce' and `Key' we can open the box
|
||||||
|
%% to obtain the `Msg` within. Returns either `{ok, Msg}' or `{error, failed_verification}'.
|
||||||
|
%% @end
|
||||||
|
-spec secretbox_open(CipherText, Nonce, Key) -> {ok, Msg} | {error, failed_verification}
|
||||||
|
when
|
||||||
|
CipherText :: iodata(),
|
||||||
|
Nonce :: binary(),
|
||||||
|
Key :: binary(),
|
||||||
|
Msg :: binary().
|
||||||
|
secretbox_open(CipherText, Nonce, Key) ->
|
||||||
|
case iolist_size(CipherText) of
|
||||||
|
K when K =< ?SECRETBOX_SIZE ->
|
||||||
|
R = case enacl_nif:crypto_secretbox_open_b([s_box_zerobytes(), CipherText],
|
||||||
|
Nonce, Key) of
|
||||||
|
{error, Err} -> {error, Err};
|
||||||
|
Bin when is_binary(Bin) -> {ok, Bin}
|
||||||
|
end,
|
||||||
|
bump(R, ?SECRETBOX_OPEN_REDUCTIONS, ?SECRETBOX_SIZE, K);
|
||||||
|
_ ->
|
||||||
|
case enacl_nif:crypto_secretbox_open([s_box_zerobytes(), CipherText], Nonce, Key) of
|
||||||
|
{error, Err} -> {error, Err};
|
||||||
|
Bin when is_binary(Bin) -> {ok, Bin}
|
||||||
|
end
|
||||||
|
end.
|
||||||
|
|
||||||
secretbox_nonce_size() ->
|
secretbox_nonce_size() ->
|
||||||
enacl_nif:crypto_secretbox_NONCEBYTES().
|
enacl_nif:crypto_secretbox_NONCEBYTES().
|
||||||
|
|
||||||
@ -292,6 +351,11 @@ stream_key_size() -> enacl_nif:crypto_stream_KEYBYTES().
|
|||||||
Nonce :: binary(),
|
Nonce :: binary(),
|
||||||
Key :: binary(),
|
Key :: binary(),
|
||||||
CryptoStream :: binary().
|
CryptoStream :: binary().
|
||||||
|
stream(Len, Nonce, Key) when is_integer(Len), Len >= 0, Len =< ?STREAM_SIZE ->
|
||||||
|
bump(enacl_nif:crypto_stream_b(Len, Nonce, Key),
|
||||||
|
?STREAM_REDUCTIONS,
|
||||||
|
?STREAM_SIZE,
|
||||||
|
Len);
|
||||||
stream(Len, Nonce, Key) when is_integer(Len), Len >= 0 ->
|
stream(Len, Nonce, Key) when is_integer(Len), Len >= 0 ->
|
||||||
enacl_nif:crypto_stream(Len, Nonce, Key);
|
enacl_nif:crypto_stream(Len, Nonce, Key);
|
||||||
stream(_, _, _) -> error(badarg).
|
stream(_, _, _) -> error(badarg).
|
||||||
@ -387,7 +451,7 @@ s_zerobytes() ->
|
|||||||
s_box_zerobytes() ->
|
s_box_zerobytes() ->
|
||||||
binary:copy(<<0>>, enacl_nif:crypto_secretbox_BOXZEROBYTES()).
|
binary:copy(<<0>>, enacl_nif:crypto_secretbox_BOXZEROBYTES()).
|
||||||
|
|
||||||
bump(Budget, Max, Sz) ->
|
bump(Res, Budget, Max, Sz) ->
|
||||||
Reds = (Budget * Sz) div Max,
|
Reds = (Budget * Sz) div Max,
|
||||||
erlang:bump_reductions(max(1, Reds)),
|
erlang:bump_reductions(max(1, Reds)),
|
||||||
ok.
|
Res.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user