mirror of https://github.com/oxen-io/lokinet
protocol docs, more efficient padding, make code reflect protocol changes.
parent
59b5af551a
commit
adbf53bc40
@ -1,225 +0,0 @@
|
||||
|
||||
invisible wire protocol version 0:
|
||||
|
||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
|
||||
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
|
||||
document are to be interpreted as described in RFC 2119 [RFC2119].
|
||||
|
||||
cryptography:
|
||||
|
||||
see crypto_v0.txt
|
||||
|
||||
|
||||
wire decryption:
|
||||
|
||||
the first 32 bytes are message authentication bytes, h
|
||||
the next 32 bytes are nouce for cipher, n
|
||||
the remaining bytes are interpreted as ciphertext, x
|
||||
|
||||
a shared secret S is generated in the session start message
|
||||
next the integrity of the ciphertext is done by checking MDS(n + x, S) == h
|
||||
if the ciphertext is valid then the frame is decrypted via SD(S, x, n)
|
||||
|
||||
wire encryption:
|
||||
|
||||
given variadic sized payload p, 32 byte nounce n and public encryption keys A
|
||||
and B
|
||||
|
||||
x = SE(S, p, n[0:24])
|
||||
h = MDS(n + x, S)
|
||||
|
||||
the resulting data is:
|
||||
|
||||
h + n + x
|
||||
|
||||
|
||||
handshake:
|
||||
|
||||
0) intro
|
||||
|
||||
32 bytes hmac, h
|
||||
32 bytes nounce, n
|
||||
32 bytes encrypted alice's transport public encryption key e
|
||||
variadic bytes padding, w0
|
||||
|
||||
Alice transmits ( h + n + e + w0 ) to Bob from the transport address matching
|
||||
his public transport encryption key (b.k).
|
||||
|
||||
w0 = "[insert variable length random padding here]"
|
||||
n = RAND(32)
|
||||
e = SE(a.k, HS(b.k + n), n[0:24])
|
||||
S = TKE(a.k, b.k, n)
|
||||
h = MDS(n + e + w0, S)
|
||||
|
||||
Bob recieves ( s + n + e + w0 )
|
||||
|
||||
1) intro ack
|
||||
|
||||
sent in reply to an intro, bob sends an intro ack encrypted to Alice using
|
||||
|
||||
32 bytes hmac, h
|
||||
32 bytes nounce, n
|
||||
32 bytes ciphertext, x
|
||||
variadic bytes padding, w1
|
||||
|
||||
w1 = "[insert variable length random padding here]"
|
||||
token = RAND(32)
|
||||
S = TKE(a.k, b.k, n)
|
||||
x = SE(k, token, n[0:24])
|
||||
h = MDS(n + x + w1, S)
|
||||
|
||||
Bob transmits ( s + n + x + w1 ), r is ignored and discarded
|
||||
Alice recieves ( s + n + x + w1 ) and verifies the signature silently
|
||||
dropping if it does not match.
|
||||
|
||||
2) session start
|
||||
|
||||
Alice uses the token from the previous message to start the wire session
|
||||
|
||||
32 bytes hmac, h
|
||||
32 bytes nounce, n
|
||||
32 bytes ciphertext, x
|
||||
variadic byttes padding, w2
|
||||
|
||||
w2 = "[insert variable length random padding here]"
|
||||
e_K = TKE(a.k, b.k, n)
|
||||
x = SE(e_K, token, n[0:24])
|
||||
h = MDS(n + x + w2, e_K)
|
||||
T = HS(token + n)
|
||||
K = TKE(a.k, b.k, T)
|
||||
|
||||
Alice transmits ( h + n + x + w2 )
|
||||
Bob recieves ( h + n + x + w2) and verifies that h == MDS(n + x, k) silently
|
||||
drops if not matching
|
||||
|
||||
the session is now established with session key K,
|
||||
Bob replies by transmitting a LIM
|
||||
|
||||
IWP payload format:
|
||||
|
||||
ciphertext:
|
||||
32 bytes hmac, h
|
||||
32 bytes nounce, n
|
||||
N bytes of ciphertext, x
|
||||
|
||||
plaintext header, H
|
||||
8 bits protocol version, v (currently 0)
|
||||
8 bits message type, t
|
||||
16 bits payload size, s
|
||||
8 bits reserved, r (currently 0)
|
||||
8 bits flags, f
|
||||
|
||||
plaintext payload: P
|
||||
s bytes of data
|
||||
N bytes remaining data is discarded
|
||||
|
||||
Encryption:
|
||||
|
||||
D = H + P
|
||||
x = SE(D, S, n)
|
||||
h = MDS(n + x, S)
|
||||
|
||||
Alice transmits h + n + x
|
||||
|
||||
Bob recieves recieve h + n + x
|
||||
|
||||
Bob checks hmac by verifying h == MDS(n + x, S)
|
||||
|
||||
if the hmac fails the data is silently dropped
|
||||
|
||||
Decryption:
|
||||
|
||||
verify h == MDS(n + x, S)
|
||||
D = SD(x, S, n)
|
||||
H = D[0:6]
|
||||
P = D[6:6+H.s]
|
||||
|
||||
message types:
|
||||
|
||||
ALIV = 0x00
|
||||
|
||||
keepalive message
|
||||
|
||||
XMIT = 0x01
|
||||
|
||||
begin link layer message transmission
|
||||
|
||||
ACKS = 0x02
|
||||
|
||||
acknolege link layer message fragment
|
||||
|
||||
FRAG = 0x03
|
||||
|
||||
transmit link layer message fragment
|
||||
|
||||
flags:
|
||||
|
||||
SESSION_INVALIDATED = 1 << 0
|
||||
|
||||
this session is now invalidated and a new session is required
|
||||
|
||||
HIGH_PACKET_DROP = 1 << 1
|
||||
|
||||
high packet drop detected
|
||||
|
||||
HIGH_MTU_DETECTED = 1 << 2
|
||||
|
||||
the network uses an mtu greater than 1488 bytes
|
||||
|
||||
PROTOCOL_UPGRADE = 1 << 3
|
||||
|
||||
indicates we want to do protocol upgrade (future use)
|
||||
|
||||
XMIT payload:
|
||||
|
||||
start transmiting a link layer message
|
||||
|
||||
msg_bytes = BE(msg)
|
||||
|
||||
32 bytes hash of message computed by HS(msg_bytes)
|
||||
64 bits unsigned int message id
|
||||
16 bits unsigned int fragment size bytes, S
|
||||
16 bits size of last fragment in bytes, L
|
||||
16 bits reserved for future, currently zero
|
||||
8 bits unsigned int nonzero number of fragments, n
|
||||
8 bits reserved flags, f
|
||||
if f LSB is set then last fragment is included and is l bytes long
|
||||
|
||||
f's LSB MUST be set as of protocol version 0.
|
||||
|
||||
msg_bytes is S * (n - 1) + L bytes long
|
||||
|
||||
FRAG payload:
|
||||
|
||||
transmit a link layer message fragment
|
||||
|
||||
64 bits message id
|
||||
8 bits unsigned int fragment number
|
||||
S bytes of payload fragment data
|
||||
remaining bytes discarded
|
||||
|
||||
ACKS payload:
|
||||
|
||||
indicates we which chunks we have recieved
|
||||
|
||||
64 bits message id
|
||||
32 bits bitmask of chunks we have received
|
||||
remaining bytes discarded
|
||||
|
||||
|
||||
control flow:
|
||||
|
||||
To transmit link message over an established session the transmitter sends an
|
||||
XMIT frame.
|
||||
In reply to an XMIT frame the recipiant MUST send an ACKS frame with an emtpy
|
||||
bitmask.
|
||||
After the transmitter recieves the first ACKS frame it is allowed to start
|
||||
sending FRAG messages.
|
||||
When all fragmenets are obtained by the recipiant, the recipiant sends an ACKS
|
||||
frame with a full bitfield (0xFFFF), to indicate the link message was recieved.
|
||||
In the event of packet drop the sender decides when to retransmit FRAG frames
|
||||
with expontential backoff.
|
||||
|
||||
In the event of packet loss greater than 50% over 10 second the session is
|
||||
invalidated and must be renegotiated with a new handshake.
|
||||
|
@ -0,0 +1,64 @@
|
||||
Wire Protocol (version 0)
|
||||
|
||||
|
||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
|
||||
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
|
||||
document are to be interpreted as described in RFC 2119 [RFC2119].
|
||||
|
||||
LLARP supports by default an authenticated and framed transport over UTP [1]
|
||||
|
||||
1088 byte fragments are sent over UTP in an ordered fashion.
|
||||
|
||||
The each fragment has the following structure:
|
||||
|
||||
[ 32 bytes blake2 keyed hash of the following 1056 bytes ]
|
||||
[ 24 bytes random nonce ]
|
||||
[ 1032 bytes encrypted payload ]
|
||||
|
||||
the decrypted payload has the following structure:
|
||||
|
||||
[ big endian unsigned 32 bit flags (F) ]
|
||||
[ big endian unsigned 32 bit fragment length (N) ]
|
||||
[ N bytes of plaintext payload ]
|
||||
|
||||
if F is non zero then more fragments for the current message being transmitted
|
||||
are expected. If F is zero then this fragment is the last in the sequence.
|
||||
|
||||
On each fragment append the N bytes of payload to an internal buffer.
|
||||
This internal buffer MUST NOT exceed 8192 bytes, the maximum size of an inter
|
||||
node message.
|
||||
|
||||
When the last fragment in the sequence is reached the internal buffer is
|
||||
processed as a link layer message (see proto_v0.txt)
|
||||
|
||||
Handshake phase:
|
||||
|
||||
Before data flows a protocol handshake must happen.
|
||||
|
||||
The first message sent is a LIM (L) (see proto_v0.txt) by the connection initiator, Alice.
|
||||
|
||||
The receiving end MUST verify the signatures of the LIM and RC.
|
||||
If any verification fails at any phase the underlying UTP session MUST be reset.
|
||||
|
||||
Each side re-computes the session key.
|
||||
|
||||
the session key kdf for K is:
|
||||
|
||||
t_h = HS(K + L.n)
|
||||
K = TKE(A.p, B_a.e, sk, t_h)
|
||||
|
||||
the initial value of K is HS(B.k)
|
||||
|
||||
Periodically the connection initiator MUST renegotiate the session key by
|
||||
sending a LIM after L.p milliseconds have elapsed.
|
||||
|
||||
If either party's RC changes while a connection is established they MUST
|
||||
renegotioate the session keys to ensure the new RC is sent.
|
||||
|
||||
|
||||
references:
|
||||
|
||||
[1] http://www.bittorrent.org/beps/bep_0029.html
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue