Adding erlang spa server component
This commit is contained in:
parent
ecb25a042c
commit
f0f8abd8e8
@ -13,10 +13,13 @@ Usage
|
|||||||
-----
|
-----
|
||||||
|
|
||||||
$ rebar3 shell
|
$ rebar3 shell
|
||||||
1> fwknop:knock("spaserver.domain.com", 62201, "Sz80RjpXOlhH2olGuKBUamHKcqyMBsS9BTgLaMugUsg=", "c0TOaMJ2aVPdYTh4Aa25Dwxni7PrLo2zLAtBoVwSepkvH6nLcW45Cjb9zaEC2SQd03kaaV+Ckx3FhCh5ohNM5Q==", { tcp, "1.1.1.1", 22 } ).
|
1> server:start("Sz80RjpXOlhH2olGuKBUamHKcqyMBsS9BTgLaMugUsg=", "c0TOaMJ2aVPdYTh4Aa25Dwxni7PrLo2zLAtBoVwSepkvH6nLcW45Cjb9zaEC2SQd03kaaV+Ckx3FhCh5ohNM5Q==").
|
||||||
|
2> fwknop:knock("spaserver.domain.com", 62201, "Sz80RjpXOlhH2olGuKBUamHKcqyMBsS9BTgLaMugUsg=", "c0TOaMJ2aVPdYTh4Aa25Dwxni7PrLo2zLAtBoVwSepkvH6nLcW45Cjb9zaEC2SQd03kaaV+Ckx3FhCh5ohNM5Q==", { tcp, "1.1.1.1", 22 } ).
|
||||||
=INFO REPORT==== 15-Nov-2016::15:49:16 ===
|
=INFO REPORT==== 15-Nov-2016::15:49:16 ===
|
||||||
Message: 0428888364523312:bXMxNzg0:1479224956:2.0.2:1:MTI3LjAuMC4xLHRjcC84NDQz
|
Message: 0428888364523312:bXMxNzg0:1479224956:2.0.2:1:MTI3LjAuMC4xLHRjcC84NDQz
|
||||||
=INFO REPORT==== 15-Nov-2016::15:49:16 ===
|
=INFO REPORT==== 15-Nov-2016::15:49:16 ===
|
||||||
HMAC: KDZrTwZ+gFpqgzk8+BCXvYhRCxCzk084UyNzhihiWLU
|
HMAC: KDZrTwZ+gFpqgzk8+BCXvYhRCxCzk084UyNzhihiWLU
|
||||||
ok
|
ok
|
||||||
2>
|
Client request:{127,0,0,1}
|
||||||
|
Got message: <<"1.1.1.1,tcp/22">>
|
||||||
|
3>
|
||||||
|
|||||||
102
erlang/src/server.erl
Normal file
102
erlang/src/server.erl
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
%% License (GNU General Public License):
|
||||||
|
%%
|
||||||
|
%% This program is free software; you can redistribute it and/or
|
||||||
|
%% modify it under the terms of the GNU General Public License
|
||||||
|
%% as published by the Free Software Foundation; either version 2
|
||||||
|
%% of the License, or (at your option) any later version.
|
||||||
|
%%
|
||||||
|
%% This program is distributed in the hope that it will be useful,
|
||||||
|
%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
%% GNU General Public License for more details.
|
||||||
|
%%
|
||||||
|
%% You should have received a copy of the GNU General Public License
|
||||||
|
%% along with this program; if not, write to the Free Software
|
||||||
|
%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||||
|
%% USA
|
||||||
|
|
||||||
|
-module( server ).
|
||||||
|
-compile( export_all ).
|
||||||
|
|
||||||
|
-import( fwknop, [ strip_base64/1, pbkdf1/2 ] ).
|
||||||
|
-export( [ start/2 ] ).
|
||||||
|
|
||||||
|
start(RijndaelKeyB64, HmacKeyB64) ->
|
||||||
|
spawn(fun() -> server(62201, RijndaelKeyB64, HmacKeyB64) end).
|
||||||
|
|
||||||
|
server(Port, RijndaelKeyB64, HmacKeyB64) ->
|
||||||
|
{ok, Socket} = gen_udp:open(Port, [binary, {active, false}]),
|
||||||
|
accept(Socket, { RijndaelKeyB64, HmacKeyB64 } ).
|
||||||
|
|
||||||
|
accept(Socket, { Key, Hmac } = Creds) ->
|
||||||
|
inet:setopts(Socket, [{active, once}]),
|
||||||
|
receive
|
||||||
|
{udp, Socket, Host, _, Bin} ->
|
||||||
|
io:format("Client request:~p~n",[Host]),
|
||||||
|
{ok, Ciphertext} = verify( Bin, Hmac ),
|
||||||
|
{ok, Plaintext} = decrypt( Ciphertext, Key ),
|
||||||
|
{ok, Message} = decode( Plaintext ),
|
||||||
|
error_logger:info_msg( "Got message: ~p", [ Message ] ),
|
||||||
|
|
||||||
|
accept( Socket, Creds )
|
||||||
|
end.
|
||||||
|
|
||||||
|
verify( SpaData, HmacKeyB64 ) ->
|
||||||
|
Magic = <<"U2FsdGVkX1">>,
|
||||||
|
HmacKey = base64:decode( HmacKeyB64 ),
|
||||||
|
|
||||||
|
% sha2.h:#define SHA256_B64_LEN 43
|
||||||
|
HmacLen = 43,
|
||||||
|
|
||||||
|
% write something to just split this on size vs two parts
|
||||||
|
DataHmac = binary:part(SpaData, {byte_size(SpaData), -HmacLen}),
|
||||||
|
EncodedMsg = binary:part(SpaData, {0, byte_size(SpaData) - HmacLen}),
|
||||||
|
|
||||||
|
ExpectedHmac = fwknop:strip_base64( base64:encode( crypto:hmac( sha256, HmacKey, << Magic/binary, EncodedMsg/binary >> ) ) ),
|
||||||
|
|
||||||
|
%io:format("DataHmac: ~s~n",[DataHmac]),
|
||||||
|
%io:format("ExpectedHmac: ~s~n",[ExpectedHmac]),
|
||||||
|
|
||||||
|
ExpectedHmac = DataHmac,
|
||||||
|
|
||||||
|
% handle replay-attack (just compare hmacs or decode to digests?)
|
||||||
|
% verify len is a blocksize?
|
||||||
|
|
||||||
|
DecodedData = base64:decode( unstrip_base64( <<Magic/binary, EncodedMsg/binary>> ) ),
|
||||||
|
% skip "Salted__"
|
||||||
|
DecodedMsg = binary:part( DecodedData, {byte_size(DecodedData), -(byte_size(DecodedData) - 8) } ),
|
||||||
|
|
||||||
|
{ ok, DecodedMsg }.
|
||||||
|
|
||||||
|
decrypt( Ciphertext, RijndaelKeyB64 ) ->
|
||||||
|
RijndaelKey = base64:decode( RijndaelKeyB64 ),
|
||||||
|
|
||||||
|
% split again on size
|
||||||
|
Salt = binary:part( Ciphertext, {0, 8} ),
|
||||||
|
EncryptedMsg = binary:part( Ciphertext, {byte_size(Ciphertext), -(byte_size(Ciphertext) - 8) } ),
|
||||||
|
|
||||||
|
{Key, IV} = fwknop:pbkdf1( Salt, RijndaelKey ),
|
||||||
|
|
||||||
|
{ok, crypto:block_decrypt( aes_cbc256, Key, IV, EncryptedMsg ) }.
|
||||||
|
|
||||||
|
decode( Plaintext ) ->
|
||||||
|
Unpadded = pkcs7:unpad( Plaintext ),
|
||||||
|
|
||||||
|
%[Rand, User, Time, Version, MsgType, Request, Digest] = re:split( Unpadded, ":", [{return,binary}]),
|
||||||
|
%io:format( "~s:~s:~s:~s:~s:~s:~s~n", [ Rand, User, Time, Version, MsgType, Request, Digest] ),
|
||||||
|
[_, _, _, _, _, Request, _] = re:split( Unpadded, ":", [{return,binary}]),
|
||||||
|
|
||||||
|
[Ip, Proto, Port] = re:split( base64:decode( unstrip_base64( Request) ), "[,/]", [{return,binary}]),
|
||||||
|
Message = list_to_binary( io_lib:format( "~s,~s/~s", [ Ip, Proto, Port ] ) ),
|
||||||
|
|
||||||
|
{ok, Message}.
|
||||||
|
|
||||||
|
%
|
||||||
|
% miscellaneous utilities
|
||||||
|
%
|
||||||
|
unstrip_base64( Bin ) ->
|
||||||
|
case ( size( Bin ) rem 4 ) of
|
||||||
|
0 -> Bin;
|
||||||
|
N -> Pad = list_to_binary(string:copies("=", (4-N) )),
|
||||||
|
<< Bin/binary, Pad/binary >>
|
||||||
|
end.
|
||||||
Loading…
x
Reference in New Issue
Block a user