mirror of
https://github.com/oxen-io/lokinet.git
synced 2024-11-17 15:25:35 +00:00
167 lines
3.2 KiB
Plaintext
167 lines
3.2 KiB
Plaintext
Wire Protocol (version 1)
|
|
|
|
|
|
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 message transport over a
|
|
datagram based network layer.
|
|
|
|
|
|
outer message format:
|
|
|
|
{
|
|
A: command,
|
|
B: <16 bytes flow id>,
|
|
C: <optional 32 bytes cookie>,
|
|
X: <N bytes payload>
|
|
}
|
|
|
|
comamnds:
|
|
|
|
A - get handshake cookie
|
|
|
|
obtain a handshake cookie
|
|
|
|
B is randomized
|
|
X MUST contain the user agent string of the requester.
|
|
|
|
the if the network id differs from the current network's id a reject message is
|
|
sent:
|
|
|
|
{
|
|
A: R,
|
|
B: msg.B,
|
|
X: "<reply line>"
|
|
}
|
|
|
|
MUST be replied to with a message rejected or a give handshake cookie
|
|
|
|
C - give handshake cookie
|
|
|
|
give a handshake cookie to a remote endpoint that asks for one
|
|
|
|
B is the B value from the get handshake cookie message
|
|
X is a 32 byte handshake cookie, calcuated via:
|
|
|
|
r = RAND(32)
|
|
a = "<ascii representation of ip>" + " " + "<port number>"
|
|
X = HS(a + B + r)
|
|
|
|
R - message rejected
|
|
|
|
B is the flow id from the recipiant
|
|
X is a reply line
|
|
|
|
reject a message with flow id B
|
|
|
|
S - session negotiation
|
|
|
|
negotiate encrypted session
|
|
|
|
B is the flow id from the recipiant
|
|
C is the handshake cookie
|
|
X is encrypted session negotiation data
|
|
|
|
D - encrypted data transmission
|
|
|
|
transmit encrypted data on session
|
|
|
|
B is the flow id from the recipiant
|
|
X is authenticated and encrypted data
|
|
|
|
BNF:
|
|
|
|
<reply-line> ::= <status-code> <space> <method> <space> <message>
|
|
|
|
<status-code> ::= <integer> <digit> <digit>
|
|
|
|
<word> ::= <letter>+
|
|
|
|
<message> ::= <word> <space> <word>* | <word>
|
|
|
|
<method> ::= "COOKIE" | "HANDSHAKE"
|
|
|
|
<user-agent> ::= <net-id> <space> <protocol-version> <space> <agent-version>
|
|
|
|
<net-id> ::= "lokinet" | "testnet"
|
|
|
|
<space> ::= " "
|
|
|
|
<zero> ::= "0"
|
|
|
|
<integer> ::= "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
|
|
|
|
<digit> ::= <zero> | <integer>
|
|
|
|
<number> ::= <zero> | <integer> <digit>*
|
|
|
|
<agent-version> ::= <number> "." <number> "." <number>
|
|
|
|
<protocol-version> ::= <number>
|
|
|
|
|
|
session negotiation:
|
|
|
|
The session starts out with each side having 2 session keys rx_K and tx_K for
|
|
decrypting inbound messages and encrypting outbound messages respectively.
|
|
|
|
The initiator (alice) and the recipiant (bob) start out with static session keys
|
|
|
|
k_a = HS(a.k)
|
|
k_b = HS(b.k)
|
|
|
|
a.rx_K = k_a
|
|
b.rx_K = k_b
|
|
|
|
a.tx_K = k_b
|
|
b.tx_K = k_a
|
|
|
|
|
|
inner message format:
|
|
|
|
<32 bytes blake2s keyed hash of following data>
|
|
<24 bytes nounce>
|
|
<remaining bytes encrypted payload>
|
|
|
|
decryption is done via:
|
|
|
|
SD(remaining, rx_K, nounce)
|
|
|
|
encrypted payload is bencoded LIM (see proto_v0.txt)
|
|
|
|
the initiator starts out by sending a LIM a_LIM to the recipiant.
|
|
|
|
the recipiant replies with a LIM b_LIM to the initiator.
|
|
|
|
when the initiator gets a valid LIM from the recipiant the session keys for data
|
|
transmission are set to:
|
|
|
|
k_a = TKE(a.k, b.k, a.sk, a_LIM.n)
|
|
k_b = TKE(b.k, a.k, b.sk, b_LIM.n)
|
|
|
|
a.rx_K = k_a
|
|
b.rx_K = k_b
|
|
|
|
a.tx_K = k_b
|
|
b.tx_K = k_a
|
|
|
|
afterwards data transmission may happen
|
|
|
|
data tranmission:
|
|
|
|
message format:
|
|
|
|
<10 byte header>
|
|
<remaining data payload>
|
|
|
|
header format:
|
|
|
|
<1 byte proto version>
|
|
<1 byte command>
|
|
<1 byte flags>
|
|
<1 byte fragno>
|
|
<2 bytes fraglen>
|
|
<4 bytes seqno>
|