Compare commits

..

No commits in common. "master" and "v1.1.0" have entirely different histories.

17 changed files with 92 additions and 147 deletions

View File

@ -6,21 +6,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
### Added ### Added
- Support for 448 DH function and Blake2s hash function.
### Changed ### Changed
- Using `crypto` over `enacl` (and removing a call to `get_stacktrace/1`) makes `enoise`
up to date for (at least) OTP-27.
- Added test dependency `eqwalizer_support` to enable checking types with Eqwalizer.
### Removed ### Removed
- The dependency on `enacl` is not needed anymore, OTP's `crypto` library now cover all
necessary operations.
## [1.2.0] - 2021-10-28 ## [4.3.1] - 2020-04-21
### Added ### Added
### Changed ### Changed
- Use the new AEAD crypto interface introduced in OTP 22. This makes `enoise` OPT 24 compatible - Fixed included compiler binary file, which was broken due to incorrect local system dependencies.
but it also means it no longer works on OTP 21 and earlier. You can't win them all. Because the aesophia version hasn't changed, the compiler in this release
- Fixed ChaChaPoly20 rekey continues to report as `v4.3.0`.
### Removed ### Removed
## [1.1.0] - 2020-09-24 ## [1.1.0] - 2020-09-24
@ -47,8 +41,7 @@ Initial version the following map describe what is supported:
, dh => [dh25519] } , dh => [dh25519] }
``` ```
[Unreleased]: https://github.com/aeternity/aesophia_cli/compare/v1.2.0...HEAD [Unreleased]: https://github.com/aeternity/aesophia_cli/compare/v1.1.0...HEAD
[1.2.0]: https://github.com/aeternity/aesophia_cli/compare/v1.1.0...v1.2.0
[1.1.0]: https://github.com/aeternity/aesophia_cli/compare/v1.0.1...v1.1.0 [1.1.0]: https://github.com/aeternity/aesophia_cli/compare/v1.0.1...v1.1.0
[1.0.1]: https://github.com/aeternity/aesophia_cli/compare/v1.0.0...v1.0.1 [1.0.1]: https://github.com/aeternity/aesophia_cli/compare/v1.0.0...v1.0.1
[1.0.0]: https://github.com/aeternity/enoise/releases/tag/v1.0.0 [1.0.0]: https://github.com/aeternity/enoise/releases/tag/v1.0.0

View File

@ -39,9 +39,3 @@ Test
---- ----
$ rebar3 eunit $ rebar3 eunit
Typecheck
---------
$ rebar3 dialyzer
$ elp --eqwalize-all --rebar

View File

@ -1,10 +1,8 @@
{erl_opts, [debug_info]}. {erl_opts, [debug_info]}.
{plugins, [rebar3_hex]}. {plugins, [rebar3_hex]}.
{deps, [{enacl, "1.1.1"}]}.
{profiles, [{test, [{deps, [ {jsx, {git, "https://github.com/talentdeficit/jsx.git", {tag, "2.8.0"}}} {profiles, [{test, [{deps, [{jsx, {git, "https://github.com/talentdeficit/jsx.git", {tag, "2.8.0"}}}]}]}
, {eqwalizer_support, {git_subdir, "https://github.com/whatsapp/eqwalizer.git", {branch, "main"}, "eqwalizer_support"}}
]}
]}
]}. ]}.
{xref_checks, [undefined_function_calls, undefined_functions, {xref_checks, [undefined_function_calls, undefined_functions,

View File

@ -1 +1,6 @@
[]. {"1.1.0",
[{<<"enacl">>,{pkg,<<"enacl">>,<<"1.1.1">>},0}]}.
[
{pkg_hash,[
{<<"enacl">>, <<"F65DC64D9BFF2D8A534CB77AEF14DA5E7A2FA148987D87856F79A4745C9C2627">>}]}
].

View File

@ -1,11 +1,11 @@
{application, enoise, {application, enoise,
[{description, "An Erlang implementation of the Noise protocol"}, [{description, "An Erlang implementation of the Noise protocol"},
{vsn, "1.2.0"}, {vsn, "1.1.0"},
{registered, []}, {registered, []},
{applications, {applications,
[kernel, [kernel,
stdlib, stdlib,
crypto enacl
]}, ]},
{env,[]}, {env,[]},
{modules, []}, {modules, []},

View File

@ -87,7 +87,8 @@ binary().
Role :: enoise_hs_state:noise_role()) -> Role :: enoise_hs_state:noise_role()) ->
{ok, enoise_hs_state:state()} | {error, term()}. {ok, enoise_hs_state:state()} | {error, term()}.
handshake(Options, Role) -> handshake(Options, Role) ->
create_hstate(Options, Role). HState = create_hstate(Options, Role),
{ok, HState}.
%% @doc Do a step (either `{send, Payload}', `{rcvd, EncryptedData}', %% @doc Do a step (either `{send, Payload}', `{rcvd, EncryptedData}',
%% or `done') %% or `done')
@ -108,13 +109,10 @@ step_handshake(HState, Data) ->
ComState :: noise_com_state()) -> ComState :: noise_com_state()) ->
{ok, noise_split_state(), noise_com_state()} | {error, term()}. {ok, noise_split_state(), noise_com_state()} | {error, term()}.
handshake(Options, Role, ComState) -> handshake(Options, Role, ComState) ->
case create_hstate(Options, Role) of HState = create_hstate(Options, Role),
{ok, HState} -> Timeout = proplists:get_value(timeout, Options, infinity),
Timeout = proplists:get_value(timeout, Options, infinity), do_handshake(HState, ComState, Timeout).
do_handshake(HState, ComState, Timeout);
Err = {error, _} ->
Err
end.
%% @doc Upgrades a gen_tcp, or equivalent, connected socket to a Noise socket, %% @doc Upgrades a gen_tcp, or equivalent, connected socket to a Noise socket,
%% that is, performs the client-side noise handshake. %% that is, performs the client-side noise handshake.
@ -272,16 +270,15 @@ create_hstate(Options, Role) ->
enoise_protocol:from_name(X); enoise_protocol:from_name(X);
_ -> NoiseProtocol0 _ -> NoiseProtocol0
end, end,
DH = enoise_protocol:dh(NoiseProtocol),
S = proplists:get_value(s, Options, undefined), S = proplists:get_value(s, Options, undefined),
E = proplists:get_value(e, Options, undefined), E = proplists:get_value(e, Options, undefined),
RS = remote_keypair(DH, proplists:get_value(rs, Options, undefined)), RS = proplists:get_value(rs, Options, undefined),
RE = remote_keypair(DH, proplists:get_value(re, Options, undefined)), RE = proplists:get_value(re, Options, undefined),
enoise_hs_state:init(NoiseProtocol, Role, enoise_hs_state:init(NoiseProtocol, Role,
Prologue, {S, E, RS, RE}). Prologue, {S, E, RS, RE}).
check_gen_tcp(TcpSock) -> check_gen_tcp(TcpSock) ->
case inet:getopts(TcpSock, [mode, packet, active, header, packet_size]) of case inet:getopts(TcpSock, [mode, packet, active, header, packet_size]) of
{ok, TcpOpts} -> {ok, TcpOpts} ->
@ -324,5 +321,3 @@ gen_tcp_rcv_msg({TcpSock, Active, Buf}, Timeout) ->
{error, timeout} {error, timeout}
end. end.
remote_keypair(_DH, undefined) -> undefined;
remote_keypair(DH, RemotePub) when is_binary(RemotePub) -> enoise_keypair:new(DH, RemotePub).

View File

@ -54,8 +54,12 @@ set_nonce(CState = #noise_cs{}, Nonce) ->
encrypt_with_ad(CState = #noise_cs{ k = empty }, _AD, PlainText) -> encrypt_with_ad(CState = #noise_cs{ k = empty }, _AD, PlainText) ->
{ok, CState, PlainText}; {ok, CState, PlainText};
encrypt_with_ad(CState = #noise_cs{ k = K, n = N, cipher = Cipher }, AD, PlainText) -> encrypt_with_ad(CState = #noise_cs{ k = K, n = N, cipher = Cipher }, AD, PlainText) ->
CipherText = enoise_crypto:encrypt(Cipher, K, N, AD, PlainText), case enoise_crypto:encrypt(Cipher, K, N, AD, PlainText) of
{ok, CState#noise_cs{ n = N+1 }, CipherText}. Encrypted when is_binary(Encrypted) ->
{ok, CState#noise_cs{ n = N+1 }, Encrypted};
Err = {error, _} ->
Err
end.
-spec decrypt_with_ad(CState :: state(), AD :: binary(), CipherText :: binary()) -> -spec decrypt_with_ad(CState :: state(), AD :: binary(), CipherText :: binary()) ->
{ok, state(), binary()} | {error, term()}. {ok, state(), binary()} | {error, term()}.
@ -70,8 +74,6 @@ decrypt_with_ad(CState = #noise_cs{ k = K, n = N, cipher = Cipher }, AD, CipherT
end. end.
-spec rekey(CState :: state()) -> state(). -spec rekey(CState :: state()) -> state().
rekey(CState = #noise_cs{ k = empty }) ->
CState;
rekey(CState = #noise_cs{ k = K, cipher = Cipher }) -> rekey(CState = #noise_cs{ k = K, cipher = Cipher }) ->
CState#noise_cs{ k = enoise_crypto:rekey(Cipher, K) }. CState#noise_cs{ k = enoise_crypto:rekey(Cipher, K) }.

View File

@ -29,18 +29,13 @@
%% @doc Perform a Diffie-Hellman calculation with the secret key from `Key1' %% @doc Perform a Diffie-Hellman calculation with the secret key from `Key1'
%% and the public key from `Key2' with algorithm `Algo'. %% and the public key from `Key2' with algorithm `Algo'.
-spec dh(Algo :: enoise_hs_state:noise_dh(), -spec dh(Algo :: enoise_hs_state:noise_dh(),
Key1:: keypair(), Key2 :: keypair()) -> binary(). Key1:: keypair(), Key2 :: keypair()) -> binary().
dh(Type, Key1, Key2) when Type == dh25519; Type == dh448 -> dh(dh25519, Key1, Key2) ->
dh_(ecdh_type(Type), enoise_keypair:pubkey(Key2), enoise_keypair:seckey(Key1)); enacl:curve25519_scalarmult( enoise_keypair:seckey(Key1)
, enoise_keypair:pubkey(Key2));
dh(Type, _Key1, _Key2) -> dh(Type, _Key1, _Key2) ->
error({unsupported_diffie_hellman, Type}). error({unsupported_diffie_hellman, Type}).
ecdh_type(dh25519) -> x25519;
ecdh_type(dh448) -> x448.
dh_(DHType, OtherPub, MyPriv) ->
crypto:compute_key(ecdh, OtherPub, MyPriv, DHType).
-spec hmac(Hash :: enoise_sym_state:noise_hash(), -spec hmac(Hash :: enoise_sym_state:noise_hash(),
Key :: binary(), Data :: binary()) -> binary(). Key :: binary(), Data :: binary()) -> binary().
hmac(Hash, Key, Data) -> hmac(Hash, Key, Data) ->
@ -59,42 +54,43 @@ hkdf(Hash, Key, Data) ->
Output3 = hmac(Hash, TempKey, <<Output2/binary, 3:8>>), Output3 = hmac(Hash, TempKey, <<Output2/binary, 3:8>>),
[Output1, Output2, Output3]. [Output1, Output2, Output3].
-spec rekey(Cipher :: enoise_cipher_state:noise_cipher(), Key :: binary()) -> binary(). -spec rekey(Cipher :: enoise_cipher_state:noise_cipher(),
rekey('ChaChaPoly', K0) -> Key :: binary()) -> binary() | {error, term()}.
KLen = 32,
<<K:KLen/binary, _/binary>> = encrypt('ChaChaPoly', K0, ?MAX_NONCE, <<>>, <<0:(32*8)>>),
K;
rekey(Cipher, K) -> rekey(Cipher, K) ->
encrypt(Cipher, K, ?MAX_NONCE, <<>>, <<0:(32*8)>>). encrypt(Cipher, K, ?MAX_NONCE, <<>>, <<0:(32*8)>>).
-spec encrypt(Cipher :: enoise_cipher_state:noise_cipher(), Key :: binary(), -spec encrypt(Cipher :: enoise_cipher_state:noise_cipher(),
Nonce :: non_neg_integer(), Ad :: binary(), PlainText :: binary()) -> binary(). Key :: binary(), Nonce :: non_neg_integer(),
encrypt(Cipher, K, N, Ad, PlainText) -> Ad :: binary(), PlainText :: binary()) ->
{CText, CTag} = crypto:crypto_one_time_aead(cipher(Cipher), K, nonce(Cipher, N), PlainText, Ad, true), binary() | {error, term()}.
<<CText/binary, CTag/binary>>. encrypt('ChaChaPoly', K, N, Ad, PlainText) ->
Nonce = <<0:32, N:64/little-unsigned-integer>>,
enacl:aead_chacha20poly1305_ietf_encrypt(PlainText, Ad, Nonce, K);
encrypt('AESGCM', K, N, Ad, PlainText) ->
Nonce = <<0:32, N:64>>,
{CipherText, CipherTag} = crypto:block_encrypt(aes_gcm, K, Nonce, {Ad, PlainText}),
<<CipherText/binary, CipherTag/binary>>.
-spec decrypt(Cipher ::enoise_cipher_state:noise_cipher(), Key :: binary(), -spec decrypt(Cipher ::enoise_cipher_state:noise_cipher(),
Nonce :: non_neg_integer(), AD :: binary(), Key :: binary(), Nonce :: non_neg_integer(),
CipherText :: binary()) -> binary() | {error, term()}. AD :: binary(), CipherText :: binary()) ->
decrypt(Cipher, K, N, Ad, CipherText0) -> binary() | {error, term()}.
decrypt('ChaChaPoly', K, N, Ad, CipherText) ->
Nonce = <<0:32, N:64/little-unsigned-integer>>,
enacl:aead_chacha20poly1305_ietf_decrypt(CipherText, Ad, Nonce, K);
decrypt('AESGCM', K, N, Ad, CipherText0) ->
CTLen = byte_size(CipherText0) - ?MAC_LEN, CTLen = byte_size(CipherText0) - ?MAC_LEN,
<<CText:CTLen/binary, MAC:?MAC_LEN/binary>> = CipherText0, <<CipherText:CTLen/binary, MAC:?MAC_LEN/binary>> = CipherText0,
case crypto:crypto_one_time_aead(cipher(Cipher), K, nonce(Cipher, N), CText, Ad, MAC, false) of Nonce = <<0:32, N:64>>,
case crypto:block_decrypt(aes_gcm, K, Nonce, {Ad, CipherText, MAC}) of
error -> {error, decrypt_failed}; error -> {error, decrypt_failed};
Data -> Data Data -> Data
end. end.
nonce('ChaChaPoly', N) -> <<0:32, N:64/little-unsigned-integer>>;
nonce('AESGCM', N) -> <<0:32, N:64/big-unsigned-integer>>.
cipher('ChaChaPoly') -> chacha20_poly1305;
cipher('AESGCM') -> aes_256_gcm.
-spec hash(Hash :: enoise_sym_state:noise_hash(), Data :: binary()) -> binary(). -spec hash(Hash :: enoise_sym_state:noise_hash(), Data :: binary()) -> binary().
hash(blake2s, Data) ->
crypto:hash(blake2s, Data);
hash(blake2b, Data) -> hash(blake2b, Data) ->
crypto:hash(blake2b, Data); Hash = enacl:generichash(64, Data), Hash;
hash(sha256, Data) -> hash(sha256, Data) ->
crypto:hash(sha256, Data); crypto:hash(sha256, Data);
hash(sha512, Data) -> hash(sha512, Data) ->

View File

@ -26,8 +26,6 @@
hs_hash := binary(), hs_hash := binary(),
final_state => state() }. final_state => state() }.
-type optional_key() :: undefined | keypair().
-type initial_keys() :: {optional_key(), optional_key(), optional_key(), optional_key()}.
-record(noise_hs, { ss :: enoise_sym_state:state() -record(noise_hs, { ss :: enoise_sym_state:state()
, s :: keypair() | undefined , s :: keypair() | undefined
@ -41,8 +39,11 @@
-opaque state() :: #noise_hs{}. -opaque state() :: #noise_hs{}.
-export_type([noise_dh/0, noise_role/0, noise_split_state/0, noise_token/0, state/0]). -export_type([noise_dh/0, noise_role/0, noise_split_state/0, noise_token/0, state/0]).
-spec init(Protocol :: enoise_protocol:protocol(), Role :: noise_role(), -spec init(Protocol :: string() | enoise_protocol:protocol(),
Prologue :: binary(), Keys :: initial_keys()) -> {ok, state()} | {error, term()}. Role :: noise_role(), Prologue :: binary(),
Keys :: term()) -> state().
init(ProtocolName, Role, Prologue, Keys) when is_list(ProtocolName) ->
init(enoise_protocol:from_name(ProtocolName), Role, Prologue, Keys);
init(Protocol, Role, Prologue, {S, E, RS, RE}) -> init(Protocol, Role, Prologue, {S, E, RS, RE}) ->
SS0 = enoise_sym_state:init(Protocol), SS0 = enoise_sym_state:init(Protocol),
SS1 = enoise_sym_state:mix_hash(SS0, Prologue), SS1 = enoise_sym_state:mix_hash(SS0, Prologue),
@ -52,19 +53,11 @@ init(Protocol, Role, Prologue, {S, E, RS, RE}) ->
, dh = enoise_protocol:dh(Protocol) , dh = enoise_protocol:dh(Protocol)
, msgs = enoise_protocol:msgs(Role, Protocol) }, , msgs = enoise_protocol:msgs(Role, Protocol) },
PreMsgs = enoise_protocol:pre_msgs(Role, Protocol), PreMsgs = enoise_protocol:pre_msgs(Role, Protocol),
pre_mix(PreMsgs, HS). lists:foldl(fun({out, [s]}, HS0) -> mix_hash(HS0, enoise_keypair:pubkey(S));
({out, [e]}, HS0) -> mix_hash(HS0, enoise_keypair:pubkey(E));
pre_mix([], HS) -> {ok, HS}; ({in, [s]}, HS0) -> mix_hash(HS0, enoise_keypair:pubkey(RS));
pre_mix([{out, [s]} | Msgs], HS = #noise_hs{ s = S }) when S /= undefined -> ({in, [e]}, HS0) -> mix_hash(HS0, enoise_keypair:pubkey(RE))
pre_mix(Msgs, mix_hash(HS, enoise_keypair:pubkey(S))); end, HS, PreMsgs).
pre_mix([{out, [e]} | Msgs], HS = #noise_hs{ e = E }) when E /= undefined ->
pre_mix(Msgs, mix_hash(HS, enoise_keypair:pubkey(E)));
pre_mix([{in, [s]} | Msgs], HS = #noise_hs{ rs = RS }) when RS /= undefined ->
pre_mix(Msgs, mix_hash(HS, enoise_keypair:pubkey(RS)));
pre_mix([{in, [e]} | Msgs], HS = #noise_hs{ re = RE }) when RE /= undefined ->
pre_mix(Msgs, mix_hash(HS, enoise_keypair:pubkey(RE)));
pre_mix(_Msg, _HS) ->
{error, invalid_noise_setup}.
-spec finalize(HS :: state()) -> {ok, noise_split_state()} | {error, term()}. -spec finalize(HS :: state()) -> {ok, noise_split_state()} | {error, term()}.
finalize(HS = #noise_hs{ msgs = [], ss = SS, role = Role }) -> finalize(HS = #noise_hs{ msgs = [], ss = SS, role = Role }) ->
@ -97,7 +90,7 @@ read_message(HS = #noise_hs{ msgs = [{in, Msg} | Msgs] }, Message) ->
Err = {error, _} -> Err Err = {error, _} -> Err
end. end.
-spec remote_keys(HS :: state()) -> undefined | keypair(). -spec remote_keys(HS :: state()) -> keypair().
remote_keys(#noise_hs{ rs = RS }) -> remote_keys(#noise_hs{ rs = RS }) ->
RS. RS.

View File

@ -30,7 +30,7 @@
%% @doc Generate a new keypair of type `Type'. %% @doc Generate a new keypair of type `Type'.
-spec new(Type :: key_type()) -> keypair(). -spec new(Type :: key_type()) -> keypair().
new(Type) -> new(Type) ->
{Pub, Sec} = new_key_pair(Type), {Sec, Pub} = new_key_pair(Type),
#kp{ type = Type, sec = Sec, pub = Pub }. #kp{ type = Type, sec = Sec, pub = Pub }.
%% @doc Create a new keypair of type `Type'. If `Public' is `undefined' %% @doc Create a new keypair of type `Type'. If `Public' is `undefined'
@ -69,14 +69,12 @@ seckey(#kp{ sec = S }) ->
S. S.
%% -- Local functions -------------------------------------------------------- %% -- Local functions --------------------------------------------------------
new_key_pair(Type) when Type == dh25519; Type == dh448 -> new_key_pair(dh25519) ->
crypto:generate_key(ecdh, ecdh_type(Type)); KeyPair = enacl:crypto_sign_ed25519_keypair(),
{enacl:crypto_sign_ed25519_secret_to_curve25519(maps:get(secret, KeyPair)),
enacl:crypto_sign_ed25519_public_to_curve25519(maps:get(public, KeyPair))};
new_key_pair(Type) -> new_key_pair(Type) ->
error({unsupported_key_type, Type}). error({unsupported_key_type, Type}).
pubkey_from_secret(Type, Secret) when Type == dh25519; Type == dh448 -> pubkey_from_secret(dh25519, Secret) ->
{Public, Secret} = crypto:generate_key(ecdh, ecdh_type(Type), Secret), enacl:curve25519_scalarmult_base(Secret).
Public.
ecdh_type(dh25519) -> x25519;
ecdh_type(dh448) -> x448.

View File

@ -19,7 +19,7 @@
, to_name/1]). , to_name/1]).
-ifdef(TEST). -ifdef(TEST).
-export([to_name/4, from_name_pattern/1, to_name_pattern/1]). -export([to_name/4]).
-endif. -endif.
-type noise_pattern() :: nn | kn | nk | kk | nx | kx | xn | in | xk | ik | xx | ix. -type noise_pattern() :: nn | kn | nk | kk | nx | kx | xn | in | xk | ik | xx | ix.
@ -137,9 +137,9 @@ supported_dh(Dh) ->
-spec supported() -> map(). -spec supported() -> map().
supported() -> supported() ->
#{ hs_pattern => [nn, kn, nk, kk, nx, kx, xn, in, xk, ik, xx, ix] #{ hs_pattern => [nn, kn, nk, kk, nx, kx, xn, in, xk, ik, xx, ix]
, hash => [blake2s, blake2b, sha256, sha512] , hash => [blake2b, sha256, sha512]
, cipher => ['ChaChaPoly', 'AESGCM'] , cipher => ['ChaChaPoly', 'AESGCM']
, dh => [dh25519, dh448] , dh => [dh25519]
}. }.
to_name(Pattern, Dh, Cipher, Hash) -> to_name(Pattern, Dh, Cipher, Hash) ->
@ -148,16 +148,16 @@ to_name(Pattern, Dh, Cipher, Hash) ->
to_name_pattern(Atom) -> to_name_pattern(Atom) ->
[Simple | Rest] = string:lexemes(atom_to_list(Atom), "_"), [Simple | Rest] = string:lexemes(atom_to_list(Atom), "_"),
lists:flatten(string:uppercase(Simple) ++ lists:join("+", Rest)). string:uppercase(Simple) ++ lists:join("+", Rest).
from_name_pattern(String) -> from_name_pattern(String) ->
[Init | Mod2] = string:lexemes(String, "+"), [Init | Mod2] = string:lexemes(String, "+"),
{Simple, Mod1} = lists:splitwith(fun(C) -> C >= $A andalso C =< $Z end, Init), {Simple, Mod1} = lists:splitwith(fun(C) -> C >= $A andalso C =< $Z end, Init),
list_to_atom(lists:flatten(string:lowercase(Simple) ++ list_to_atom(string:lowercase(Simple) ++
case Mod1 of case Mod1 of
"" -> ""; "" -> "";
_ -> "_" ++ lists:join("_", [Mod1 | Mod2]) _ -> "_" ++ lists:join([Mod1 | Mod2], "_")
end)). end).
to_name_dh(dh25519) -> "25519"; to_name_dh(dh25519) -> "25519";
to_name_dh(dh448) -> "448". to_name_dh(dh448) -> "448".

View File

@ -26,14 +26,5 @@ chachapoly_test() ->
enoise_cipher_state:decrypt_with_ad(CS1, AD, <<CipherText/binary, MAC/binary>>), enoise_cipher_state:decrypt_with_ad(CS1, AD, <<CipherText/binary, MAC/binary>>),
?assertMatch(PlainText, PlainText0), ?assertMatch(PlainText, PlainText0),
% rekey test
CS4 = enoise_cipher_state:rekey(CS1),
{ok, _CS5, <<CipherText1:CTLen/binary, MAC1:MACLen/binary>>} =
enoise_cipher_state:encrypt_with_ad(CS4, AD, PlainText),
{ok, _CS6, <<PlainText1:PTLen/binary>>} =
enoise_cipher_state:decrypt_with_ad(CS4, AD, <<CipherText1/binary, MAC1/binary>>),
?assertMatch(PlainText, PlainText1),
ok. ok.

View File

@ -44,13 +44,6 @@ chachapoly_test() ->
enoise_crypto:decrypt('ChaChaPoly', Key, Nonce, AD, <<CipherText/binary, MAC/binary>>), enoise_crypto:decrypt('ChaChaPoly', Key, Nonce, AD, <<CipherText/binary, MAC/binary>>),
?assertMatch(PlainText, PlainText0), ?assertMatch(PlainText, PlainText0),
Key1 = enoise_crypto:rekey('ChaChaPoly', Key),
<<CipherText1:CTLen/binary, MAC1:MACLen/binary>> =
enoise_crypto:encrypt('ChaChaPoly', Key1, Nonce, AD, PlainText),
<<PlainText1:PTLen/binary>> =
enoise_crypto:decrypt('ChaChaPoly', Key1, Nonce, AD, <<CipherText1/binary, MAC1/binary>>),
?assertMatch(PlainText, PlainText1),
ok. ok.
blake2b_test() -> blake2b_test() ->

View File

@ -43,8 +43,7 @@ noise_test(_Name, Protocol, Init, Resp, Messages, HSHash) ->
SecK = fun(undefined) -> undefined; (Sec) -> enoise_keypair:new(DH, Sec, undefined) end, SecK = fun(undefined) -> undefined; (Sec) -> enoise_keypair:new(DH, Sec, undefined) end,
PubK = fun(undefined) -> undefined; (Pub) -> enoise_keypair:new(DH, Pub) end, PubK = fun(undefined) -> undefined; (Pub) -> enoise_keypair:new(DH, Pub) end,
HSInit = fun(P, R, #{ e := E, s := S, rs := RS, prologue := PL }) -> HSInit = fun(P, R, #{ e := E, s := S, rs := RS, prologue := PL }) ->
{ok, HS} = enoise_hs_state:init(P, R, PL, {SecK(S), SecK(E), PubK(RS), undefined}), enoise_hs_state:init(P, R, PL, {SecK(S), SecK(E), PubK(RS), undefined})
HS
end, end,
InitHS = HSInit(Protocol, initiator, Init), InitHS = HSInit(Protocol, initiator, Init),

View File

@ -7,18 +7,5 @@
-include_lib("eunit/include/eunit.hrl"). -include_lib("eunit/include/eunit.hrl").
name_test() -> name_test() ->
roundtrip("Noise_XK_25519_ChaChaPoly_SHA512"), ?assertMatch(<<"Noise_XK_25519_ChaChaPoly_SHA512">>,
roundtrip("Noise_NN_25519_AESGCM_BLAKE2b"). enoise_protocol:to_name(enoise_protocol:from_name("Noise_XK_25519_ChaChaPoly_SHA512"))).
name2_test() ->
Name = "Noise_NXpsk2_25519_AESGCM_SHA512",
?assertError({name_not_recognized, Name}, enoise_protocol:from_name(Name)).
name_pattern_test() ->
Pat = "XKfallback+psk0",
RoundPat = enoise_protocol:to_name_pattern(enoise_protocol:from_name_pattern(Pat)),
?assertEqual(Pat, RoundPat).
roundtrip(Name) ->
ExpectedName = iolist_to_binary(Name),
?assertMatch(ExpectedName, enoise_protocol:to_name(enoise_protocol:from_name(Name))).

View File

@ -41,9 +41,10 @@ noise_interactive(V = #{ protocol_name := Name }) ->
noise_interactive(_Name, Protocol, Init, Resp, Messages, HSHash) -> noise_interactive(_Name, Protocol, Init, Resp, Messages, HSHash) ->
DH = enoise_protocol:dh(Protocol), DH = enoise_protocol:dh(Protocol),
SecK = fun(undefined) -> undefined; (Sec) -> enoise_keypair:new(DH, Sec, undefined) end, SecK = fun(undefined) -> undefined; (Sec) -> enoise_keypair:new(DH, Sec, undefined) end,
PubK = fun(undefined) -> undefined; (Pub) -> enoise_keypair:new(DH, Pub) end,
HSInit = fun(#{ e := E, s := S, rs := RS, prologue := PL }, R) -> HSInit = fun(#{ e := E, s := S, rs := RS, prologue := PL }, R) ->
Opts = [{noise, Protocol}, {s, SecK(S)}, {e, SecK(E)}, {rs, RS}, {prologue, PL}], Opts = [{noise, Protocol}, {s, SecK(S)}, {e, SecK(E)}, {rs, PubK(RS)}, {prologue, PL}],
enoise:handshake(Opts, R) enoise:handshake(Opts, R)
end, end,
{ok, InitHS} = HSInit(Init, initiator), {ok, InitHS} = HSInit(Init, initiator),
@ -148,12 +149,12 @@ noise_test_run_(Conf, SKP, CKP) ->
Protocol = enoise_protocol:from_name(Conf), Protocol = enoise_protocol:from_name(Conf),
Port = 4556, Port = 4556,
SrvOpts = [{echos, 2}, {cpub, enoise_keypair:pubkey(CKP)}], SrvOpts = [{echos, 2}, {cpub, CKP}],
EchoSrv = enoise_utils:echo_srv_start(Port, Protocol, SKP, SrvOpts), EchoSrv = enoise_utils:echo_srv_start(Port, Protocol, SKP, SrvOpts),
{ok, TcpSock} = gen_tcp:connect("localhost", Port, [{active, once}, binary, {reuseaddr, true}], 100), {ok, TcpSock} = gen_tcp:connect("localhost", Port, [{active, once}, binary, {reuseaddr, true}], 100),
Opts = [{noise, Protocol}, {s, CKP}] ++ [{rs, enoise_keypair:pubkey(SKP)} || enoise_utils:need_rs(initiator, Conf) ], Opts = [{noise, Protocol}, {s, CKP}] ++ [{rs, SKP} || enoise_utils:need_rs(initiator, Conf) ],
{ok, EConn, _} = enoise:connect(TcpSock, Opts), {ok, EConn, _} = enoise:connect(TcpSock, Opts),
ok = enoise:send(EConn, <<"Hello World!">>), ok = enoise:send(EConn, <<"Hello World!">>),

View File

@ -26,7 +26,7 @@ echo_srv(Port, Protocol, SKP, SrvOpts) ->
AcceptRes = AcceptRes =
try try
enoise:accept(TcpSock, Opts) enoise:accept(TcpSock, Opts)
catch _:R:S -> gen_tcp:close(TcpSock), {error, {R, S}} end, catch _:R -> gen_tcp:close(TcpSock), {error, {R, erlang:get_stacktrace()}} end,
gen_tcp:close(LSock), gen_tcp:close(LSock),