diff --git a/README.md b/README.md index 974d080..629b2b3 100644 --- a/README.md +++ b/README.md @@ -3,29 +3,4 @@ zNoise An Erlang implementation of the [Noise protocol](https://noiseprotocol.org/) -`zNoise` provides a generic handshake mechanism, that can be used in a couple -of different ways. There is also a plain `gen_tcp` wrapper, where you can -"upgrade" a TCP socket to a Noise socket and use it in much the same way as you -would use `gen_tcp`. - -Interactive handshake ---------------------- - -When using `zNoise` to do an interactive handshake, `zNoise` will only take -care of message composition/decompositiona and encryption/decryption - i.e. the -user has to do the actual sending and receiving. - -An example of the interactive handshake can be seen in the `noise_interactive` -test in `test/enoise_tests.erl`. - -Generic handshake ------------------ - -There is also the option to use an automated handshake procedure. If provided -with a generic _Communication state_ that describe how data is sent and -received, the handshake procedure is done automatically. The result of a -successful handshake is two Cipher states that can be used to encrypt/decrypt a -RX channel and a TX channel respectively. - -The provided `gen_tcp`-wrapper is implemented using the generic handshake, see -`src/enoise.erl`. +This is a fork of [enoise](https://git.qpq.swiss/QPQ-AG/enoise). diff --git a/src/znoise.erl b/src/znoise.erl index 4d3bb51..8f65fb4 100644 --- a/src/znoise.erl +++ b/src/znoise.erl @@ -4,6 +4,8 @@ %%% @doc %%% Interface to the Noise protocol: https://noiseprotocol.org %%% +%%% This is a fork of the `enoise' project: https://git.qpq.swiss/QPQ-AG/enoise +%%% %%% For convenience there is also an API to use Noise over TCP (i.e. `gen_tcp') %%% and after "upgrading" a `gen_tcp'-socket into a `znoise'-socket it has a %%% similar API as `gen_tcp'. @@ -12,6 +14,7 @@ -module(znoise). -vsn("0.1.0"). -author("Craig Everett "). +-author("Hans Svensson "). -copyright("QPQ AG "). -license("ISC"). @@ -26,25 +29,26 @@ send/2, set_active/2]). --record(znoise, {pid}). +-record(znoise, + {pid = none | pid()}). -type key() :: binary(). -type keypair() :: znoise_keypair:keypair(). -type options() :: [option()]. %% A list of Noise options is a proplist, it *must* contain a value `noise' -%% that describes which Noise configuration to use. It is possible to give a -%% `prologue' to the protocol. And for the protocol to work, the correct +%% that describes which Noise configuration to use. It is possible to give +%% a `prologue' to the protocol. And for the protocol to work, the correct %% configuration of pre-defined keys (`s', `e', `rs', `re') should also be %% provided. --type option() :: {noise, protocol_option()} %% Required - | {e, keypair()} %% Mandatary depending on `noise' - | {s, keypair()} - | {re, key()} - | {rs, key()} +-type option() :: {noise, protocol_option()} %% Required + | {e, keypair()} %% Mandatary depending on `noise' + | {s, keypair()} + | {re, key()} + | {rs, key()} | {prologue, binary()} %% Optional - | {timeout, integer() | infinity}. %% Optional + | {timeout, integer() | infinity}. %% Optional -type protocol_option() :: znoise_protocol:protocol() | string() @@ -186,17 +190,17 @@ close(#znoise{ pid = Pid }) -> znoise_tcp:close(Pid). --spec controlling_process(Socket, Pid) -> Outcome +-spec controlling_process(Socket, PID) -> Outcome when Socket :: socket(), - Pid :: pid(), + PID :: pid(), Outcome :: ok | {error, term()}. %% @doc %% Assigns a new controlling process to the Noise socket. A controlling %% process is the owner of an Noise socket, and receives all messages from the %% socket. -controlling_process(#znoise{ pid = Pid }, NewPid) -> - znoise_tcp:controlling_process(Pid, NewPid). +controlling_process(#znoise{pid = PID}, NewPID) -> + znoise_tcp:controlling_process(PID, NewPID). -spec set_active(Socket, Mode) -> Outcome diff --git a/src/znoise_cipher_state.erl b/src/znoise_cipher_state.erl index e4caa96..3f43563 100644 --- a/src/znoise_cipher_state.erl +++ b/src/znoise_cipher_state.erl @@ -8,6 +8,7 @@ -module(znoise_cipher_state). -vsn("0.1.0"). -author("Craig Everett "). +-author("Hans Svensson "). -copyright("QPQ AG "). -license("ISC"). diff --git a/src/znoise_crypto.erl b/src/znoise_crypto.erl index e091e3f..921f3f0 100644 --- a/src/znoise_crypto.erl +++ b/src/znoise_crypto.erl @@ -8,6 +8,7 @@ -module(znoise_crypto). -vsn("0.1.0"). -author("Craig Everett "). +-author("Hans Svensson "). -copyright("QPQ AG "). -license("ISC"). diff --git a/src/znoise_hs_state.erl b/src/znoise_hs_state.erl index 82e9ed3..219f535 100644 --- a/src/znoise_hs_state.erl +++ b/src/znoise_hs_state.erl @@ -8,6 +8,7 @@ -module(znoise_hs_state). -vsn("0.1.0"). -author("Craig Everett "). +-author("Hans Svensson "). -copyright("QPQ AG "). -license("ISC"). diff --git a/src/znoise_keypair.erl b/src/znoise_keypair.erl index d10f1d8..66a0a86 100644 --- a/src/znoise_keypair.erl +++ b/src/znoise_keypair.erl @@ -8,6 +8,7 @@ -module(znoise_keypair). -vsn("0.1.0"). -author("Craig Everett "). +-author("Hans Svensson "). -copyright("QPQ AG "). -license("ISC"). diff --git a/src/znoise_protocol.erl b/src/znoise_protocol.erl index dc207f8..354905b 100644 --- a/src/znoise_protocol.erl +++ b/src/znoise_protocol.erl @@ -8,6 +8,7 @@ -module(znoise_protocol). -vsn("0.1.0"). -author("Craig Everett "). +-author("Hans Svensson "). -copyright("QPQ AG "). -license("ISC"). diff --git a/src/znoise_sym_state.erl b/src/znoise_sym_state.erl index 3bd2d60..63e11d6 100644 --- a/src/znoise_sym_state.erl +++ b/src/znoise_sym_state.erl @@ -7,6 +7,7 @@ -module(znoise_sym_state). -vsn("0.1.0"). -author("Craig Everett "). +-author("Hans Svensson "). -copyright("QPQ AG "). -license("ISC"). diff --git a/src/znoise_tcp.erl b/src/znoise_tcp.erl index ee0c085..9b7da6e 100644 --- a/src/znoise_tcp.erl +++ b/src/znoise_tcp.erl @@ -11,6 +11,7 @@ -module(znoise_tcp). -vsn("0.1.0"). -author("Craig Everett "). +-author("Hans Svensson "). -copyright("QPQ AG "). -license("ISC"). @@ -24,7 +25,8 @@ -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). --record(znoise, {pid}). +-record(znoise, + {pid}). -record(s, {rx = , @@ -158,69 +160,75 @@ code_change(_OldVsn, State, _Extra) -> %%% Handlers -handle_control_change(S = #state{ owner = Pid, owner_ref = OldRef }, Pid, NewPid) -> - NewRef = erlang:monitor(process, NewPid), +handle_control_change(State = #s{owner = PID, owner_ref = OldRef}, PID, NewPID) -> + NewRef = erlang:monitor(process, NewPID), erlang:demonitor(OldRef, [flush]), - {ok, S#state{ owner = NewPid, owner_ref = NewRef }}; -handle_control_change(S, _OldPid, _NewPid) -> - {{error, not_owner}, S}. + {ok, State#s{owner = NewPID, owner_ref = NewRef}}; +handle_control_change(State, _, _) -> + {{error, not_owner}, State}. -handle_active(S = #state{ owner = Pid, tcp_sock = TcpSock }, Pid, Active) -> + +handle_active(State = #s{owner = PID, tcp_sock = TcpSock}, PID, Active) -> case Active of true -> inet:setopts(TcpSock, [{active, true}]), - {ok, handle_msgs(S#state{ active = true })}; + {ok, handle_msgs(State#s{active = true})}; once -> - S1 = handle_msgs(S#state{ active = {once, false} }), - set_active(S1), - {ok, S1} + NewState = handle_msgs(State#s{active = {once, false}}), + set_active(NewState), + {ok, NewState} end; -handle_active(S, _Pid, _NewActive) -> - {{error, not_owner}, S}. +handle_active(State, _, _) -> + {{error, not_owner}, State}. -handle_data(S = #state{ rawbuf = Buf, rx = Rx }, Data) -> + +handle_data(State = #s{rawbuf = Buf, rx = RX}, Data) -> case <> of B = <> when Len > byte_size(Rest) -> - {S#state{ rawbuf = B }, []}; %% Not a full Noise message - save it + {State#s{rawbuf = B}, []}; %% Not a full Noise message - save it <> -> <> = Rest, - case znoise_cipher_state:decrypt_with_ad(Rx, <<>>, Msg) of - {ok, Rx1, Msg1} -> - {S1, Msgs} = handle_data(S#state{ rawbuf = Rest2, rx = Rx1 }, <<>>), - {S1, [Msg1 | Msgs]}; + case znoise_cipher_state:decrypt_with_ad(RX, <<>>, Msg) of + {ok, NewRX, NewMsg} -> + {NewState, Msgs} = handle_data(State#s{rawbuf = Rest2, rx = NewRX}, <<>>), + {NewState, [NewMsg | Msgs]}; {error, _} -> error({znoise_error, decrypt_input_failed}) end; EmptyOrSingleByte -> - {S#state{ rawbuf = EmptyOrSingleByte }, []} + {State#s{rawbuf = EmptyOrSingleByte}, []} end. -handle_msgs(S = #state{ msgbuf = [] }) -> - S; -handle_msgs(S = #state{ msgbuf = Msgs, active = true, owner = Owner }) -> - [ Owner ! {noise, #znoise{ pid = self() }, Msg} || Msg <- Msgs ], - S#state{ msgbuf = [] }; -handle_msgs(S = #state{ msgbuf = [Msg | Msgs], active = {once, Delivered}, owner = Owner }) -> + +handle_msgs(State = #s{msgbuf = []}) -> + State; +handle_msgs(State = #s{msgbuf = Msgs, active = true, owner = Owner}) -> + [ Owner ! {noise, #znoise{pid = self()}, Msg} || Msg <- Msgs ], + State#s{msgbuf = []}; +handle_msgs(State = #s{msgbuf = [Msg | Msgs], active = {once, Delivered}, owner = Owner}) -> case Delivered of true -> - S; + State; false -> - Owner ! {noise, #znoise{ pid = self() }, Msg}, - S#state{ msgbuf = Msgs, active = {once, true} } + Owner ! {noise, #znoise{pid = self()}, Msg}, + State#s{msgbuf = Msgs, active = {once, true}} end. -handle_send(S = #state{ tcp_sock = TcpSock, tx = Tx }, Data) -> - {ok, Tx1, Msg} = znoise_cipher_state:encrypt_with_ad(Tx, <<>>, Data), + +handle_send(State = #s{tcp_sock = TcpSock, tx = TX}, Data) -> + {ok, MewTX, Msg} = znoise_cipher_state:encrypt_with_ad(TX, <<>>, Data), case gen_tcp:send(TcpSock, <<(byte_size(Msg)):16, Msg/binary>>) of - ok -> {ok, S#state{ tx = Tx1 }}; - Err = {error, _} -> {Err, S} + ok -> {ok, State#s{tx = MewTX}}; + Error -> {Error, State} end. -set_active(#state{ msgbuf = [], active = {once, _}, tcp_sock = TcpSock }) -> + +set_active(#s{msgbuf = [], active = {once, _}, tcp_sock = TcpSock}) -> inet:setopts(TcpSock, [{active, once}]); set_active(_) -> ok. + flush_tcp(Pid, TcpSock) -> receive {tcp, TcpSock, Data} -> Pid ! {tcp, TcpSock, Data}, @@ -228,6 +236,7 @@ flush_tcp(Pid, TcpSock) -> after 1 -> ok end. + close_tcp(closed) -> ok; close_tcp(Sock) ->