Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 991d7390ea | |||
| 83fa0d5a00 | |||
| 336b331b8a | |||
| fc4a41f13d | |||
| 3819ba5c0f | |||
| 98d18bcaa5 | |||
| a3e803fc1a | |||
| 1e6ee6703f | |||
| 7c7ad54a6a |
@@ -0,0 +1,47 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
### Added
|
||||
### Changed
|
||||
### Removed
|
||||
|
||||
## [4.3.1] - 2020-04-21
|
||||
### Added
|
||||
### Changed
|
||||
- Fixed included compiler binary file, which was broken due to incorrect local system dependencies.
|
||||
Because the aesophia version hasn't changed, the compiler in this release
|
||||
continues to report as `v4.3.0`.
|
||||
### Removed
|
||||
|
||||
## [1.1.0] - 2020-09-24
|
||||
### Added
|
||||
Include [Cacaphony](https://github.com/centromere/cacophony) test vectors.
|
||||
### Changed
|
||||
Updated `enacl` to version [1.1.1](https://github.com/jlouis/enacl/releases/tag/v1.1.1).
|
||||
Fixed some imprecise type specifications.
|
||||
### Removed
|
||||
|
||||
## [1.0.1] - 2018-12-21
|
||||
### Added
|
||||
### Changed
|
||||
Improved argument checks and error handling in handshake (in particular related to empty
|
||||
hand shake messages).
|
||||
### Removed
|
||||
|
||||
## [1.0] - 2018-10-09
|
||||
Initial version the following map describe what is supported:
|
||||
```
|
||||
#{ hs_pattern => [nn, kn, nk, kk, nx, kx, xn, in, xk, ik, xx, ix]
|
||||
, hash => [blake2b, sha256, sha512]
|
||||
, cipher => ['ChaChaPoly', 'AESGCM']
|
||||
, dh => [dh25519] }
|
||||
```
|
||||
|
||||
[Unreleased]: https://github.com/aeternity/aesophia_cli/compare/v1.1.0...HEAD
|
||||
[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.0]: https://github.com/aeternity/enoise/releases/tag/v1.0.0
|
||||
+2
-1
@@ -1,6 +1,6 @@
|
||||
{erl_opts, [debug_info]}.
|
||||
{plugins, [rebar3_hex]}.
|
||||
{deps, [{enacl, "0.17.2"}]}.
|
||||
{deps, [{enacl, "1.1.1"}]}.
|
||||
|
||||
{profiles, [{test, [{deps, [{jsx, {git, "https://github.com/talentdeficit/jsx.git", {tag, "2.8.0"}}}]}]}
|
||||
]}.
|
||||
@@ -9,3 +9,4 @@
|
||||
locals_not_used,
|
||||
deprecated_function_calls, deprecated_functions]}.
|
||||
|
||||
{dialyzer, [{warnings, [unknown]}]}.
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{"1.1.0",
|
||||
[{<<"enacl">>,{pkg,<<"enacl">>,<<"0.17.2">>},0}]}.
|
||||
[{<<"enacl">>,{pkg,<<"enacl">>,<<"1.1.1">>},0}]}.
|
||||
[
|
||||
{pkg_hash,[
|
||||
{<<"enacl">>, <<"4AD59142943E72D72C56E33C30DEDEF28ADD8EBEE79C51033562B0CB4B93EDE0">>}]}
|
||||
{<<"enacl">>, <<"F65DC64D9BFF2D8A534CB77AEF14DA5E7A2FA148987D87856F79A4745C9C2627">>}]}
|
||||
].
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{application, enoise,
|
||||
[{description, "An Erlang implementation of the Noise protocol"},
|
||||
{vsn, "1.0.1"},
|
||||
{vsn, "1.1.0"},
|
||||
{registered, []},
|
||||
{applications,
|
||||
[kernel,
|
||||
|
||||
+3
-5
@@ -64,11 +64,9 @@ binary().
|
||||
send_msg := send_msg_fun(),
|
||||
state := term() }.
|
||||
%% Noise communication state - used to parameterize a handshake. Consists of a
|
||||
%% send function one receive function and an internal state.
|
||||
%% send function, one receive function, and an internal state.
|
||||
|
||||
-type noise_split_state() :: #{ rx := enoise_cipher_state:state(),
|
||||
tx := enoise_cipher_state:state(),
|
||||
hs_hash := binary() }.
|
||||
-type noise_split_state() :: enoise_hs_state:noise_split_state().
|
||||
%% Return value from the final `split' operation. Provides a CipherState for
|
||||
%% receiving and a CipherState transmission. Also includes the final handshake
|
||||
%% hash for channel binding.
|
||||
@@ -140,7 +138,7 @@ connect(TcpSock, Options) ->
|
||||
%% @end
|
||||
-spec accept(TcpSock :: gen_tcp:socket(),
|
||||
Options :: noise_options()) ->
|
||||
{ok, noise_socket()} | {error, term()}.
|
||||
{ok, noise_socket(), enoise_hs_state:state()} | {error, term()}.
|
||||
accept(TcpSock, Options) ->
|
||||
tcp_handshake(TcpSock, responder, Options).
|
||||
|
||||
|
||||
@@ -50,11 +50,16 @@ set_nonce(CState = #noise_cs{}, Nonce) ->
|
||||
CState#noise_cs{ n = Nonce }.
|
||||
|
||||
-spec encrypt_with_ad(CState :: state(), AD :: binary(), PlainText :: binary()) ->
|
||||
{ok, state(), binary()}.
|
||||
{ok, state(), binary()} | {error, term()}.
|
||||
encrypt_with_ad(CState = #noise_cs{ k = empty }, _AD, PlainText) ->
|
||||
{ok, CState, PlainText};
|
||||
encrypt_with_ad(CState = #noise_cs{ k = K, n = N, cipher = Cipher }, AD, PlainText) ->
|
||||
{ok, CState#noise_cs{ n = N+1 }, enoise_crypto:encrypt(Cipher, K, N, AD, PlainText)}.
|
||||
case enoise_crypto:encrypt(Cipher, K, N, AD, PlainText) of
|
||||
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()) ->
|
||||
{ok, state(), binary()} | {error, term()}.
|
||||
|
||||
@@ -53,15 +53,19 @@ start_link(TcpSock, Rx, Tx, Owner, {Active0, Buf}) ->
|
||||
Err
|
||||
end.
|
||||
|
||||
-spec send(Noise :: pid(), Data :: binary()) -> ok | {error, term()}.
|
||||
send(Noise, Data) ->
|
||||
gen_server:call(Noise, {send, Data}).
|
||||
|
||||
-spec set_active(Noise :: pid(), Active :: true | once) -> ok | {error, term()}.
|
||||
set_active(Noise, Active) ->
|
||||
gen_server:call(Noise, {active, self(), Active}).
|
||||
|
||||
-spec close(Noise :: pid()) -> ok | {error, term()}.
|
||||
close(Noise) ->
|
||||
gen_server:call(Noise, close).
|
||||
|
||||
-spec controlling_process(Noise :: pid(), NewPid :: pid()) -> ok | {error, term()}.
|
||||
controlling_process(Noise, NewPid) ->
|
||||
gen_server:call(Noise, {controlling_process, self(), NewPid}, 100).
|
||||
|
||||
|
||||
+10
-5
@@ -55,7 +55,7 @@ hkdf(Hash, Key, Data) ->
|
||||
[Output1, Output2, Output3].
|
||||
|
||||
-spec rekey(Cipher :: enoise_cipher_state:noise_cipher(),
|
||||
Key :: binary()) -> binary().
|
||||
Key :: binary()) -> binary() | {error, term()}.
|
||||
rekey(Cipher, K) ->
|
||||
encrypt(Cipher, K, ?MAX_NONCE, <<>>, <<0:(32*8)>>).
|
||||
|
||||
@@ -64,7 +64,8 @@ rekey(Cipher, K) ->
|
||||
Ad :: binary(), PlainText :: binary()) ->
|
||||
binary() | {error, term()}.
|
||||
encrypt('ChaChaPoly', K, N, Ad, PlainText) ->
|
||||
enacl:aead_chacha20poly1305_encrypt(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}),
|
||||
@@ -75,17 +76,21 @@ encrypt('AESGCM', K, N, Ad, PlainText) ->
|
||||
AD :: binary(), CipherText :: binary()) ->
|
||||
binary() | {error, term()}.
|
||||
decrypt('ChaChaPoly', K, N, Ad, CipherText) ->
|
||||
enacl:aead_chacha20poly1305_decrypt(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,
|
||||
<<CipherText:CTLen/binary, MAC:?MAC_LEN/binary>> = CipherText0,
|
||||
Nonce = <<0:32, N:64>>,
|
||||
crypto:block_decrypt(aes_gcm, K, Nonce, {Ad, CipherText, MAC}).
|
||||
case crypto:block_decrypt(aes_gcm, K, Nonce, {Ad, CipherText, MAC}) of
|
||||
error -> {error, decrypt_failed};
|
||||
Data -> Data
|
||||
end.
|
||||
|
||||
|
||||
-spec hash(Hash :: enoise_sym_state:noise_hash(), Data :: binary()) -> binary().
|
||||
hash(blake2b, Data) ->
|
||||
{ok, Hash} = enacl:generichash(64, Data), Hash;
|
||||
Hash = enacl:generichash(64, Data), Hash;
|
||||
hash(sha256, Data) ->
|
||||
crypto:hash(sha256, Data);
|
||||
hash(sha512, Data) ->
|
||||
|
||||
@@ -21,6 +21,11 @@
|
||||
-type noise_dh() :: dh25519 | dh448.
|
||||
-type noise_token() :: s | e | ee | ss | es | se.
|
||||
-type keypair() :: enoise_keypair:keypair().
|
||||
-type noise_split_state() :: #{ rx := enoise_cipher_state:state(),
|
||||
tx := enoise_cipher_state:state(),
|
||||
hs_hash := binary(),
|
||||
final_state => state() }.
|
||||
|
||||
|
||||
-record(noise_hs, { ss :: enoise_sym_state:state()
|
||||
, s :: keypair() | undefined
|
||||
@@ -32,7 +37,7 @@
|
||||
, msgs = [] :: [enoise_protocol:noise_msg()] }).
|
||||
|
||||
-opaque state() :: #noise_hs{}.
|
||||
-export_type([noise_dh/0, noise_role/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 :: string() | enoise_protocol:protocol(),
|
||||
Role :: noise_role(), Prologue :: binary(),
|
||||
@@ -54,7 +59,7 @@ init(Protocol, Role, Prologue, {S, E, RS, RE}) ->
|
||||
({in, [e]}, HS0) -> mix_hash(HS0, enoise_keypair:pubkey(RE))
|
||||
end, HS, PreMsgs).
|
||||
|
||||
-spec finalize(HS :: state()) -> {ok, map()} | {error, term()}.
|
||||
-spec finalize(HS :: state()) -> {ok, noise_split_state()} | {error, term()}.
|
||||
finalize(HS = #noise_hs{ msgs = [], ss = SS, role = Role }) ->
|
||||
{C1, C2} = enoise_sym_state:split(SS),
|
||||
HSHash = enoise_sym_state:h(SS),
|
||||
@@ -68,7 +73,7 @@ finalize(_) ->
|
||||
|
||||
-spec next_message(HS :: state()) -> in | out | done.
|
||||
next_message(#noise_hs{ msgs = [{Dir, _} | _] }) -> Dir;
|
||||
next_message(_) -> done.
|
||||
next_message(#noise_hs{ }) -> done.
|
||||
|
||||
-spec write_message(HS :: state(), PayLoad :: binary()) -> {ok, state(), binary()}.
|
||||
write_message(HS = #noise_hs{ msgs = [{out, Msg} | Msgs] }, PayLoad) ->
|
||||
@@ -85,6 +90,7 @@ read_message(HS = #noise_hs{ msgs = [{in, Msg} | Msgs] }, Message) ->
|
||||
Err = {error, _} -> Err
|
||||
end.
|
||||
|
||||
-spec remote_keys(HS :: state()) -> keypair().
|
||||
remote_keys(#noise_hs{ rs = RS }) ->
|
||||
RS.
|
||||
|
||||
|
||||
@@ -36,7 +36,9 @@ new(Type) ->
|
||||
%% @doc Create a new keypair of type `Type'. If `Public' is `undefined'
|
||||
%% it will be computed from the `Secret' (using the curve/algorithm
|
||||
%% indicated by `Type').
|
||||
-spec new(Type :: key_type(), Secret :: binary(), Public :: binary() | undefined) -> keypair().
|
||||
-spec new(Type :: key_type(),
|
||||
Secret :: binary() | undefined,
|
||||
Public :: binary() | undefined) -> keypair().
|
||||
new(Type, Secret, undefined) ->
|
||||
new(Type, Secret, pubkey_from_secret(Type, Secret));
|
||||
new(Type, Secret, Public) ->
|
||||
|
||||
@@ -90,6 +90,7 @@ pre_msgs(Role, #noise_protocol{ hs_pattern = Pattern }) ->
|
||||
{PreMsgs, _Msgs} = protocol(Pattern),
|
||||
role_adapt(Role, PreMsgs).
|
||||
|
||||
-spec role_adapt(Role :: enoise_hs_state:noise_role(), [noise_msg()]) -> [noise_msg()].
|
||||
role_adapt(initiator, Msgs) ->
|
||||
Msgs;
|
||||
role_adapt(responder, Msgs) ->
|
||||
|
||||
@@ -12,12 +12,12 @@ noise_hs_test_() ->
|
||||
fun() -> test_utils:noise_test_vectors() end,
|
||||
fun(_X) -> ok end,
|
||||
fun(Tests) ->
|
||||
[ {maps:get(name, T), fun() -> noise_hs_test(T) end}
|
||||
[ {maps:get(protocol_name, T), fun() -> noise_hs_test(T) end}
|
||||
|| T <- test_utils:noise_test_filter(Tests) ]
|
||||
end
|
||||
}.
|
||||
|
||||
noise_hs_test(V = #{ name := Name }) ->
|
||||
noise_hs_test(V = #{ protocol_name := Name }) ->
|
||||
Protocol = enoise_protocol:from_name(Name),
|
||||
|
||||
FixK = fun(undefined) -> undefined;
|
||||
|
||||
@@ -12,12 +12,12 @@ noise_interactive_test_() ->
|
||||
fun() -> test_utils:noise_test_vectors() end,
|
||||
fun(_X) -> ok end,
|
||||
fun(Tests) ->
|
||||
[ {maps:get(name, T), fun() -> noise_interactive(T) end}
|
||||
[ {maps:get(protocol_name, T), fun() -> noise_interactive(T) end}
|
||||
|| T <- test_utils:noise_test_filter(Tests) ]
|
||||
end
|
||||
}.
|
||||
|
||||
noise_interactive(V = #{ name := Name }) ->
|
||||
noise_interactive(V = #{ protocol_name := Name }) ->
|
||||
Protocol = enoise_protocol:from_name(Name),
|
||||
|
||||
FixK = fun(undefined) -> undefined;
|
||||
|
||||
+3
-2
@@ -114,9 +114,10 @@ parse_test_vectors(File) ->
|
||||
|
||||
%% Only test supported configurations
|
||||
noise_test_filter(Tests0) ->
|
||||
Tests1 = [ T || T = #{ name := Name } <- Tests0, supported(Name) ],
|
||||
Tests1 = [ T || T = #{ protocol_name := Name } <- Tests0, supported(Name) ],
|
||||
case length(Tests1) < length(Tests0) of
|
||||
true -> ?debugFmt("WARNING: ~p test vectors are unsupported", [length(Tests0) - length(Tests1)]);
|
||||
true -> ?debugFmt("WARNING: ~p test vectors out of ~p are unsupported",
|
||||
[length(Tests0) - length(Tests1), length(Tests0)]);
|
||||
false -> ok
|
||||
end,
|
||||
Tests1.
|
||||
|
||||
+29692
-14524
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user