Add chacha stream function access.

This commit is contained in:
Doug Huff 2015-10-28 05:47:49 +00:00
parent ca005d32f9
commit 4d5524db61
3 changed files with 153 additions and 0 deletions

View File

@ -641,6 +641,16 @@ ERL_NIF_TERM enif_crypto_secretbox_BOXZEROBYTES(ErlNifEnv *env, int argc, ERL_NI
return enif_make_int64(env, crypto_secretbox_BOXZEROBYTES);
}
static
ERL_NIF_TERM enif_crypto_stream_chacha20_KEYBYTES(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_stream_chacha20_KEYBYTES);
}
static
ERL_NIF_TERM enif_crypto_stream_chacha20_NONCEBYTES(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_stream_chacha20_NONCEBYTES);
}
static
ERL_NIF_TERM enif_crypto_stream_KEYBYTES(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_stream_KEYBYTES);
@ -756,6 +766,61 @@ ERL_NIF_TERM enif_crypto_secretbox_open(ErlNifEnv *env, int argc, ERL_NIF_TERM c
padded_ciphertext.size - crypto_secretbox_ZEROBYTES);
}
static
ERL_NIF_TERM enif_crypto_stream_chacha20(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
ErlNifBinary c, n, k;
ErlNifUInt64 clen;
if (
(argc != 3) ||
(!enif_get_uint64(env, argv[0], &clen)) ||
(!enif_inspect_binary(env, argv[1], &n)) ||
(!enif_inspect_binary(env, argv[2], &k))) {
return enif_make_badarg(env);
}
if (
(k.size != crypto_stream_chacha20_KEYBYTES) ||
(n.size != crypto_stream_chacha20_NONCEBYTES)) {
return enif_make_badarg(env);
}
if (!enif_alloc_binary(clen, &c)) {
return nacl_error_tuple(env, "alloc_failed");
}
crypto_stream_chacha20(c.data, c.size, n.data, k.data);
return enif_make_binary(env, &c);
}
static
ERL_NIF_TERM enif_crypto_stream_chacha20_xor(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
ErlNifBinary c, m, n, k;
if (
(argc != 3) ||
(!enif_inspect_iolist_as_binary(env, argv[0], &m)) ||
(!enif_inspect_binary(env, argv[1], &n)) ||
(!enif_inspect_binary(env, argv[2], &k))) {
return enif_make_badarg(env);
}
if (
(k.size != crypto_stream_chacha20_KEYBYTES) ||
(n.size != crypto_stream_chacha20_NONCEBYTES)) {
return enif_make_badarg(env);
}
if (!enif_alloc_binary(m.size, &c)) {
return nacl_error_tuple(env, "alloc_failed");
}
crypto_stream_chacha20_xor(c.data, m.data, m.size, n.data, k.data);
return enif_make_binary(env, &c);
}
static
ERL_NIF_TERM enif_crypto_stream(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) {
ErlNifBinary c, n, k;
@ -1071,6 +1136,13 @@ static ErlNifFunc nif_funcs[] = {
{"crypto_secretbox_open_b", 3, enif_crypto_secretbox_open},
{"crypto_secretbox_open", 3, enif_crypto_secretbox_open, ERL_NIF_DIRTY_JOB_CPU_BOUND},
{"crypto_stream_chacha20_KEYBYTES", 0, enif_crypto_stream_chacha20_KEYBYTES},
{"crypto_stream_chacha20_NONCEBYTES", 0, enif_crypto_stream_chacha20_NONCEBYTES},
{"crypto_stream_chacha20_b", 3, enif_crypto_stream_chacha20},
{"crypto_stream_chacha20", 3, enif_crypto_stream_chacha20, ERL_NIF_DIRTY_JOB_CPU_BOUND},
{"crypto_stream_chacha20_xor_b", 3, enif_crypto_stream_chacha20_xor},
{"crypto_stream_chacha20_xor", 3, enif_crypto_stream_chacha20_xor, ERL_NIF_DIRTY_JOB_CPU_BOUND},
{"crypto_stream_KEYBYTES", 0, enif_crypto_stream_KEYBYTES},
{"crypto_stream_NONCEBYTES", 0, enif_crypto_stream_NONCEBYTES},
{"crypto_stream_b", 3, enif_crypto_stream},

View File

@ -49,6 +49,11 @@
secretbox/3,
secretbox_open/3,
stream_chacha20_key_size/0,
stream_chacha20_nonce_size/0,
stream_chacha20/3,
stream_chacha20_xor/3,
stream_key_size/0,
stream_nonce_size/0,
stream/3,
@ -129,6 +134,8 @@
-define(S_ZEROBYTES, <<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0>>). %% 32 bytes
-define(CRYPTO_SECRETBOX_BOXZEROBYTES, 16).
-define(S_BOXZEROBYTES, <<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0>>). %% 16 bytes
-define(CRYPTO_STREAM_CHACHA20_KEYBYTES, 32).
-define(CRYPTO_STREAM_CHACHA20_NONCEBYTES, 8).
-define(CRYPTO_STREAM_KEYBYTES, 32).
-define(CRYPTO_STREAM_NONCEBYTES, 24).
@ -141,6 +148,8 @@ verify() ->
?S_BOXZEROBYTES),
Verifiers = [
{crypto_stream_chacha20_KEYBYTES, ?CRYPTO_STREAM_CHACHA20_KEYBYTES},
{crypto_stream_chacha20_NONCEBYTES, ?CRYPTO_STREAM_CHACHA20_NONCEBYTES},
{crypto_stream_KEYBYTES, ?CRYPTO_STREAM_KEYBYTES},
{crypto_stream_NONCEBYTES, ?CRYPTO_STREAM_NONCEBYTES},
{crypto_box_ZEROBYTES, ?CRYPTO_BOX_ZEROBYTES},
@ -501,6 +510,63 @@ secretbox_nonce_size() ->
secretbox_key_size() ->
enacl_nif:crypto_secretbox_KEYBYTES().
%% @doc stream_chacha20_nonce_size/0 returns the byte size of the nonce for streams
%% @end
-spec stream_chacha20_nonce_size() -> pos_integer().
stream_chacha20_nonce_size() -> ?CRYPTO_STREAM_CHACHA20_NONCEBYTES.
%% @doc stream_key_size/0 returns the byte size of the key for streams
%% @end
-spec stream_chacha20_key_size() -> pos_integer().
stream_chacha20_key_size() -> ?CRYPTO_STREAM_CHACHA20_KEYBYTES.
%% @doc stream_chacha20/3 produces a cryptographic stream suitable for secret-key encryption
%%
%% <p>Given a positive `Len' a `Nonce' and a `Key', the stream_chacha20/3 function will return an unpredictable cryptographic stream of bytes
%% based on this output. In other words, the produced stream is indistinguishable from a random stream. Using this stream one
%% can XOR it with a message in order to produce a encrypted message.</p>
%% <p><b>Note:</b> You need to use different Nonce values for different messages. Otherwise the same stream is produced and thus
%% the messages will have predictability which in turn makes the encryption scheme fail.</p>
%% @end
-spec stream_chacha20(Len, Nonce, Key) -> CryptoStream
when
Len :: non_neg_integer(),
Nonce :: binary(),
Key :: binary(),
CryptoStream :: binary().
stream_chacha20(Len, Nonce, Key) when is_integer(Len), Len >= 0, Len =< ?STREAM_SIZE ->
bump(enacl_nif:crypto_stream_chacha20_b(Len, Nonce, Key),
?STREAM_REDUCTIONS,
?STREAM_SIZE,
Len);
stream_chacha20(Len, Nonce, Key) when is_integer(Len), Len >= 0 ->
enacl_nif:crypto_stream_chacha20(Len, Nonce, Key);
stream_chacha20(_, _, _) -> error(badarg).
%% @doc stream_chacha20_xor/3 encrypts a plaintext message into ciphertext
%%
%% The stream_chacha20_xor/3 function works by using the {@link stream_chacha20/3} api to XOR a message with the cryptographic stream. The same
%% caveat applies: the nonce must be new for each sent message or the system fails to work.
%% @end
-spec stream_chacha20_xor(Msg, Nonce, Key) -> CipherText
when
Msg :: iodata(),
Nonce :: binary(),
Key :: binary(),
CipherText :: binary().
stream_chacha20_xor(Msg, Nonce, Key) ->
case iolist_size(Msg) of
K when K =< ?STREAM_SIZE ->
bump(enacl_nif:crypto_stream_chacha20_xor_b(Msg, Nonce, Key),
?STREAM_REDUCTIONS,
?STREAM_SIZE,
K);
_ ->
enacl_nif:crypto_stream_chacha20_xor(Msg, Nonce, Key)
end.
%% @doc auth_key_size/0 returns the byte-size of the authentication key
%% @end
%% @doc stream_nonce_size/0 returns the byte size of the nonce for streams
%% @end
-spec stream_nonce_size() -> pos_integer().

View File

@ -52,6 +52,14 @@
crypto_secretbox_open/3,
crypto_secretbox_open_b/3,
crypto_stream_chacha20_KEYBYTES/0,
crypto_stream_chacha20_NONCEBYTES/0,
crypto_stream_chacha20/3,
crypto_stream_chacha20_b/3,
crypto_stream_chacha20_xor/3,
crypto_stream_chacha20_xor_b/3,
crypto_stream_KEYBYTES/0,
crypto_stream_NONCEBYTES/0,
@ -168,6 +176,13 @@ crypto_secretbox_b(_Msg, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).
crypto_secretbox_open(_Msg, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).
crypto_secretbox_open_b(_Msg, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).
crypto_stream_chacha20_KEYBYTES() -> erlang:nif_error(nif_not_loaded).
crypto_stream_chacha20_NONCEBYTES() -> erlang:nif_error(nif_not_loaded).
crypto_stream_chacha20(_Bytes, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).
crypto_stream_chacha20_b(_Bytes, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).
crypto_stream_chacha20_xor(_M, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).
crypto_stream_chacha20_xor_b(_M, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).
crypto_stream_KEYBYTES() -> erlang:nif_error(nif_not_loaded).
crypto_stream_NONCEBYTES() -> erlang:nif_error(nif_not_loaded).
crypto_stream(_Bytes, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).