1
1
Fork 0
mirror of https://github.com/oxen-io/lokinet synced 2023-12-14 06:53:00 +01:00

protocol docs, more efficient padding, make code reflect protocol changes.

This commit is contained in:
Jeff Becker 2018-09-08 11:53:20 -04:00
parent 59b5af551a
commit adbf53bc40
No known key found for this signature in database
GPG key ID: F357B3B42F6F9B05
9 changed files with 296 additions and 407 deletions

View file

@ -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.

View file

@ -266,14 +266,18 @@ identifies the sender as having the RC contained in r. The recipiant MUST
validate the RC's signature and ensure that the public key in use is listed in
the RC.a matching the ipv6 address it originated from.
if r is not present in sessions made by clients.
{
a: "i",
n: "<32 bytes nonce for key exhcange>",
p: uint64_milliseconds_session_period,
r: RC,
v: 0
v: 0,
z: "<64 bytes signature of entire message by r.k>"
}
the link session will be kept open for p milliseconds after which
the session MUST be renegotiated.
link relay commit message (LRCM)
request a commit to relay traffic to another node.
@ -734,4 +738,4 @@ wrapper message for sending many dht messages down a path.
M: [many, dht, messages, here],
S: uint64_sequence_number,
V: 0
}
}

64
doc/wire-protocol.txt Normal file
View file

@ -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

View file

@ -43,6 +43,9 @@ namespace llarp
std::function< const PubKey &(void) > GetPubKey;
/// get remote address
std::function< const Addr &(void) > GetRemoteEndpoint;
/// handle a valid LIM
std::function< bool(const LinkIntroMessage *msg) > GotLIM;
};
} // namespace llarp

View file

@ -2,5 +2,6 @@
#define LLARP_LINK_LAYER_HPP
#include <llarp/link/server.hpp>
#include <llarp/link/session.hpp>
constexpr size_t MAX_LINK_MSG_SIZE = 8192;
constexpr size_t MAX_LINK_MSG_SIZE = 8192;
constexpr llarp_time_t DefaultLinkSessionLifetime = 10 * 1000;
#endif

View file

@ -8,6 +8,8 @@ namespace llarp
struct LinkIntroMessage : public ILinkMessage
{
static constexpr size_t MaxSize = MAX_RC_SIZE + 256;
LinkIntroMessage() : ILinkMessage()
{
}
@ -19,8 +21,12 @@ namespace llarp
~LinkIntroMessage();
RouterContact rc;
KeyExchangeNonce N;
Signature Z;
uint64_t P;
LinkIntroMessage&
operator=(const LinkIntroMessage& msg);
bool
DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf);
@ -30,6 +36,12 @@ namespace llarp
bool
HandleMessage(llarp_router* router) const;
bool
Sign(llarp_crypto* c, const SecretKey& signKeySecret);
bool
Verify(llarp_crypto* c) const;
};
} // namespace llarp

View file

@ -25,7 +25,7 @@
#define MAXHOPS (8)
#define DEFAULT_PATH_LIFETIME (10 * 60 * 1000)
#define PATH_BUILD_TIMEOUT (10 * 1000)
#define MESSAGE_PAD_SIZE (1024)
#define MESSAGE_PAD_SIZE (512)
namespace llarp
{

View file

@ -60,14 +60,14 @@ namespace llarp
Alive();
/// base
BaseSession(llarp_router* r);
BaseSession(LinkLayer* p);
/// outbound
BaseSession(llarp_router* r, utp_socket* s, const RouterContact& rc,
BaseSession(LinkLayer* p, utp_socket* s, const RouterContact& rc,
const AddressInfo& addr);
/// inbound
BaseSession(llarp_router* r, utp_socket* s, const Addr& remote);
BaseSession(LinkLayer* p, utp_socket* s, const Addr& remote);
enum State
{
@ -143,14 +143,7 @@ namespace llarp
QueueWriteBuffers(llarp_buffer_t buf)
{
llarp::LogDebug("write ", buf.sz, " bytes to ", remoteAddr);
if(state != eSessionReady)
{
llarp::LogWarn("failed to send ", buf.sz,
" bytes on non ready session state=", state);
return false;
}
else
lastActive = llarp_time_now_ms();
lastActive = llarp_time_now_ms();
size_t sz = buf.sz;
byte_t* ptr = buf.base;
while(sz)
@ -176,57 +169,36 @@ namespace llarp
OnLinkEstablished(p);
KeyExchangeNonce nonce;
nonce.Randomize();
gotLIM = true;
if(DoKeyExchange(Router()->crypto.transport_dh_client, nonce,
remoteTransportPubKey, Router()->encryption))
{
SendHandshake(nonce);
EnterState(eSessionReady);
SendKeepAlive();
}
OutboundHandshake(nonce);
}
// send our RC to the remote
// send first message
void
SendHandshake(const KeyExchangeNonce& n)
{
FragmentBuffer tmp;
auto buf = InitBuffer(tmp.data(), tmp.size());
// fastforward buffer for handshake to fit before
buf.cur += sizeof(uint32_t) * 2;
byte_t* begin = buf.cur;
LinkIntroMessage msg;
msg.rc = Router()->rc;
msg.N = n;
if(!msg.BEncode(&buf))
{
llarp::LogError("failed to encode our RC for handshake");
Close();
return;
}
uint32_t sz = buf.cur - begin;
llarp::LogDebug("handshake is of size ", sz, " bytes");
// write handshake header
buf.cur = buf.base;
llarp_buffer_put_uint32(&buf, LLARP_PROTO_VERSION);
llarp_buffer_put_uint32(&buf, sz);
// send it
write_ll(tmp.data(), sz + (sizeof(uint32_t) * 2));
}
OutboundHandshake(const KeyExchangeNonce& n);
// mix keys
bool
DoKeyExchange(llarp_transport_dh_func dh, const KeyExchangeNonce& n,
const PubKey& other, const SecretKey& secret)
{
PubKey us = llarp::seckey_topublic(secret);
llarp::LogDebug("DH us=", us, " them=", other, " n=", n);
if(!dh(sessionKey, other, secret, n))
ShortHash t_h;
AlignedBuffer< 64 > tmp;
memcpy(tmp.data(), sessionKey, sessionKey.size());
memcpy(tmp.data() + sessionKey.size(), n, n.size());
// t_h = HS(K + L.n)
if(!Router()->crypto.shorthash(t_h, ConstBuffer(tmp)))
{
llarp::LogError("key exchange with ", other, " failed");
Close();
llarp::LogError("failed to mix key to ", remoteAddr);
return false;
}
// K = TKE(a.p, B_a.e, sk, t_h)
if(!dh(sessionKey, other, secret, t_h))
{
llarp::LogError("key exchange with ", other, " failed");
return false;
}
llarp::LogDebug("keys mixed with session to ", remoteAddr);
return true;
}
@ -238,19 +210,11 @@ namespace llarp
void
Close();
bool
RecvHandshake(const void* buf, size_t bufsz, LinkLayer* p);
bool
Recv(const void* buf, size_t sz)
{
if(state != eSessionReady)
{
llarp::LogWarn("session not ready via ", remoteAddr);
return false;
}
Alive();
byte_t* ptr = (const byte_t*)buf;
byte_t* ptr = (byte_t*)buf;
llarp::LogDebug("utp read ", sz, " from ", remoteAddr);
size_t s = sz;
// process leftovers
@ -290,6 +254,12 @@ namespace llarp
return true;
}
bool
InboundLIM(const LinkIntroMessage* msg);
bool
OutboundLIM(const LinkIntroMessage* msg);
bool
IsTimedOut(llarp_time_t now) const
{
@ -527,13 +497,15 @@ namespace llarp
return std::unique_ptr< LinkLayer >(new LinkLayer(r));
}
BaseSession::BaseSession(llarp_router* r)
BaseSession::BaseSession(LinkLayer* p)
{
parent = p;
remoteTransportPubKey.Zero();
parent = nullptr;
recvMsgOffset = 0;
SendKeepAlive = [&]() -> bool {
if(false && sendq.size() == 0)
/*
if(sendq.size() == 0 && state == eSessionReady)
{
DiscardMessage msg;
byte_t tmp[128] = {0};
@ -545,8 +517,10 @@ namespace llarp
if(!this->QueueWriteBuffers(buf))
return false;
}
*/
return true;
};
gotLIM = false;
sendBufOffset = 0;
recvBufOffset = 0;
TimedOut = [&](llarp_time_t now) -> bool {
@ -567,9 +541,9 @@ namespace llarp
GetRemoteEndpoint = std::bind(&BaseSession::RemoteEndpoint, this);
}
BaseSession::BaseSession(llarp_router* r, utp_socket* s,
BaseSession::BaseSession(LinkLayer* p, utp_socket* s,
const RouterContact& rc, const AddressInfo& addr)
: BaseSession(r)
: BaseSession(p)
{
remoteRC.Clear();
remoteTransportPubKey = addr.pubkey;
@ -579,17 +553,99 @@ namespace llarp
assert(s == sock);
remoteAddr = addr;
Start = std::bind(&BaseSession::Connect, this);
GotLIM =
std::bind(&BaseSession::OutboundLIM, this, std::placeholders::_1);
}
BaseSession::BaseSession(llarp_router* r, utp_socket* s, const Addr& addr)
: BaseSession(r)
BaseSession::BaseSession(LinkLayer* p, utp_socket* s, const Addr& addr)
: BaseSession(p)
{
p->router->crypto.shorthash(sessionKey,
ConstBuffer(p->router->rc.pubkey));
remoteRC.Clear();
sock = s;
assert(s == sock);
assert(utp_set_userdata(sock, this) == this);
remoteAddr = addr;
Start = []() {};
GotLIM = std::bind(&BaseSession::InboundLIM, this, std::placeholders::_1);
}
bool
BaseSession::InboundLIM(const LinkIntroMessage* msg)
{
if(gotLIM && remoteRC.pubkey != msg->rc.pubkey)
{
return false;
}
remoteRC = msg->rc;
gotLIM = true;
if(!DoKeyExchange(Router()->crypto.transport_dh_server, msg->N,
remoteRC.enckey, parent->TransportSecretKey()))
return false;
EnterState(eSessionReady);
return true;
}
bool
BaseSession::OutboundLIM(const LinkIntroMessage* msg)
{
if(gotLIM && remoteRC.pubkey != msg->rc.pubkey)
{
return false;
}
remoteRC = msg->rc;
gotLIM = true;
// TODO: update address info pubkey
return DoKeyExchange(Router()->crypto.transport_dh_client, msg->N,
remoteTransportPubKey, Router()->encryption);
}
void
BaseSession::OutboundHandshake(const KeyExchangeNonce& n)
{
Router()->crypto.shorthash(sessionKey, ConstBuffer(remoteRC.pubkey));
byte_t tmp[LinkIntroMessage::MaxSize];
auto buf = StackBuffer< decltype(tmp) >(tmp);
LinkIntroMessage msg;
msg.rc = Router()->rc;
msg.N = n;
msg.P = DefaultLinkSessionLifetime;
if(!msg.Sign(&Router()->crypto, Router()->identity))
{
llarp::LogError("failed to sign LIM for outbound handshake to ",
remoteAddr);
Close();
return;
}
// encode
if(!msg.BEncode(&buf))
{
llarp::LogError("failed to encode LIM for handshake to ", remoteAddr);
Close();
return;
}
// rewind
buf.sz = buf.cur - buf.base;
buf.cur = buf.base;
// send
if(!SendMessageBuffer(buf))
{
llarp::LogError("failed to send handshake to ", remoteAddr);
Close();
return;
}
// mix keys
if(!DoKeyExchange(Router()->crypto.transport_dh_client, msg.N,
remoteTransportPubKey, Router()->encryption))
{
llarp::LogError("failed to mix keys for outbound session to ",
remoteAddr);
Close();
}
else
EnterState(eSessionReady);
}
llarp_router*
@ -611,14 +667,12 @@ namespace llarp
LinkLayer::NewOutboundSession(const RouterContact& rc,
const AddressInfo& addr)
{
return new BaseSession(router, utp_create_socket(_utp_ctx), rc, addr);
return new BaseSession(this, utp_create_socket(_utp_ctx), rc, addr);
}
uint64
LinkLayer::OnRead(utp_callback_arguments* arg)
{
LinkLayer* parent =
static_cast< LinkLayer* >(utp_context_get_userdata(arg->context));
BaseSession* self =
static_cast< BaseSession* >(utp_get_userdata(arg->socket));
@ -628,26 +682,13 @@ namespace llarp
{
return 0;
}
else if(self->state == BaseSession::eSessionReady)
if(!self->Recv(arg->buf, arg->len))
{
if(!self->Recv(arg->buf, arg->len))
{
llarp::LogDebug("recv fail for ", self->remoteAddr);
self->Close();
return 0;
}
utp_read_drained(arg->socket);
}
else if(self->state == BaseSession::eLinkEstablished)
{
if(!self->RecvHandshake(arg->buf, arg->len, parent))
{
llarp::LogDebug("recv handshake failed for ", self->remoteAddr);
self->Close();
return 0;
}
utp_read_drained(arg->socket);
llarp::LogDebug("recv fail for ", self->remoteAddr);
self->Close();
return 0;
}
utp_read_drained(arg->socket);
}
else
{
@ -698,7 +739,7 @@ namespace llarp
static_cast< LinkLayer* >(utp_context_get_userdata(arg->context));
Addr remote(*arg->address);
llarp::LogDebug("utp accepted from ", remote);
BaseSession* session = new BaseSession(self->router, arg->socket, remote);
BaseSession* session = new BaseSession(self, arg->socket, remote);
self->PutSession(remote, session);
session->OnLinkEstablished(self);
return 0;
@ -709,12 +750,8 @@ namespace llarp
bool isLastFragment)
{
if(state != eSessionReady)
{
llarp::LogWarn("tried to send to non ready session on ", remoteAddr);
return;
}
FragmentBuffer buf;
sendq.emplace_back();
auto& buf = sendq.back();
llarp::LogDebug("encrypt then hash ", sz, " bytes last=", isLastFragment);
buf.Randomize();
byte_t* nonce = buf.data() + FragmentHashSize;
@ -740,8 +777,6 @@ namespace llarp
payload.sz = FragmentBufferSize - FragmentHashSize;
// key'd hash
Router()->crypto.hmac(buf.data(), payload, sessionKey);
// push back
sendq.push_back(std::move(buf));
}
void
@ -811,83 +846,6 @@ namespace llarp
return true;
}
bool
BaseSession::RecvHandshake(const void* buf, size_t bufsz, LinkLayer* p)
{
size_t sz = bufsz;
parent = p;
llarp::LogDebug("recv handshake ", sz, " from ", remoteAddr);
if(sz <= 8)
{
llarp::LogDebug("handshake too small from ", remoteAddr);
Close();
return false;
}
// process handshake header
byte_t* ptr = (byte_t*)buf;
uint32_t version = bufbe32toh(ptr);
if(version != LLARP_PROTO_VERSION)
{
llarp::LogWarn("protocol version missmatch ", version,
" != ", LLARP_PROTO_VERSION);
Close();
return false;
}
ptr += sizeof(uint32_t);
sz -= sizeof(uint32_t);
uint32_t limsz = bufbe32toh(ptr);
ptr += sizeof(uint32_t);
sz -= sizeof(uint32_t);
if(limsz > sz)
{
// not enough data
// TODO: don't bail here, continue reading
llarp::LogDebug("not enough data for handshake, want ", limsz,
" bytes but got ", sz);
Close();
return false;
}
llarp::LogDebug("from ", bufsz, " bytes reading ", limsz, " of ", sz,
" bytes");
// process LIM
auto mbuf = InitBuffer(ptr, limsz);
LinkIntroMessage msg(this);
if(!msg.BDecode(&mbuf))
{
llarp::LogError("Failed to parse LIM from ", remoteAddr);
llarp::DumpBuffer(mbuf);
Close();
return false;
}
if(!msg.HandleMessage(Router()))
{
llarp::LogError("failed to verify signature of rc");
return false;
}
gotLIM = true;
sz -= limsz;
remoteRC = msg.rc;
if(!DoKeyExchange(Router()->crypto.transport_dh_server, msg.N,
remoteRC.enckey, parent->TransportSecretKey()))
return false;
EnterState(eSessionReady);
if(sz)
{
llarp::LogDebug("got ", sz, " leftover from handshake from ",
remoteAddr);
return Recv(ptr + limsz, sz);
}
else
{
llarp::LogDebug("no leftovers in handshake from ", remoteAddr);
}
return true;
}
void
BaseSession::Close()
{

View file

@ -29,6 +29,10 @@ namespace llarp
llarp::LogWarn("failed to decode nonce in LIM");
return false;
}
if(llarp_buffer_eq(key, "p"))
{
return bencode_read_integer(buf, &P);
}
if(llarp_buffer_eq(key, "r"))
{
if(rc.BDecode(buf))
@ -50,6 +54,10 @@ namespace llarp
llarp::LogDebug("LIM version ", version);
return true;
}
else if(llarp_buffer_eq(key, "z"))
{
return Z.BDecode(buf);
}
else
{
llarp::LogWarn("invalid LIM key: ", *key.cur);
@ -73,6 +81,11 @@ namespace llarp
if(!N.BEncode(buf))
return false;
if(!bencode_write_bytestring(buf, "p", 1))
return false;
if(!bencode_write_uint64(buf, P))
return false;
if(!bencode_write_bytestring(buf, "r", 1))
return false;
if(!rc.BEncode(buf))
@ -81,12 +94,71 @@ namespace llarp
if(!bencode_write_version_entry(buf))
return false;
if(!bencode_write_bytestring(buf, "z", 1))
return false;
if(!Z.BEncode(buf))
return false;
return bencode_end(buf);
}
LinkIntroMessage&
LinkIntroMessage::operator=(const LinkIntroMessage& msg)
{
version = msg.version;
Z = msg.Z;
rc = msg.rc;
N = msg.N;
P = msg.P;
return *this;
}
bool
LinkIntroMessage::HandleMessage(llarp_router* router) const
{
return rc.VerifySignature(&router->crypto);
if(!Verify(&router->crypto))
return false;
return session->GotLIM(this);
}
bool
LinkIntroMessage::Sign(llarp_crypto* c, const SecretKey& k)
{
Z.Zero();
byte_t tmp[MaxSize] = {0};
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
if(!BEncode(&buf))
return false;
buf.sz = buf.cur - buf.base;
buf.cur = buf.base;
return c->sign(Z, k, buf);
}
bool
LinkIntroMessage::Verify(llarp_crypto* c) const
{
LinkIntroMessage copy;
copy = *this;
copy.Z.Zero();
byte_t tmp[MaxSize] = {0};
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
if(!copy.BEncode(&buf))
return false;
buf.sz = buf.cur - buf.base;
buf.cur = buf.base;
// outer signature
if(!c->verify(rc.pubkey, buf, Z))
{
llarp::LogError("outer signature failure");
return false;
}
// rc signature
if(!rc.VerifySignature(c))
{
llarp::LogError("inner signature failure");
return false;
}
return true;
}
} // namespace llarp