diff --git a/rebar.config b/rebar.config index 748f94a..79dcd42 100644 --- a/rebar.config +++ b/rebar.config @@ -9,3 +9,4 @@ locals_not_used, deprecated_function_calls, deprecated_functions]}. +{dialyzer, [{warnings, [unknown]}]}. diff --git a/src/enoise.erl b/src/enoise.erl index 16b36b4..3fa55b9 100644 --- a/src/enoise.erl +++ b/src/enoise.erl @@ -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). diff --git a/src/enoise_cipher_state.erl b/src/enoise_cipher_state.erl index 7df0730..7a5d784 100644 --- a/src/enoise_cipher_state.erl +++ b/src/enoise_cipher_state.erl @@ -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()}. diff --git a/src/enoise_connection.erl b/src/enoise_connection.erl index ad36c7e..215a937 100644 --- a/src/enoise_connection.erl +++ b/src/enoise_connection.erl @@ -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 :: boolean()) -> 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). diff --git a/src/enoise_crypto.erl b/src/enoise_crypto.erl index 086fcb5..92b52d9 100644 --- a/src/enoise_crypto.erl +++ b/src/enoise_crypto.erl @@ -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)>>). @@ -80,7 +80,10 @@ decrypt('AESGCM', K, N, Ad, CipherText0) -> CTLen = byte_size(CipherText0) - ?MAC_LEN, <> = 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(). diff --git a/src/enoise_hs_state.erl b/src/enoise_hs_state.erl index 9a64acd..dff6f2d 100644 --- a/src/enoise_hs_state.erl +++ b/src/enoise_hs_state.erl @@ -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) -> diff --git a/src/enoise_keypair.erl b/src/enoise_keypair.erl index 174999f..313e8a2 100644 --- a/src/enoise_keypair.erl +++ b/src/enoise_keypair.erl @@ -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) -> diff --git a/src/enoise_protocol.erl b/src/enoise_protocol.erl index 51b3e47..21369dc 100644 --- a/src/enoise_protocol.erl +++ b/src/enoise_protocol.erl @@ -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) ->