mirror of
https://github.com/oxen-io/lokinet.git
synced 2024-11-17 15:25:35 +00:00
226 lines
4.9 KiB
Plaintext
226 lines
4.9 KiB
Plaintext
|
|
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:4]
|
|
P = D[4:4+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.
|
|
|