|
|
|
@ -11,96 +11,79 @@ datagram based network layer.
|
|
|
|
|
|
|
|
|
|
outer message format:
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
A: command,
|
|
|
|
|
B: <16 bytes flow id>,
|
|
|
|
|
C: <optional 32 bytes cookie>,
|
|
|
|
|
X: <N bytes payload>
|
|
|
|
|
}
|
|
|
|
|
outer-header:
|
|
|
|
|
|
|
|
|
|
comamnds:
|
|
|
|
|
<1 byte command>
|
|
|
|
|
<1 byte reserved, R, set to '=' (0x3d)>
|
|
|
|
|
<32 bytes flow id, B>
|
|
|
|
|
|
|
|
|
|
A - get handshake cookie
|
|
|
|
|
|
|
|
|
|
obtain a handshake cookie
|
|
|
|
|
command 'O' - obtain flow id
|
|
|
|
|
|
|
|
|
|
B is randomized
|
|
|
|
|
X MUST contain the user agent string of the requester.
|
|
|
|
|
obtain a handshake cookie
|
|
|
|
|
|
|
|
|
|
the if the network id differs from the current network's id a reject message is
|
|
|
|
|
sent:
|
|
|
|
|
<outer-header>
|
|
|
|
|
<32 bytes random>
|
|
|
|
|
<8 bytes net id>
|
|
|
|
|
<remaining discarded>
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
A: R,
|
|
|
|
|
B: msg.B,
|
|
|
|
|
X: "<reply line>"
|
|
|
|
|
}
|
|
|
|
|
the if the network id differs from the current network's id a reject message
|
|
|
|
|
MUST be sent
|
|
|
|
|
|
|
|
|
|
MUST be replied to with a message rejected or a give handshake cookie
|
|
|
|
|
|
|
|
|
|
C - give handshake cookie
|
|
|
|
|
command 'G' - give flow id
|
|
|
|
|
|
|
|
|
|
give a handshake cookie to a remote endpoint that asks for one
|
|
|
|
|
<outer-header>
|
|
|
|
|
<32 byte new flow-id, X>
|
|
|
|
|
<remaining discarded>
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
give a flow id to a remote endpoint that asks for one
|
|
|
|
|
|
|
|
|
|
R - message rejected
|
|
|
|
|
B is the B value from the request flow id message
|
|
|
|
|
X is a 32 byte the flow id, calcuated via:
|
|
|
|
|
|
|
|
|
|
B is the flow id from the recipiant
|
|
|
|
|
X is a reply line
|
|
|
|
|
r = RAND(32)
|
|
|
|
|
a = "::ffff.<ascii representation of ipv4 address>" + ":" + "<port number>"
|
|
|
|
|
X = HS(a + B + r + net id)
|
|
|
|
|
|
|
|
|
|
reject a message with flow id B
|
|
|
|
|
resulting message:
|
|
|
|
|
|
|
|
|
|
S - session negotiation
|
|
|
|
|
"G=<32 byte flowid><32 bytes new flowid>"
|
|
|
|
|
|
|
|
|
|
negotiate encrypted session
|
|
|
|
|
after recieving a give flow id message a session negotiation can happen
|
|
|
|
|
|
|
|
|
|
B is the flow id from the recipiant
|
|
|
|
|
C is the handshake cookie
|
|
|
|
|
X is encrypted session negotiation data
|
|
|
|
|
command 'R' - message rejected
|
|
|
|
|
|
|
|
|
|
D - encrypted data transmission
|
|
|
|
|
<outer-header>
|
|
|
|
|
<N arbitrary bytes reason for rejection>
|
|
|
|
|
|
|
|
|
|
transmit encrypted data on session
|
|
|
|
|
reject a message on a flow id
|
|
|
|
|
|
|
|
|
|
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>
|
|
|
|
|
resulting message of reject with reason "no you"
|
|
|
|
|
|
|
|
|
|
<net-id> ::= "lokinet" | "testnet"
|
|
|
|
|
"R=<32 byte flow-id>no you"
|
|
|
|
|
|
|
|
|
|
<space> ::= " "
|
|
|
|
|
command 'S' - session negotiation
|
|
|
|
|
|
|
|
|
|
<zero> ::= "0"
|
|
|
|
|
|
|
|
|
|
<integer> ::= "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
|
|
|
|
|
|
|
|
|
|
<digit> ::= <zero> | <integer>
|
|
|
|
|
negotiate encrypted session
|
|
|
|
|
|
|
|
|
|
<number> ::= <zero> | <integer> <digit>*
|
|
|
|
|
<outer-header>
|
|
|
|
|
<24 bytes nounce, N>
|
|
|
|
|
<encrypted session negotiation data, X>
|
|
|
|
|
<last 32 bytes keyed hash, Z>
|
|
|
|
|
|
|
|
|
|
<agent-version> ::= <number> "." <number> "." <number>
|
|
|
|
|
B is the flow id from the recipiant generated by the give flow id message (from outer header)
|
|
|
|
|
N is a random nounce
|
|
|
|
|
X is encrypted session negotiation data
|
|
|
|
|
Z is a keyed hash
|
|
|
|
|
|
|
|
|
|
<protocol-version> ::= <number>
|
|
|
|
|
Z is generated via:
|
|
|
|
|
|
|
|
|
|
msg.Z = '0x00' * 32
|
|
|
|
|
msg.Z = MDS(msg, tx_K)
|
|
|
|
|
|
|
|
|
|
session negotiation:
|
|
|
|
|
|
|
|
|
@ -119,15 +102,9 @@ 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)
|
|
|
|
|
SD(msg.X, rx_K, msg.N)
|
|
|
|
|
|
|
|
|
|
encrypted payload is bencoded LIM (see proto_v0.txt)
|
|
|
|
|
|
|
|
|
@ -147,20 +124,144 @@ b.rx_K = k_b
|
|
|
|
|
a.tx_K = k_b
|
|
|
|
|
b.tx_K = k_a
|
|
|
|
|
|
|
|
|
|
afterwards data transmission may happen
|
|
|
|
|
afterwards data transmission may happen.
|
|
|
|
|
the intiator's remote address is permitted to change during data transmission.
|
|
|
|
|
remote address of the last successfully
|
|
|
|
|
|
|
|
|
|
data tranmission:
|
|
|
|
|
D - encrypted data transmission
|
|
|
|
|
|
|
|
|
|
message format:
|
|
|
|
|
transmit encrypted data on session
|
|
|
|
|
|
|
|
|
|
<10 byte header>
|
|
|
|
|
<remaining data payload>
|
|
|
|
|
<outer-header>
|
|
|
|
|
<24 bytes nonce, N>
|
|
|
|
|
<encrypted data, X>
|
|
|
|
|
<last 32 bytes keyed hash of entire payload, Z>
|
|
|
|
|
|
|
|
|
|
header format:
|
|
|
|
|
|
|
|
|
|
<1 byte proto version>
|
|
|
|
|
B is the flow id from the recipiant (from outer header)
|
|
|
|
|
N is a random nounce
|
|
|
|
|
X is encrypted data
|
|
|
|
|
Z is keyed hash of entire message
|
|
|
|
|
|
|
|
|
|
Z is generated via:
|
|
|
|
|
|
|
|
|
|
msg.Z = '0x00' * 32
|
|
|
|
|
msg.Z = MDS(msg, tx_K)
|
|
|
|
|
|
|
|
|
|
data tranmission:
|
|
|
|
|
|
|
|
|
|
inner message format of X (after decryption):
|
|
|
|
|
|
|
|
|
|
header:
|
|
|
|
|
|
|
|
|
|
<1 byte protocol version>
|
|
|
|
|
<1 byte command>
|
|
|
|
|
<1 byte flags>
|
|
|
|
|
<1 byte fragno>
|
|
|
|
|
<2 bytes fraglen>
|
|
|
|
|
<4 bytes seqno>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
command: 'K' (keep alive)
|
|
|
|
|
|
|
|
|
|
tell other side to acknoledge they are alive
|
|
|
|
|
|
|
|
|
|
<header>
|
|
|
|
|
<2 bytes resevered, set to 0>
|
|
|
|
|
<2 bytes attempt counter, set to 0 and incremented every retransmit, reset when we get a keepalive ack>
|
|
|
|
|
<2 bytes milliseconds ping timeout>
|
|
|
|
|
<8 bytes current session TX limit in bytes per second>
|
|
|
|
|
<8 bytes current session RX use in bytes per second>
|
|
|
|
|
<8 bytes milliseconds since epoch our current time>
|
|
|
|
|
<remaining bytes discarded>
|
|
|
|
|
|
|
|
|
|
command: 'L' (keep alive ack)
|
|
|
|
|
|
|
|
|
|
acknolege keep alive message
|
|
|
|
|
|
|
|
|
|
<header>
|
|
|
|
|
<6 bytes reserved, set to 0>
|
|
|
|
|
<8 bytes current session RX limit in bytes per second>
|
|
|
|
|
<8 bytes current session TX use in bytes per second>
|
|
|
|
|
<8 bytes milliseconds since epoch our current time>
|
|
|
|
|
<remaining bytes discarded>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
command: 'C' (congestion)
|
|
|
|
|
|
|
|
|
|
tell other side to slow down
|
|
|
|
|
|
|
|
|
|
<header>
|
|
|
|
|
<2 bytes reduce TX rate by this many 1024 bytes per second>
|
|
|
|
|
<4 bytes milliseconds slowdown lifetime>
|
|
|
|
|
<remaining bytes discarded>
|
|
|
|
|
|
|
|
|
|
command: 'D' (anti-congestion)
|
|
|
|
|
|
|
|
|
|
tell other side to speed up
|
|
|
|
|
|
|
|
|
|
<header>
|
|
|
|
|
<2 bytes increase TX rate by this many 1024 bytes per second>
|
|
|
|
|
<4 bytes milliseconds speedup lifetime>
|
|
|
|
|
<remaining bytes discarded>
|
|
|
|
|
|
|
|
|
|
command: 'T' (transmit)
|
|
|
|
|
|
|
|
|
|
transit fragment
|
|
|
|
|
|
|
|
|
|
<header>
|
|
|
|
|
<1 byte number of 16 byte blocks offset from beginning of message, O>
|
|
|
|
|
<1 byte number of 16 byte blocks size of fragment data, N>
|
|
|
|
|
<4 bytes sequence number>
|
|
|
|
|
<32 bytes expected digest of message, present if O is 0, otherwise omitted>
|
|
|
|
|
<16 * N bytes of data>
|
|
|
|
|
<remaining bytes discarded>
|
|
|
|
|
|
|
|
|
|
command: 'A' (ack)
|
|
|
|
|
|
|
|
|
|
acknoledge fragments
|
|
|
|
|
|
|
|
|
|
<header>
|
|
|
|
|
<1 byte number of acks following, N>
|
|
|
|
|
<8 * N bytes acks>
|
|
|
|
|
<remaining bytes discarded>
|
|
|
|
|
|
|
|
|
|
ack format:
|
|
|
|
|
|
|
|
|
|
<4 byte message sequence number>
|
|
|
|
|
<1 byte reserved current set to 0>
|
|
|
|
|
<1 byte ack counter (number of acks sent for the corrisponding message)>
|
|
|
|
|
<1 byte bitmask fragments selective ack (msb is fragment 0, lsb is fragment 7)>
|
|
|
|
|
<1 byte bitmask fragments posative ack (msb is fragment 0, lsb is fragment 7)>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
command: 'R' (rotate keys)
|
|
|
|
|
|
|
|
|
|
inform remote that their RX key should be rotated
|
|
|
|
|
|
|
|
|
|
given alice(A) sends this message to bob(B) the new keys are computed as such:
|
|
|
|
|
|
|
|
|
|
n_K = TKE(K, B_e, K_seed, N)
|
|
|
|
|
|
|
|
|
|
A.tx_K = n_K
|
|
|
|
|
B.rx_K = n_K
|
|
|
|
|
|
|
|
|
|
<2 bytes milliseconds lifetime of old keys, retain them for this long and then discard>
|
|
|
|
|
<4 bytes reserved, set to 0>
|
|
|
|
|
<32 bytes key exchange nounce, N>
|
|
|
|
|
<32 bytes next public encryption key, K>
|
|
|
|
|
<remaining bytes discarded>
|
|
|
|
|
|
|
|
|
|
command: 'U' (upgrade)
|
|
|
|
|
|
|
|
|
|
request protocol upgrade
|
|
|
|
|
|
|
|
|
|
<header>
|
|
|
|
|
<1 byte protocol min version to upgrade to>
|
|
|
|
|
<1 byte protocol max version to upgrade to>
|
|
|
|
|
<remaining bytes discarded>
|
|
|
|
|
|
|
|
|
|
command: 'V' (version upgrade)
|
|
|
|
|
|
|
|
|
|
sent in response to upgrade message
|
|
|
|
|
|
|
|
|
|
<header>
|
|
|
|
|
<1 byte protocol version selected>
|
|
|
|
|
<1 byte protocol version highest we support>
|
|
|
|
|
<remaining bytes discarded>
|
|
|
|
|