pull/1/head
Ryan Tharp 6 years ago
commit d8329b9955

@ -0,0 +1,24 @@
{
"configurations": [
{
"name": "Linux",
"browse": {
"path": [
"${workspaceFolder}/llarp",
"${workspaceFolder}/daemon",
"${workspaceFolder}/include"
],
"limitSymbolsToIncludedHeaders": true
},
"includePath": [
"${workspaceFolder}/include"
],
"defines": [],
"compilerPath": "/usr/bin/clang",
"cStandard": "c11",
"cppStandard": "c++17",
"intelliSenseMode": "clang-x64"
}
],
"version": 4
}

@ -0,0 +1,27 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "enter program name, for example ${workspaceFolder}/a.out",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": true,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
}
]
}

@ -0,0 +1,3 @@
{
"editor.formatOnSave": true
}

14
.vscode/tasks.json vendored

@ -6,12 +6,14 @@
{
"label": "build",
"type": "shell",
"command": "make"
},
{
"label": "rebuild",
"type": "shell",
"command": "make clean all"
"command": "make",
"group": "build",
"osx": {
"command": "make CXX=g++-8 CC=gcc-8"
},
"problemMatcher": [
"$gcc"
]
}
]
}

@ -83,6 +83,7 @@ set(LIB_SRC
llarp/crypto_async.cpp
llarp/crypto_libsodium.cpp
llarp/dht.cpp
llarp/encrypted_frame.cpp
llarp/ev.cpp
llarp/exit_info.cpp
llarp/exit_route.c
@ -95,7 +96,10 @@ set(LIB_SRC
llarp/mem.cpp
llarp/net.cpp
llarp/nodedb.cpp
llarp/path.cpp
llarp/relay_ack.cpp
llarp/relay_commit.cpp
llarp/relay_up_down.cpp
llarp/router_contact.cpp
llarp/router.cpp
llarp/router_identity.c

@ -4,6 +4,7 @@
#include <stdio.h>
#include <string.h>
#include <experimental/filesystem>
#include <llarp/crypto.hpp>
namespace fs = std::experimental::filesystem;
@ -202,10 +203,10 @@ main(int argc, char *argv[])
llarp_crypto crypt;
llarp_crypto_libsodium_init(&crypt);
fs::path ident_keyfile = "identity.key";
llarp_seckey_t identity;
byte_t identity[SECKEYSIZE];
llarp_findOrCreateIdentity(&crypt, ident_keyfile.c_str(), identity);
// get identity public key
uint8_t *pubkey = llarp_seckey_topublic(identity);
uint8_t *pubkey = llarp::seckey_topublic(identity);
llarp_rc_set_pubkey(&tmp, pubkey);
// this causes a segfault
llarp_rc_sign(&crypt, identity, &tmp);
@ -250,10 +251,10 @@ main(int argc, char *argv[])
llarp_crypto crypt;
llarp_crypto_libsodium_init(&crypt);
fs::path ident_keyfile = "identity.key";
llarp_seckey_t identity;
byte_t identity[SECKEYSIZE];
llarp_findOrCreateIdentity(&crypt, ident_keyfile.c_str(), identity);
// get identity public key
uint8_t *pubkey = llarp_seckey_topublic(identity);
uint8_t *pubkey = llarp::seckey_topublic(identity);
llarp_rc_set_pubkey(&tmp, pubkey);
llarp_rc_sign(&crypt, identity, &tmp);
// set filename

@ -210,7 +210,7 @@ find router contact message (FRCM)
find a router by long term RC.k public key
{
A: "F",
A: "R",
K: "<32 byte public key of router>",
T: transaction_id_uint64,
V: 0
@ -245,7 +245,7 @@ R is a list containing a single RC if found or is an empty list if not found
sent in reply to FRCM only
{
A: "G",
A: "S",
R: [RC],
T: transaction_id_uint64,
V: 0

@ -165,7 +165,7 @@ x is the timestamp seconds since epoch that this introducer expires at
{
k: "<32 bytes public identity key of router>",
p: path_id_uint64,
p: "<16 bytes path id>",
v: 0,
x: time_expires_seconds_since_epoch_uint64
}
@ -227,14 +227,14 @@ to encrypt a frame to a router with public key B.k
A.k, s = ECKG()
n = RAND(32)
S = PKE(p, A.k, B.k)
S = PKE(p, A.k, B.k, n)
1) encode and encrypt
x = BE(msg)
new_x = SE(S, n[0:24], x)
2) generate hmac
2) generate message authentication
h = MDS(n + A.k + new_x, S)
@ -358,7 +358,7 @@ this establishes the downstream keys.
a: "a",
c: [ list, of, encrypted, LCAR],
l: encrypted frame for path creator,
r: "<16 bytes rx hop>",
t: "<16 bytes tx hop>",
v: 0
}
@ -390,47 +390,44 @@ popped off and the last element filled with random.
link relay upstream message (LRUM)
sent to relay data via upstream direction of a previously created path.
decrypt z using previously derived upstream key and nounce y. Relay with new_y
and new_z in upstream direction as a LRUM.
h = MDS(x, k_up)
verify h == z[0:32]
new_x = SD(k_up, y, x)
new_y = y ^ new_x[0:24]
new_z = z[32:] + RAND(32)
{
a: "u",
p: "<16 bytes tx path id>",
v: 0,
x: "<insert N bytes payload here>",
y: "<insert 24 bytes nounce here>",
z: "<256 bytes rolling hmac>"
x: "<N bytes encrypted x1 value>",
y: "<32 bytes nonce>",
z: "<discard>"
}
link relay downstream message (LRDM)
plaintext x1 is a routing message
sent to relay data via downstream direction of a previously created path.
decrypt z using previously derived downstream key and nounce y. Relay with new_y
and new_z in downstream direction as a LRUM.
h = MDS(x, k_down)
verify h == z[0:32]
new_x = SD(k_down, y, x)
new_y = y ^ new_x[0:24]
new_z = z[32:] + RAND(32)
x1 = BD(SD(k_up, y[0:24], x))
new_y = HS(y + k_up)
verify new_y == x1.n
in the event we get a path data message (PDM), transmit a LRUM to next hop
{
a: "d",
p: "<16 bytes rx path id>",
v: 0,
x: "<insert N bytes payload here>",
y: "<insert 24 bytes nounce here>",
z: "<256 bytes rolling hmac>"
a: "u",
p: x1.P,
v: x1.V,
x: x1.D,
y: x1.N,
z: RAND(x1.R)
}
link relay exit message (LRXM)
if we are the farthest hop, process x1 as a routing message
link relay downstream message (LRDM)
sent to relay data via downstream direction of a previously created path.
same as LRUM but a is 'd' and p/x1.p refer to the rx path id
link relay exit message (LRXM) [under construction]
sent to exit a previously commited path before it expires.
verify signature using cancel key c in relay commit message.
@ -503,6 +500,21 @@ originated from inside a LRDM.
ipv4 addresses are allowed via ipv4 mapped ipv6 addresses, i.e. ::ffff.10.0.0.1
path data message (PDM)
intermediate path data
forward N as LRUM if we got it in a LRUM
forward N as LRDM if we got it in a LRDM
{
A: "D",
D: "<N bytes payload here>",
N: "<32 bytes next nonce>",
P: "<16 bytes next path id>",
R: number_of_bytes_Z_padding,
V: 0
}
obtain exit address message (OXAM)
sent to an exit router to obtain a NAT ip address for ip exit traffic.
@ -564,8 +576,8 @@ signed data sent anonymously over the network to a recipiant from a sender.
sent inside a TDFM encrypted to the hidden service's public encryption key.
{
A: "D",
D: "<payload bytes>",
A: "H",
H: "<payload bytes>",
I: Introducer for reply,
R: SA of recipiant,
S: SI of sender,

@ -22,7 +22,7 @@ struct llarp_ai
{
uint16_t rank;
char dialect[MAX_AI_DIALECT_SIZE + 1];
llarp_pubkey_t enc_key;
byte_t enc_key[PUBKEYSIZE];
struct in6_addr ip;
uint16_t port;
};

@ -1,6 +1,7 @@
#ifndef LLARP_ALIGNED_HPP
#define LLARP_ALIGNED_HPP
#include <llarp/bencode.h>
#include <llarp/crypto.h>
#include <sodium.h>
#include <iomanip>
@ -59,6 +60,12 @@ namespace llarp
return sz;
}
size_t
size()
{
return sz;
}
void
Zero()
{
@ -69,7 +76,7 @@ namespace llarp
void
Randomize()
{
randombytes(l, sz);
randombytes(b, sz);
}
byte_t*
@ -106,6 +113,24 @@ namespace llarp
return &b[0];
}
bool
BEncode(llarp_buffer_t* buf) const
{
return bencode_write_bytestring(buf, b, sz);
}
bool
BDecode(llarp_buffer_t* buf)
{
llarp_buffer_t strbuf;
if(!bencode_read_string(buf, &strbuf))
return false;
if(strbuf.sz != sz)
return false;
memcpy(b, strbuf.base, sz);
return true;
}
private:
union {
byte_t b[sz];

@ -0,0 +1,101 @@
#ifndef LLARP_BENCODE_HPP
#define LLARP_BENCODE_HPP
#include <llarp/bencode.h>
namespace llarp
{
bool
BEncodeWriteDictMsgType(llarp_buffer_t* buf, const char* k, const char* t)
{
return bencode_write_bytestring(buf, k, 1)
&& bencode_write_bytestring(buf, t, 1);
}
template < typename Obj_t >
bool
BEncodeWriteDictEntry(const char* k, const Obj_t& o, llarp_buffer_t* buf)
{
return bencode_write_bytestring(buf, k, 1) && o.BEncode(buf);
}
template < typename Item_t >
bool
BEncodeRead(Item_t& item, llarp_buffer_t* buf);
template < typename Item_t >
bool
BEncodeMaybeReadDictEntry(const char* k, Item_t& item, bool& read,
llarp_buffer_t key, llarp_buffer_t* buf)
{
llarp_buffer_t strbuf;
if(llarp_buffer_eq(key, k))
{
if(!bencode_read_string(buf, &strbuf))
return false;
if(!item.BDecode(buf))
return false;
read = true;
return true;
}
return true;
}
template < typename Item_t >
bool
BEncodeMaybeReadVersion(const char* k, Item_t& item, uint64_t expect,
bool& read, llarp_buffer_t key, llarp_buffer_t* buf)
{
if(llarp_buffer_eq(key, k))
{
if(!bencode_read_integer(buf, &item))
return false;
read = item == expect;
return true;
}
return true;
}
template < typename Iter >
bool
BEncodeWriteList(Iter itr, Iter end, llarp_buffer_t* buf)
{
if(!bencode_start_list(buf))
return false;
while(itr != end)
if(!itr->BEncode(buf))
return false;
else
++itr;
return bencode_end(buf);
}
template < typename List_t >
bool
BEncodeReadList(List_t& result, llarp_buffer_t* buf)
{
if(*buf->cur != 'l') // ensure is a list
return false;
buf->cur++;
while(llarp_buffer_size_left(*buf) && *buf->cur != 'e')
{
if(!result.emplace(result.end())->BDecode(buf))
return false;
}
if(*buf->cur != 'e') // make sure we're at a list end
return false;
buf->cur++;
return true;
}
template < typename List_t >
bool
BEncodeWriteDictList(const char* k, List_t& list, llarp_buffer_t* buf)
{
return bencode_write_bytestring(buf, k, 1)
&& BEncodeWriteList(list.begin(), list.end(), buf);
}
}
#endif

@ -27,6 +27,7 @@ extern "C" {
#define TUNNONCESIZE 32
#define HMACSIZE 32
/*
typedef byte_t llarp_pubkey_t[PUBKEYSIZE];
typedef byte_t llarp_seckey_t[SECKEYSIZE];
typedef byte_t llarp_nonce_t[NONCESIZE];
@ -37,23 +38,19 @@ typedef byte_t llarp_hmac_t[HMACSIZE];
typedef byte_t llarp_hmacsec_t[HMACSECSIZE];
typedef byte_t llarp_sig_t[SIGSIZE];
typedef byte_t llarp_tunnel_nonce_t[TUNNONCESIZE];
/// get public key from secret
byte_t *
llarp_seckey_topublic(byte_t *secret);
*/
/// label functors
/// PKE(result, publickey, nonce, secretkey)
typedef bool (*llarp_dh_func)(llarp_sharedkey_t *, llarp_pubkey_t,
llarp_tunnel_nonce_t, llarp_seckey_t);
typedef bool (*llarp_path_dh_func)(byte_t *, byte_t *, byte_t *, byte_t *);
/// TKE(result publickey, secretkey, nonce)
typedef bool (*llarp_transport_dh_func)(byte_t *, byte_t *, byte_t *, byte_t *);
/// SD/SE(buffer, key, nonce)
typedef bool (*llarp_sym_cipher_func)(llarp_buffer_t, llarp_sharedkey_t,
llarp_nonce_t);
typedef bool (*llarp_sym_cipher_func)(llarp_buffer_t, const byte_t *,
const byte_t *);
/// H(result, body)
typedef bool (*llarp_hash_func)(byte_t *, llarp_buffer_t);
@ -77,9 +74,9 @@ struct llarp_crypto
/// xchacha symettric cipher
llarp_sym_cipher_func xchacha20;
/// path dh creator's side
llarp_dh_func dh_client;
llarp_path_dh_func dh_client;
/// path dh relay side
llarp_dh_func dh_server;
llarp_path_dh_func dh_server;
/// transport dh client side
llarp_transport_dh_func transport_dh_client;
/// transport dh server side

@ -0,0 +1,46 @@
#ifndef LLARP_CRYPTO_HPP
#define LLARP_CRYPTO_HPP
#include <llarp/crypto.h>
#include <llarp/mem.h>
#include <llarp/threadpool.h>
#include <llarp/aligned.hpp>
namespace llarp
{
const byte_t*
seckey_topublic(const byte_t* secret);
byte_t*
seckey_topublic(byte_t* secret);
typedef AlignedBuffer< 32 > SharedSecret;
typedef AlignedBuffer< 32 > KeyExchangeNonce;
typedef AlignedBuffer< PUBKEYSIZE > PubKey;
struct PubKeyHash
{
std::size_t
operator()(PubKey const& a) const noexcept
{
size_t sz = 0;
memcpy(&sz, a.data(), sizeof(size_t));
return sz;
}
};
typedef AlignedBuffer< SECKEYSIZE > SecretKey;
typedef AlignedBuffer< SHORTHASHSIZE > ShortHash;
typedef AlignedBuffer< SIGSIZE > Signature;
typedef AlignedBuffer< TUNNONCESIZE > TunnelNonce;
typedef AlignedBuffer< 24 > SymmNonce;
typedef AlignedBuffer< 32 > SymmKey;
}
#endif

@ -50,7 +50,7 @@ struct llarp_router_lookup_job
void* user;
llarp_rotuer_lookup_handler hook;
struct llarp_dht_context* dht;
llarp_pubkey_t target;
byte_t target[PUBKEYSIZE];
bool found;
struct llarp_rc result;
};

@ -0,0 +1,61 @@
#ifndef LLARP_ENCCRYPTED_HPP
#define LLARP_ENCCRYPTED_HPP
#include <llarp/bencode.h>
#include <llarp/buffer.h>
#include <sodium.h>
namespace llarp
{
/// encrypted buffer base type
struct Encrypted
{
Encrypted() = default;
Encrypted(const byte_t* buf, size_t sz);
Encrypted(size_t sz);
~Encrypted();
bool
BEncode(llarp_buffer_t* buf) const
{
return bencode_write_bytestring(buf, data, size);
}
void
Randomize()
{
if(data)
randombytes(data, size);
}
bool
BDecode(llarp_buffer_t* buf)
{
llarp_buffer_t strbuf;
if(!bencode_read_string(buf, &strbuf))
return false;
if(strbuf.sz == 0)
return false;
if(data)
delete[] data;
size = strbuf.sz;
data = new byte_t[size];
memcpy(data, strbuf.base, size);
return true;
}
llarp_buffer_t*
Buffer()
{
return &m_Buffer;
}
byte_t* data = nullptr;
size_t size = 0;
private:
llarp_buffer_t m_Buffer;
};
}
#endif

@ -0,0 +1,14 @@
#ifndef LLARP_ENCRYPTED_ACK_HPP
#define LLARP_ENCRYPTED_ACK_HPP
#include <llarp/encrypted.hpp>
namespace llarp
{
struct EncryptedAck : public Encrypted
{
bool
DecryptInPlace(const byte_t* symkey, const byte_t* nonce,
llarp_crypto* crypto);
};
}
#endif

@ -1,12 +1,115 @@
#ifndef LLARP_ENCRYPTED_FRAME_HPP
#define LLARP_ENCRYPTED_FRAME_HPP
#include <llarp/crypto.h>
#include <llarp/mem.h>
#include <vector>
#include <llarp/threadpool.h>
#include <llarp/encrypted.hpp>
namespace llarp
{
typedef std::vector< byte_t > EncryptedFrame;
struct EncryptedFrame : public Encrypted
{
static constexpr size_t OverheadSize =
PUBKEYSIZE + TUNNONCESIZE + SHORTHASHSIZE;
EncryptedFrame() = default;
EncryptedFrame(byte_t* buf, size_t sz) : Encrypted(buf, sz)
{
}
EncryptedFrame(size_t sz) : Encrypted(sz + OverheadSize)
{
}
bool
DecryptInPlace(byte_t* seckey, llarp_crypto* crypto);
bool
EncryptInPlace(byte_t* seckey, byte_t* other, llarp_crypto* crypto);
};
/// TOOD: can only handle 1 frame at a time
template < typename User >
struct AsyncFrameEncrypter
{
typedef void (*EncryptHandler)(EncryptedFrame*, User*);
static void
Encrypt(void* user)
{
AsyncFrameEncrypter< User >* ctx =
static_cast< AsyncFrameEncrypter< User >* >(user);
if(ctx->frame->EncryptInPlace(ctx->seckey, ctx->otherKey, ctx->crypto))
ctx->handler(ctx->frame, ctx->user);
else
{
delete ctx->frame;
ctx->handler(nullptr, ctx->user);
}
}
llarp_crypto* crypto;
byte_t* secretkey;
EncryptHandler handler;
EncryptedFrame* frame;
User* user;
byte_t* otherKey;
AsyncFrameEncrypter(llarp_crypto* c, byte_t* seckey, EncryptHandler h)
: crypto(c), secretkey(seckey), handler(h)
{
}
void
AsyncEncrypt(llarp_threadpool* worker, llarp_buffer_t buf, byte_t* other,
User* u)
{
// TODO: should we own otherKey?
otherKey = other;
frame = new EncryptedFrame(buf.sz);
memcpy(frame->data + EncryptedFrame::OverheadSize, buf.base, buf.sz);
user = u;
llarp_threadpool_queue_job(worker, {this, &Encrypt});
}
};
/// TOOD: can only handle 1 frame at a time
template < typename User >
struct AsyncFrameDecrypter
{
typedef void (*DecryptHandler)(llarp_buffer_t*, User*);
static void
Decrypt(void* user)
{
AsyncFrameDecrypter< User >* ctx =
static_cast< AsyncFrameDecrypter< User >* >(user);
if(ctx->target->DecryptInPlace(ctx->seckey, ctx->crypto))
ctx->result(ctx->target->Buffer(), ctx->context);
else
ctx->result(nullptr, ctx->context);
}
AsyncFrameDecrypter(llarp_crypto* c, byte_t* secretkey, DecryptHandler h)
: result(h), crypto(c), seckey(secretkey)
{
}
DecryptHandler result;
User* context;
llarp_crypto* crypto;
byte_t* seckey;
EncryptedFrame* target;
void
AsyncDecrypt(llarp_threadpool* worker, EncryptedFrame* frame, User* user)
{
target = frame;
context = user;
llarp_threadpool_queue_job(worker, {this, &Decrypt});
}
};
}
#endif

@ -19,7 +19,7 @@ struct llarp_xi
{
struct in6_addr address;
struct in6_addr netmask;
llarp_pubkey_t pubkey;
byte_t pubkey[PUBKEYSIZE];
};
bool

@ -2,7 +2,6 @@
#define LLARP_IWP_H_
#include <llarp/crypto.h>
#include <llarp/link.h>
#include <llarp/router_identity.h>
#ifdef __cplusplus
extern "C" {

@ -5,7 +5,6 @@
#include <llarp/ev.h>
#include <llarp/logic.h>
#include <llarp/mem.h>
#include <llarp/obmd.h>
#include <stdbool.h>
#include <stdint.h>

@ -3,15 +3,13 @@
#include <llarp/bencode.h>
#include <llarp/link.h>
#include <llarp/aligned.hpp>
#include <llarp/router_id.hpp>
#include <queue>
#include <vector>
namespace llarp
{
typedef AlignedBuffer< 32 > RouterID;
struct ILinkMessage;
typedef std::queue< ILinkMessage* > SendQueue;

@ -0,0 +1,15 @@
#ifndef LLARP_MESSAGES_HPP
#define LLARP_MESSAGES_HPP
/**
include shortcut for all link and routing messages
*/
#include <llarp/messages/dht_immediate.hpp>
#include <llarp/messages/discard.hpp>
#include <llarp/messages/link_intro.hpp>
#include <llarp/messages/relay.hpp>
#include <llarp/messages/relay_ack.hpp>
#include <llarp/messages/relay_commit.hpp>
#endif

@ -0,0 +1,38 @@
#ifndef LLARP_MESSAGES_RELAY_HPP
#define LLARP_MESSAGES_RELAY_HPP
#include <llarp/link_message.hpp>
namespace llarp
{
struct RelayUpstreamMessage : public ILinkMessage
{
RelayUpstreamMessage(const RouterID& from);
~RelayUpstreamMessage();
bool
DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf);
bool
BEncode(llarp_buffer_t* buf) const;
bool
HandleMessage(llarp_router* router) const;
};
struct RelayDownstreamMessage : public ILinkMessage
{
RelayDownstreamMessage(const RouterID& from);
~RelayDownstreamMessage();
bool
DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf);
bool
BEncode(llarp_buffer_t* buf) const;
bool
HandleMessage(llarp_router* router) const;
};
}
#endif

@ -0,0 +1,46 @@
#ifndef LLARP_MESSAGES_RELAY_ACK_HPP
#define LLARP_MESSAGES_RELAY_ACK_HPP
#include <llarp/crypto.hpp>
#include <llarp/encrypted_frame.hpp>
#include <llarp/link_message.hpp>
#include <llarp/path_types.hpp>
namespace llarp
{
struct LR_AckRecord
{
PubKey pubkey;
TunnelNonce nonce;
PathID_t rxPathID;
uint64_t version = 0;
bool
BEncode(llarp_buffer_t* buf) const;
bool
BDecode(llarp_buffer_t* buf);
};
struct LR_AckMessage : public ILinkMessage
{
std::vector< EncryptedFrame > acks;
EncryptedFrame lasthopFrame;
PathID_t txPathID;
uint64_t version = 0;
LR_AckMessage(const RouterID& from);
~LR_AckMessage();
bool
DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf);
bool
BEncode(llarp_buffer_t* buf) const;
bool
HandleMessage(llarp_router* router) const;
};
}
#endif

@ -1,26 +1,33 @@
#ifndef LLARP_RELAY_COMMIT_HPP
#define LLARP_RELAY_COMMIT_HPP
#include <llarp/crypto.h>
#include <llarp/crypto.hpp>
#include <llarp/encrypted_ack.hpp>
#include <llarp/encrypted_frame.hpp>
#include <llarp/link_message.hpp>
#include <llarp/path_types.hpp>
#include <vector>
namespace llarp
{
struct LR_CommitRecord
{
llarp_pubkey_t commkey;
llarp_pubkey_t nextHop;
llarp_tunnel_nonce_t nonce;
uint64_t lifetime;
uint64_t pathid;
PubKey commkey;
PubKey nextHop;
TunnelNonce tunnelNonce;
PathID_t txid;
SymmKey downstreamReplyKey;
SymmNonce downstreamReplyNonce;
uint64_t version;
bool
BDecode(llarp_buffer_t *buf);
bool
BEncode(llarp_buffer_t *buf);
BEncode(llarp_buffer_t *buf) const;
private:
static bool
OnKey(dict_reader *r, llarp_buffer_t *buf);
};
struct LR_AcceptRecord
@ -30,32 +37,26 @@ namespace llarp
std::vector< byte_t > padding;
bool
BDecode(llarp_buffer_t *buf);
bool
BEncode(llarp_buffer_t *buf);
};
struct LR_StatusMessage
{
std::vector< EncryptedFrame > replies;
uint64_t version;
bool
BDecode(llarp_buffer_t *buf);
DecodeKey(llarp_buffer_t key, llarp_buffer_t *buf);
bool
BEncode(llarp_buffer_t *buf);
BEncode(llarp_buffer_t *buf) const;
};
struct LR_CommitMessage : public ILinkMessage
{
std::vector< EncryptedFrame > frames;
EncryptedFrame lasthopFrame;
std::vector< EncryptedAck > acks;
uint64_t version;
LR_CommitMessage() : ILinkMessage()
{
}
LR_CommitMessage(const RouterID &from) : ILinkMessage(from)
{
}
~LR_CommitMessage();
void
@ -70,42 +71,6 @@ namespace llarp
bool
HandleMessage(llarp_router *router) const;
};
struct AsyncPathDecryption
{
static void
Decrypted(void *data);
LR_CommitMessage lrcm;
LR_CommitRecord ourRecord;
llarp_threadpool *worker = nullptr;
llarp_crypto *crypto = nullptr;
llarp_logic *logic = nullptr;
llarp_thread_job result;
void
AsyncDecryptOurHop();
};
struct AsyncPathEncryption
{
static void
EncryptedFrame(void *data);
std::vector< LR_CommitRecord > hops;
LR_CommitMessage lrcm;
llarp_threadpool *worker = nullptr;
llarp_crypto *crypto = nullptr;
llarp_logic *logic = nullptr;
llarp_thread_job result;
void
AsyncEncrypt();
private:
void
EncryptNext();
};
}
#endif

@ -57,14 +57,14 @@ llarp_nodedb_iterate_all(struct llarp_nodedb *n, struct llarp_nodedb_iter i);
*/
bool
llarp_nodedb_find_rc(struct llarp_nodedb *n, struct llarp_rc *rc,
llarp_pubkey_t k);
const byte_t *k);
/**
return true if we have a rc with rc.k of value k on disk
otherwise return false
*/
bool
llarp_nodedb_has_rc(struct llarp_nodedb *n, llarp_pubkey_t k);
llarp_nodedb_has_rc(struct llarp_nodedb *n, const byte_t *k);
/**
put an rc into the node db

@ -1,36 +0,0 @@
#ifndef LLARP_OBMD_H_
#define LLARP_OBMD_H_
#include <llarp/buffer.h>
#include <llarp/crypto.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/* forward decl */
struct llarp_link;
/**
* link layer outbound message sending muxer
*/
struct llarp_link_dispatcher;
struct llarp_link_dispatcher *
llarp_init_link_dispatcher();
void
llarp_free_link_dispatcher(struct llarp_link_dispatcher **dispatcher);
void
llarp_link_sendto(struct llarp_link_dispatcher *dispatcher,
llarp_pubkey_t pubkey, llarp_buffer_t msg);
void
llarp_link_register(struct llarp_link_dispatcher *dispatcher,
struct llarp_link *link);
#ifdef __cplusplus
}
#endif
#endif

@ -1,27 +0,0 @@
#ifndef LLARP_PATH_H
#define LLARP_PATH_H
#ifdef __cplusplus
extern "C" {
#endif
#include <llarp/types.h>
typedef uint64_t llarp_path_id_t;
struct llarp_transit_hop
{
llarp_path_id_t id;
llarp_sharedkey_t symkey;
llarp_pubkey_t nextHop;
llarp_pubkey_t prevHop;
uint64_t started;
uint64_t lifetime;
llarp_proto_version_t version;
};
struct llarp_path_context;
#ifdef __cplusplus
}
#endif
#endif

@ -0,0 +1,297 @@
#ifndef LLARP_PATH_HPP
#define LLARP_PATH_HPP
#include <llarp/router.h>
#include <llarp/time.h>
#include <llarp/aligned.hpp>
#include <llarp/crypto.hpp>
#include <llarp/messages/relay_ack.hpp>
#include <llarp/messages/relay_commit.hpp>
#include <llarp/path_types.hpp>
#include <llarp/router_id.hpp>
#include <mutex>
#include <unordered_map>
#include <vector>
namespace llarp
{
struct TransitHopInfo
{
TransitHopInfo() = default;
TransitHopInfo(const RouterID& down, const LR_CommitRecord& record);
PathID_t rxID;
PathID_t txID;
RouterID upstream;
RouterID downstream;
friend std::ostream&
operator<<(std::ostream& out, const TransitHopInfo& info)
{
out << "<Transit Hop rxid=" << info.rxID << " txid=" << info.txID;
out << " upstream=" << info.upstream << " downstream=" << info.downstream;
return out << ">";
}
bool
operator==(const TransitHopInfo& other) const
{
return rxID == other.rxID && txID == other.txID
&& upstream == other.upstream && downstream == other.downstream;
}
bool
operator!=(const TransitHopInfo& other) const
{
return !(*this == other);
}
struct Hash
{
std::size_t
operator()(TransitHopInfo const& a) const
{
std::size_t idx0, idx1, idx2, idx3;
memcpy(&idx0, a.upstream, sizeof(std::size_t));
memcpy(&idx1, a.downstream, sizeof(std::size_t));
memcpy(&idx2, a.rxID, sizeof(std::size_t));
memcpy(&idx3, a.txID, sizeof(std::size_t));
return idx0 ^ idx1 ^ idx2 ^ idx3;
}
};
};
struct TransitHop
{
TransitHop() = default;
SharedSecret rxKey;
SharedSecret txKey;
llarp_time_t started;
llarp_proto_version_t version;
};
struct PathHopConfig
{
/// path id
PathID_t txID;
/// router identity key
PubKey encryptionKey;
/// shared secret at this hop
SharedSecret shared;
/// nonce for key exchange
TunnelNonce nonce;
};
struct Path
{
typedef std::vector< PathHopConfig > HopList;
HopList hops;
llarp_time_t buildStarted;
};
template < typename User >
struct AsyncPathKeyExchangeContext
{
Path path;
typedef void (*Handler)(AsyncPathKeyExchangeContext*);
User* user = nullptr;
Handler result = nullptr;
const byte_t* secretkey = nullptr;
size_t idx = 0;
llarp_threadpool* worker = nullptr;
llarp_path_dh_func dh = nullptr;
static void
GenerateNextKey(void* user)
{
AsyncPathKeyExchangeContext< User >* ctx =
static_cast< AsyncPathKeyExchangeContext< User >* >(user);
auto& hop = ctx->path.hops[ctx->idx];
ctx->dh(hop.shared, hop.encryptionKey, hop.nonce, ctx->secretkey);
++ctx->idx;
if(ctx->idx < ctx.path.hops.size())
{
llarp_threadpool_queue_job(ctx->worker, {ctx, &GenerateNextKey});
}
else
{
ctx->Done();
}
}
AsyncPathKeyExchangeContext(const byte_t* secret, llarp_crypto* crypto)
: secretkey(secret), dh(crypto->dh_client)
{
}
void
Done()
{
idx = 0;
result(this);
}
/// Generate all keys asynchronously and call hadler when done
void
AsyncGenerateKeys(llarp_threadpool* pool, User* u, Handler func) const
{
user = u;
result = func;
worker = pool;
llarp_threadpool_queue_job(pool, {this, &GenerateNextKey});
}
};
enum PathBuildStatus
{
ePathBuildSuccess,
ePathBuildTimeout,
ePathBuildReject
};
/// path selection algorithm
struct IPathSelectionAlgorithm
{
virtual ~IPathSelectionAlgorithm(){};
/// select full path given an empty hop list to end at target
virtual bool
SelectFullPathTo(Path::HopList& hops, const RouterID& target) = 0;
/// report to path builder the result of a path build
/// can be used to "improve" path building algoirthm in the
/// future
virtual void
ReportPathBuildStatus(const Path::HopList& hops, const RouterID& target,
PathBuildStatus status){};
};
class PathBuildJob
{
public:
PathBuildJob(llarp_router* router, IPathSelectionAlgorithm* selector);
~PathBuildJob();
void
Start();
private:
typedef AsyncPathKeyExchangeContext< PathBuildJob > KeyExchanger;
LR_CommitMessage*
BuildLRCM();
static void
KeysGenerated(KeyExchanger* ctx);
llarp_router* router;
IPathSelectionAlgorithm* m_HopSelector;
KeyExchanger m_KeyExchanger;
};
/// a pool of paths for a hidden service
struct PathPool
{
PathPool(llarp_router* router);
~PathPool();
/// build a new path to a router by identity key
PathBuildJob*
BuildNewPathTo(const RouterID& router);
};
struct PathContext
{
PathContext(llarp_router* router);
~PathContext();
void
AllowTransit();
void
RejectTransit();
bool
HasTransitHop(const TransitHopInfo& info);
bool
HandleRelayCommit(const LR_CommitMessage* msg);
bool
HandleRelayAck(const LR_AckMessage* msg);
void
PutPendingRelayCommit(const RouterID& router, const PathID_t& txid,
const TransitHopInfo& info, const TransitHop& hop);
bool
HasPendingRelayCommit(const RouterID& upstream, const PathID_t& txid);
bool
ForwardLRCM(const RouterID& nextHop, std::deque< EncryptedFrame >& frames,
std::deque< EncryptedAck >& acks, EncryptedFrame& lastFrame);
bool
HopIsUs(const PubKey& k) const;
typedef std::unordered_map< TransitHopInfo, TransitHop,
TransitHopInfo::Hash >
TransitHopsMap_t;
typedef std::pair< std::mutex, TransitHopsMap_t > SyncTransitMap_t;
struct PendingPathKey
{
RouterID upstream;
PathID_t txID;
PendingPathKey(const RouterID& up, const PathID_t& id)
: upstream(up), txID(id)
{
}
bool
operator==(const PendingPathKey& other) const
{
return upstream == other.upstream && txID == other.txID;
}
struct Hash
{
std::size_t
operator()(PendingPathKey const& a) const
{
std::size_t idx0, idx1;
memcpy(&idx0, a.upstream, sizeof(std::size_t));
memcpy(&idx1, a.txID, sizeof(std::size_t));
return idx0 ^ idx1;
}
};
};
typedef std::pair< TransitHopInfo, TransitHop > PendingCommit_t;
typedef std::pair< std::mutex,
std::unordered_map< PendingPathKey, PendingCommit_t,
PendingPathKey::Hash > >
SyncPendingCommitMap_t;
llarp_threadpool*
Worker();
llarp_crypto*
Crypto();
byte_t*
EncryptionSecretKey();
private:
llarp_router* m_Router;
SyncTransitMap_t m_TransitPaths;
SyncPendingCommitMap_t m_WaitingForAcks;
bool m_AllowTransit;
};
}
#endif

@ -0,0 +1,11 @@
#ifndef LLARP_PATH_TYPES_HPP
#define LLARP_PATH_TYPES_HPP
#include <llarp/aligned.hpp>
namespace llarp
{
typedef AlignedBuffer< 16 > PathID_t;
}
#endif

@ -24,6 +24,13 @@ llarp_init_router(struct llarp_threadpool *worker,
void
llarp_free_router(struct llarp_router **router);
/// send raw message to router we have a session with
/// return false on message not sent becasue we don't have a session otherwise
/// return true
bool
llarp_rotuer_sendto(struct llarp_router *router, const byte_t *pubkey,
llarp_buffer_t buf);
bool
llarp_router_try_connect(struct llarp_router *router, struct llarp_rc *remote);

@ -15,9 +15,12 @@ struct llarp_alloc;
struct llarp_rc
{
struct llarp_ai_list *addrs;
llarp_pubkey_t pubkey;
// public encryption public key
byte_t enckey[PUBKEYSIZE];
// public signing public key
byte_t pubkey[PUBKEYSIZE];
struct llarp_xi_list *exits;
llarp_sig_t signature;
byte_t signature[SIGSIZE];
uint64_t last_updated;
};
@ -39,7 +42,7 @@ void
llarp_rc_set_addrs(struct llarp_rc *rc, struct llarp_alloc *mem,
struct llarp_ai_list *addr);
void
llarp_rc_set_pubkey(struct llarp_rc *rc, uint8_t *pubkey);
llarp_rc_set_pubkey(struct llarp_rc *rc, const uint8_t *pubkey);
void
llarp_rc_sign(struct llarp_crypto *crypto, const byte_t *seckey,

@ -0,0 +1,11 @@
#ifndef LLARP_ROUTER_ID_HPP
#define LLARP_ROUTER_ID_HPP
#include <llarp/aligned.hpp>
namespace llarp
{
typedef AlignedBuffer< 32 > RouterID;
}
#endif

@ -1,46 +0,0 @@
#ifndef LLARP_ROUTER_IDENT_H
#define LLARP_ROUTER_IDENT_H
#include <llarp/address_info.h>
#include <llarp/crypto.h>
#include <llarp/exit_info.h>
#include <llarp/router_contact.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* rotuer identity private info
*/
struct llarp_router_ident
{
struct llarp_crypto *crypto;
llarp_seckey_t signkey;
uint64_t updated;
uint16_t version;
struct llarp_ai_list *addrs;
struct llarp_xi_list *exits;
};
void
llarp_router_ident_new(struct llarp_router_ident **ri,
struct llarp_crypto *crypto);
void
llarp_router_ident_append_ai(struct llarp_router_ident *ri,
struct llarp_ai *ai);
bool
llarp_router_ident_bdecode(struct llarp_router_ident *ri, llarp_buffer_t *buf);
bool
llarp_router_ident_bencode(struct llarp_router_ident *ri, llarp_buffer_t *buf);
void
llarp_router_ident_free(struct llarp_router_ident **ri);
bool
llarp_router_ident_generate_rc(struct llarp_router_ident *ri,
struct llarp_rc **rc);
#ifdef __cplusplus
}
#endif
#endif

@ -0,0 +1,21 @@
#ifndef LLARP_ROUTING_ENDPOINT_HPP
#define LLARP_ROUTING_ENDPOINT_HPP
#include <llarp/aligned.hpp>
#include <llarp/buffer.h>
namespace llarp
{
typedef AlignedBuffer<32> RoutingEndpoint_t;
/// Interface for end to end crypto between endpoints
struct IRoutingEndpoint
{
virtual ~IRoutingEndpoint() {};
};
}
#endif

@ -56,10 +56,10 @@ llarp_ai_decode_key(struct dict_reader *r, llarp_buffer_t *key)
if(!bencode_read_string(r->buffer, &strbuf))
return false;
if(strbuf.sz != sizeof(llarp_pubkey_t))
if(strbuf.sz != PUBKEYSIZE)
return false;
memcpy(ai->enc_key, strbuf.base, sizeof(llarp_pubkey_t));
memcpy(ai->enc_key, strbuf.base, PUBKEYSIZE);
return true;
}
@ -154,7 +154,7 @@ llarp_ai_bencode(struct llarp_ai *ai, llarp_buffer_t *buff)
/* encryption key */
if(!bencode_write_bytestring(buff, "e", 1))
return false;
if(!bencode_write_bytestring(buff, ai->enc_key, sizeof(llarp_pubkey_t)))
if(!bencode_write_bytestring(buff, ai->enc_key, PUBKEYSIZE))
return false;
/** ip */
ipstr = inet_ntop(AF_INET6, &ai->ip, ipbuff, sizeof(ipbuff));

@ -132,6 +132,8 @@ bencode_read_dict(llarp_buffer_t* buff, struct dict_reader* r)
if(!r->on_key(r, &strbuf)) // check for early abort
return false;
}
else
return false;
}
if(*r->buffer->cur != 'e') // make sure we're at dictionary end

@ -1,23 +1 @@
#ifndef LLARP_CRYPTO_HPP
#define LLARP_CRYPTO_HPP
#include <llarp/crypto.h>
#include <llarp/aligned.hpp>
namespace llarp
{
typedef AlignedBuffer< PUBKEYSIZE > pubkey;
struct pubkeyhash
{
std::size_t
operator()(pubkey const& a) const noexcept
{
size_t sz = 0;
memcpy(&sz, a.data(), sizeof(size_t));
return sz;
}
};
}
#endif
#include <llarp/crypto.hpp>

@ -2,6 +2,7 @@
#include <llarp/router_contact.h>
#include <llarp/mem.h>
#include <string.h>
#include <llarp/crypto.hpp>
#include "buffer.hpp"
#include "mem.hpp"
@ -43,9 +44,9 @@ namespace iwp
gen_intro(void *user)
{
iwp_async_intro *intro = static_cast< iwp_async_intro * >(user);
llarp_sharedkey_t sharedkey;
llarp_shorthash_t e_k;
llarp_nonce_t n;
llarp::SharedSecret sharedkey;
llarp::ShortHash e_k;
llarp::SymmNonce n;
llarp_crypto *crypto = intro->iwp->crypto;
byte_t tmp[64];
// S = TKE(a.k, b.k, n)
@ -59,7 +60,7 @@ namespace iwp
memcpy(tmp + 32, intro->nonce, 32);
crypto->shorthash(e_k, buf);
// e = SE(a.k, e_k, n[0:24])
memcpy(intro->buf + 64, llarp_seckey_topublic(intro->secretkey), 32);
memcpy(intro->buf + 64, llarp::seckey_topublic(intro->secretkey), 32);
buf.base = intro->buf + 64;
buf.cur = buf.base;
buf.sz = 32;
@ -78,12 +79,12 @@ namespace iwp
{
iwp_async_intro *intro = static_cast< iwp_async_intro * >(user);
auto crypto = intro->iwp->crypto;
llarp_sharedkey_t sharedkey;
llarp_shorthash_t e_K;
llarp_hmac_t h;
llarp_nonce_t N;
llarp::SharedSecret sharedkey;
llarp::ShortHash e_K;
llarp::SharedSecret h;
llarp::SymmNonce N;
byte_t tmp[64];
auto OurPK = llarp_seckey_topublic(intro->secretkey);
auto OurPK = llarp::seckey_topublic(intro->secretkey);
// e_k = HS(b.k + n)
memcpy(tmp, OurPK, 32);
memcpy(tmp + 32, intro->nonce, 32);
@ -129,8 +130,8 @@ namespace iwp
auto crypto = introack->iwp->crypto;
auto logic = introack->iwp->logic;
llarp_hmac_t digest;
llarp_sharedkey_t sharedkey;
llarp::ShortHash digest;
llarp::SharedSecret sharedkey;
auto hmac = introack->buf;
auto body = introack->buf + 32;
@ -171,7 +172,7 @@ namespace iwp
gen_introack(void *user)
{
iwp_async_introack *introack = static_cast< iwp_async_introack * >(user);
llarp_sharedkey_t sharedkey;
llarp::SharedSecret sharedkey;
auto crypto = introack->iwp->crypto;
auto pubkey = introack->remote_pubkey;
auto secretkey = introack->secretkey;
@ -223,8 +224,8 @@ namespace iwp
auto token = session->token;
auto K = session->sessionkey;
llarp_sharedkey_t e_K;
llarp_shorthash_t T;
llarp::SharedSecret e_K;
llarp::ShortHash T;
byte_t tmp[64];
llarp_buffer_t buf;
@ -273,8 +274,8 @@ namespace iwp
auto token = session->token;
auto K = session->sessionkey;
llarp_sharedkey_t e_K;
llarp_shorthash_t T;
llarp::SharedSecret e_K;
llarp::ShortHash T;
byte_t tmp[64];
@ -336,7 +337,7 @@ namespace iwp
byte_t *nonce = frame->buf + 32;
byte_t *body = frame->buf + 64;
llarp_sharedkey_t digest;
llarp::ShortHash digest;
llarp_buffer_t buf;
buf.base = nonce;

@ -1,6 +1,7 @@
#include <assert.h>
#include <llarp/crypto.h>
#include <sodium.h>
#include <llarp/crypto.hpp>
#include "mem.hpp"
namespace llarp
@ -8,7 +9,7 @@ namespace llarp
namespace sodium
{
static bool
xchacha20(llarp_buffer_t buff, llarp_sharedkey_t k, llarp_nonce_t n)
xchacha20(llarp_buffer_t buff, const byte_t *k, const byte_t *n)
{
return crypto_stream_xchacha20_xor(buff.base, buff.base, buff.sz, n, k)
== 0;
@ -18,7 +19,7 @@ namespace llarp
dh(uint8_t *out, uint8_t *client_pk, uint8_t *server_pk, uint8_t *pubkey,
uint8_t *secret)
{
llarp_sharedkey_t shared;
llarp::SharedSecret shared;
crypto_generichash_state h;
const size_t outsz = SHAREDKEYSIZE;
@ -33,26 +34,24 @@ namespace llarp
}
static bool
dh_client(llarp_sharedkey_t *shared, llarp_pubkey_t pk,
llarp_tunnel_nonce_t n, llarp_seckey_t sk)
dh_client(byte_t *shared, byte_t *pk, byte_t *n, byte_t *sk)
{
if(dh(*shared, llarp_seckey_topublic(sk), pk, pk, sk))
if(dh(shared, llarp::seckey_topublic(sk), pk, pk, sk))
{
return crypto_generichash(*shared, SHAREDKEYSIZE, *shared,
SHAREDKEYSIZE, n, TUNNONCESIZE)
return crypto_generichash(shared, SHAREDKEYSIZE, shared, SHAREDKEYSIZE,
n, TUNNONCESIZE)
!= -1;
}
return false;
}
static bool
dh_server(llarp_sharedkey_t *shared, llarp_pubkey_t pk,
llarp_tunnel_nonce_t n, llarp_seckey_t sk)
dh_server(byte_t *shared, byte_t *pk, byte_t *n, byte_t *sk)
{
if(dh(*shared, pk, llarp_seckey_topublic(sk), pk, sk))
if(dh(shared, pk, llarp::seckey_topublic(sk), pk, sk))
{
return crypto_generichash(*shared, SHAREDKEYSIZE, *shared,
SHAREDKEYSIZE, n, TUNNONCESIZE)
return crypto_generichash(shared, SHAREDKEYSIZE, shared, SHAREDKEYSIZE,
n, TUNNONCESIZE)
!= -1;
}
return false;
@ -61,8 +60,8 @@ namespace llarp
static bool
transport_dh_client(uint8_t *shared, uint8_t *pk, uint8_t *sk, uint8_t *n)
{
llarp_sharedkey_t dh_result;
if(dh(dh_result, llarp_seckey_topublic(sk), pk, pk, sk))
llarp::SharedSecret dh_result;
if(dh(dh_result, llarp::seckey_topublic(sk), pk, pk, sk))
{
return crypto_generichash(shared, 32, n, 32, dh_result, 32) != -1;
}
@ -72,8 +71,8 @@ namespace llarp
static bool
transport_dh_server(uint8_t *shared, uint8_t *pk, uint8_t *sk, uint8_t *n)
{
llarp_sharedkey_t dh_result;
if(dh(dh_result, pk, llarp_seckey_topublic(sk), pk, sk))
llarp::SharedSecret dh_result;
if(dh(dh_result, pk, llarp::seckey_topublic(sk), pk, sk))
{
return crypto_generichash(shared, 32, n, 32, dh_result, 32) != -1;
}
@ -138,16 +137,28 @@ namespace llarp
static void
enckeygen(uint8_t *keys)
{
randombytes(keys, 32);
crypto_scalarmult_curve25519_base(keys + 32, keys);
crypto_box_keypair(keys + 32, keys);
}
} // namespace sodium
const byte_t *
seckey_topublic(const byte_t *sec)
{
return sec + 32;
}
byte_t *
seckey_topublic(byte_t *sec)
{
return sec + 32;
}
} // namespace llarp
extern "C" {
uint8_t *
llarp_seckey_topublic(uint8_t *secret)
const byte_t *
llarp_seckey_topublic(const byte_t *secret)
{
return secret + 32;
}

@ -0,0 +1,146 @@
#include <llarp/crypto.hpp>
#include <llarp/encrypted_frame.hpp>
#include "logger.hpp"
namespace llarp
{
Encrypted::Encrypted(const byte_t* buf, size_t sz)
{
size = sz;
data = new byte_t[sz];
if(buf)
memcpy(data, buf, sz);
m_Buffer.base = data;
m_Buffer.cur = data;
m_Buffer.sz = size;
}
Encrypted::Encrypted(size_t sz) : Encrypted(nullptr, sz)
{
}
Encrypted::~Encrypted()
{
if(data)
delete[] data;
}
bool
EncryptedFrame::EncryptInPlace(byte_t* ourSecretKey, byte_t* otherPubkey,
llarp_crypto* crypto)
{
// format of frame is
// <32 bytes keyed hash of following data>
// <32 bytes nonce>
// <32 bytes pubkey>
// <N bytes encrypted payload>
//
byte_t* hash = data;
byte_t* nonce = hash + SHORTHASHSIZE;
byte_t* pubkey = nonce + TUNNONCESIZE;
byte_t* body = pubkey + PUBKEYSIZE;
SharedSecret shared;
auto DH = crypto->dh_client;
auto Encrypt = crypto->xchacha20;
auto MDS = crypto->hmac;
llarp_buffer_t buf;
buf.base = body;
buf.cur = buf.base;
buf.sz = size - OverheadSize;
// set our pubkey
memcpy(pubkey, llarp::seckey_topublic(ourSecretKey), PUBKEYSIZE);
// randomize nonce
crypto->randbytes(nonce, TUNNONCESIZE);
// derive shared key
if(!DH(shared, otherPubkey, nonce, ourSecretKey))
{
llarp::Error("DH failed");
return false;
}
// encrypt body
if(!Encrypt(buf, shared, nonce))
{
llarp::Error("encrypt failed");
return false;
}
// generate message auth
buf.base = nonce;
buf.cur = buf.base;
buf.sz = size - SHORTHASHSIZE;
if(!MDS(hash, buf, shared))
{
llarp::Error("Failed to generate messgae auth");
return false;
}
return true;
}
bool
EncryptedFrame::DecryptInPlace(byte_t* ourSecretKey, llarp_crypto* crypto)
{
if(size <= OverheadSize)
{
llarp::Warn("encrypted frame too small, ", size, " <= ", OverheadSize);
return false;
}
// format of frame is
// <32 bytes keyed hash of following data>
// <32 bytes nonce>
// <32 bytes pubkey>
// <N bytes encrypted payload>
//
byte_t* hash = data;
byte_t* nonce = hash + SHORTHASHSIZE;
byte_t* otherPubkey = nonce + TUNNONCESIZE;
byte_t* body = otherPubkey + PUBKEYSIZE;
// use dh_server becuase we are not the creator of this message
auto DH = crypto->dh_server;
auto Decrypt = crypto->xchacha20;
auto MDS = crypto->hmac;
llarp_buffer_t buf;
buf.base = nonce;
buf.cur = buf.base;
buf.sz = size - SHORTHASHSIZE;
SharedSecret shared;
ShortHash digest;
if(!DH(shared, otherPubkey, nonce, ourSecretKey))
{
llarp::Error("DH failed");
return false;
}
if(!MDS(digest, buf, shared))
{
llarp::Error("Digest failed");
return false;
}
if(memcmp(digest, hash, digest.size()))
{
llarp::Error("message authentication failed");
return false;
}
buf.base = body;
buf.cur = body;
buf.sz = size - OverheadSize;
if(!Decrypt(buf, shared, nonce))
{
llarp::Error("decrypt failed");
return false;
}
return true;
}
}

@ -82,7 +82,7 @@ llarp_xi_bencode(struct llarp_xi *xi, llarp_buffer_t *buff)
/** public key */
if(!bencode_write_bytestring(buff, "k", 1))
return false;
if(!bencode_write_bytestring(buff, xi->pubkey, sizeof(llarp_pubkey_t)))
if(!bencode_write_bytestring(buff, xi->pubkey, PUBKEYSIZE))
return false;
/** version */
@ -128,9 +128,9 @@ llarp_xi_decode_dict(struct dict_reader *r, llarp_buffer_t *key)
{
if(!bencode_read_string(r->buffer, &strbuf))
return false;
if(strbuf.sz != sizeof(llarp_pubkey_t))
if(strbuf.sz != PUBKEYSIZE)
return false;
memcpy(xi->pubkey, strbuf.base, sizeof(llarp_pubkey_t));
memcpy(xi->pubkey, strbuf.base, PUBKEYSIZE);
return true;
}

@ -1,8 +1,21 @@
#ifndef LLARP_FS_HPP
#define LLARP_FS_HPP
#if(__cplusplus >= 201703L)
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
#else
#error "fs support unimplemented"
#include <string>
namespace fs
{
static std::string Sep = "/";
struct path
{
};
}
#endif
#endif

@ -2,6 +2,7 @@
#include <llarp/iwp.h>
#include <llarp/net.h>
#include <llarp/time.h>
#include <llarp/crypto.hpp>
#include "link/encoder.hpp"
#include <sodium/crypto_sign_ed25519.h>
@ -19,7 +20,6 @@
#include <vector>
#include "buffer.hpp"
#include "crypto.hpp"
#include "fs.hpp"
#include "logger.hpp"
#include "mem.hpp"
@ -669,9 +669,9 @@ namespace iwp
llarp_rc *our_router = nullptr;
llarp_rc remote_router;
llarp_seckey_t eph_seckey;
llarp_pubkey_t remote;
llarp_sharedkey_t sessionkey;
llarp::SecretKey eph_seckey;
llarp::PubKey remote;
llarp::SharedSecret sessionkey;
llarp_link_establish_job *establish_job = nullptr;
@ -707,7 +707,7 @@ namespace iwp
: udp(u), crypto(c), iwp(i), logic(l), addr(a), state(eInitial)
{
if(seckey)
memcpy(eph_seckey, seckey, sizeof(llarp_seckey_t));
eph_seckey = seckey;
else
{
c->encryption_keygen(eph_seckey);
@ -735,7 +735,7 @@ namespace iwp
{
session *self = static_cast< session * >(s->impl);
auto id = self->frame.txids++;
llarp_shorthash_t digest;
llarp::ShortHash digest;
self->crypto->shorthash(digest, msg);
transit_message *m = new transit_message(msg, digest, id);
self->add_outbound_message(id, m);
@ -804,7 +804,7 @@ namespace iwp
send_LIM()
{
llarp::Debug("send LIM");
llarp_shorthash_t digest;
llarp::ShortHash digest;
// 64 bytes overhead for link message
byte_t tmp[MAX_RC_SIZE + 64];
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
@ -1233,13 +1233,13 @@ namespace iwp
LinkMap_t m_sessions;
mtx_t m_sessions_Mutex;
typedef std::unordered_map< llarp::pubkey, llarp::Addr, llarp::pubkeyhash >
typedef std::unordered_map< llarp::PubKey, llarp::Addr, llarp::PubKeyHash >
SessionMap_t;
SessionMap_t m_Connected;
mtx_t m_Connected_Mutex;
llarp_seckey_t seckey;
llarp::SecretKey seckey;
server(llarp_router *r, llarp_crypto *c, llarp_logic *l,
llarp_threadpool *w)
@ -1257,7 +1257,7 @@ namespace iwp
// set that src address has identity pubkey
void
MapAddr(const llarp::Addr &src, llarp::pubkey identity)
MapAddr(const llarp::Addr &src, const llarp::PubKey &identity)
{
lock_t lock(m_Connected_Mutex);
m_Connected[identity] = src;
@ -1267,7 +1267,7 @@ namespace iwp
HasSessionToRouter(llarp_link *l, const byte_t *pubkey)
{
server *serv = static_cast< server * >(l->impl);
llarp::pubkey pk(pubkey);
llarp::PubKey pk(pubkey);
lock_t lock(serv->m_Connected_Mutex);
return serv->m_Connected.find(pk) != serv->m_Connected.end();
}
@ -1319,7 +1319,9 @@ namespace iwp
// std::unordered_map< llarp::pubkey, llarp::Addr, llarp::pubkeyhash >
auto itr = std::find_if(
m_Connected.begin(), m_Connected.end(),
[src](const std::pair<llarp::pubkey, llarp::Addr> &item) -> bool { return src == item.second; });
[src](const std::pair< llarp::PubKey, llarp::Addr > &item) -> bool {
return src == item.second;
});
if(itr == std::end(m_Connected))
return;
@ -1414,7 +1416,7 @@ namespace iwp
uint8_t *
pubkey()
{
return llarp_seckey_topublic(seckey);
return llarp::seckey_topublic(seckey);
}
bool
@ -1430,7 +1432,7 @@ namespace iwp
std::ifstream f(keyfile);
if(f.is_open())
{
f.read((char *)seckey, sizeof(llarp_seckey_t));
f.read((char *)seckey.data(), seckey.size());
return true;
}
return false;
@ -1444,7 +1446,7 @@ namespace iwp
std::ofstream f(fname);
if(f.is_open())
{
f.write((char *)seckey, sizeof(llarp_seckey_t));
f.write((char *)seckey.data(), seckey.size());
return true;
}
return false;
@ -1505,7 +1507,7 @@ namespace iwp
auto rxmsg = rx[id];
if(rxmsg->reassemble(msg))
{
llarp_shorthash_t digest;
llarp::ShortHash digest;
auto buf = llarp::Buffer< decltype(msg) >(msg);
router->crypto.shorthash(digest, buf);
if(memcmp(digest, rxmsg->msginfo.hash(), 32))
@ -1825,7 +1827,7 @@ namespace iwp
link->put_session(dst, s);
}
s->establish_job = job;
s->frame.alive(); // mark it alive
s->frame.alive(); // mark it alive
s->introduce(job->ai.enc_key);
}
return true;

@ -1,9 +1,5 @@
#include <llarp/router_contact.h>
#include <llarp/link_message.hpp>
#include <llarp/messages/dht_immediate.hpp>
#include <llarp/messages/discard.hpp>
#include <llarp/messages/link_intro.hpp>
#include <llarp/messages/relay_commit.hpp>
#include <llarp/messages.hpp>
#include "buffer.hpp"
#include "logger.hpp"
#include "router.hpp"
@ -37,30 +33,40 @@ namespace llarp
// we are expecting the first key to be 'a'
if(!llarp_buffer_eq(*key, "a"))
{
llarp::Warn(__FILE__, "message has no message type");
llarp::Warn("message has no message type");
return false;
}
if(!bencode_read_string(r->buffer, &strbuf))
{
llarp::Warn(__FILE__, "could not read value of message type");
llarp::Warn("could not read value of message type");
return false;
}
// bad key size
if(strbuf.sz != 1)
{
llarp::Warn(__FILE__, "bad mesage type size: ", strbuf.sz);
llarp::Warn("bad mesage type size: ", strbuf.sz);
return false;
}
// create the message to parse based off message type
switch(*strbuf.cur)
{
case 'i':
handler->msg = new LinkIntroMessage(
handler->from->get_remote_router(handler->from));
break;
case 'd':
handler->msg = new RelayDownstreamMessage(handler->GetCurrentFrom());
break;
case 'u':
handler->msg = new RelayUpstreamMessage(handler->GetCurrentFrom());
break;
case 'm':
handler->msg = new DHTImmeidateMessage(handler->GetCurrentFrom());
break;
case 'a':
handler->msg = new LR_AckMessage(handler->GetCurrentFrom());
break;
case 'c':
handler->msg = new LR_CommitMessage(handler->GetCurrentFrom());
break;

@ -53,15 +53,16 @@ llarp_getifaddr(const char* ifname, int af, struct sockaddr* addr)
if(af == AF_INET)
sl = sizeof(sockaddr_in);
#ifdef AF_LINK
//printf("AF_INET[%d]\n", AF_INET); // FBSD 2
//printf("AF_INET6[%d]\n", AF_INET6); // FBSD 28
//printf("AF_LINK[%d]\n", AF_LINK); // FBSD 18
if(af == AF_LINK) {
// printf("AF_INET[%d]\n", AF_INET); // FBSD 2
// printf("AF_INET6[%d]\n", AF_INET6); // FBSD 28
// printf("AF_LINK[%d]\n", AF_LINK); // FBSD 18
if(af == AF_LINK)
{
printf("We dont support AF_LINK yet\n");
}
#endif
#ifdef AF_PACKET
//printf("AF_PACKET[%d]\n", AF_PACKET); // FBSD dne
// printf("AF_PACKET[%d]\n", AF_PACKET); // FBSD dne
if(af == AF_PACKET)
sl = sizeof(sockaddr_ll);
#endif
@ -72,10 +73,11 @@ llarp_getifaddr(const char* ifname, int af, struct sockaddr* addr)
{
if(i->ifa_addr)
{
//llarp::Info(__FILE__, "scanning ", i->ifa_name, " af: ", std::to_string(i->ifa_addr->sa_family));
// llarp::Info(__FILE__, "scanning ", i->ifa_name, " af: ",
// std::to_string(i->ifa_addr->sa_family));
if(llarp::StrEq(i->ifa_name, ifname) && i->ifa_addr->sa_family == af)
{
//llarp::Info(__FILE__, "found ", ifname, " af: ", af);
// llarp::Info(__FILE__, "found ", ifname, " af: ", af);
memcpy(addr, i->ifa_addr, sl);
if(af == AF_INET6)
{

@ -1,15 +1,15 @@
#include <llarp/crypto_async.h>
#include <llarp/nodedb.h>
#include <llarp/router_contact.h>
#include <llarp/crypto_async.h>
#include <fstream>
#include <map>
#include <llarp/crypto.hpp>
#include <unordered_map>
#include "buffer.hpp"
#include "crypto.hpp"
#include "fs.hpp"
#include "mem.hpp"
#include "encode.hpp"
#include "fs.hpp"
#include "logger.hpp"
#include "mem.hpp"
static const char skiplist_subdirs[] = "0123456789ABCDEF";
@ -20,7 +20,8 @@ struct llarp_nodedb
}
llarp_crypto *crypto;
std::map< llarp::pubkey, llarp_rc * > entries;
//std::map< llarp::pubkey, llarp_rc * > entries;
std::unordered_map< llarp::PubKey, llarp_rc *, llarp::PubKeyHash > entries;
fs::path nodePath;
void
@ -34,47 +35,43 @@ struct llarp_nodedb
}
}
inline llarp::pubkey getPubKeyFromRC(llarp_rc *rc)
{
llarp::pubkey pk;
memcpy(pk.data(), rc->pubkey, pk.size());
return pk;
}
llarp_rc *getRC(llarp::pubkey pk)
llarp_rc *
getRC(llarp::PubKey pk)
{
return entries[pk];
}
bool pubKeyExists(llarp_rc *rc)
bool
pubKeyExists(llarp_rc *rc)
{
// extract pk from rc
llarp::pubkey pk = getPubKeyFromRC(rc);
llarp::PubKey pk = rc->pubkey;
// return true if we found before end
return entries.find(pk) != entries.end();
}
bool check(llarp_rc *rc)
bool
check(llarp_rc *rc)
{
if (!pubKeyExists(rc))
if(!pubKeyExists(rc))
{
// we don't have it
return false;
}
llarp::pubkey pk = getPubKeyFromRC(rc);
llarp::PubKey pk = rc->pubkey;
// TODO: zero out any fields you don't want to compare
// serialize both and memcmp
byte_t nodetmp[MAX_RC_SIZE];
auto nodebuf = llarp::StackBuffer< decltype(nodetmp) >(nodetmp);
if (llarp_rc_bencode(entries[pk], &nodebuf))
if(llarp_rc_bencode(entries[pk], &nodebuf))
{
byte_t paramtmp[MAX_RC_SIZE];
auto parambuf = llarp::StackBuffer< decltype(paramtmp) >(paramtmp);
if (llarp_rc_bencode(rc, &parambuf))
if(llarp_rc_bencode(rc, &parambuf))
{
if (memcmp(&parambuf, &nodebuf, MAX_RC_SIZE) == 0)
if(memcmp(&parambuf, &nodebuf, MAX_RC_SIZE) == 0)
{
return true;
}
@ -83,21 +80,23 @@ struct llarp_nodedb
return false;
}
bool setRC(llarp_rc *rc) {
bool
setRC(llarp_rc *rc)
{
byte_t tmp[MAX_RC_SIZE];
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
// extract pk from rc
llarp::pubkey pk = getPubKeyFromRC(rc);
llarp::PubKey pk = rc->pubkey;
// set local db
entries[pk] = rc;
if (llarp_rc_bencode(rc, &buf))
if(llarp_rc_bencode(rc, &buf))
{
char ftmp[68] = {0};
const char *hexname =
llarp::HexEncode< llarp::pubkey, decltype(ftmp) >(pk, ftmp);
llarp::HexEncode< llarp::PubKey, decltype(ftmp) >(pk, ftmp);
std::string hexString(hexname);
std::string filepath = nodePath;
filepath.append("/");
@ -107,13 +106,15 @@ struct llarp_nodedb
filepath.append(".signed.txt");
llarp::Info("saving RC.pubkey ", filepath);
// write buf to disk
//auto filename = hexStr(pk.data(), sizeof(pk)) + ".rc";
// auto filename = hexStr(pk.data(), sizeof(pk)) + ".rc";
// FIXME: path?
//printf("filename[%s]\n", filename.c_str());
std::ofstream ofs (filepath, std::ofstream::out & std::ofstream::binary & std::ofstream::trunc);
// printf("filename[%s]\n", filename.c_str());
std::ofstream ofs(
filepath,
std::ofstream::out & std::ofstream::binary & std::ofstream::trunc);
ofs.write((char *)buf.base, buf.sz);
ofs.close();
if (!ofs)
if(!ofs)
{
llarp::Error("Failed to write: ", filepath);
return false;
@ -188,8 +189,7 @@ struct llarp_nodedb
{
if(llarp_rc_verify_sig(crypto, rc))
{
llarp::pubkey pk;
memcpy(pk.data(), rc->pubkey, pk.size());
llarp::PubKey pk(&rc->pubkey[0]);
entries[pk] = rc;
return true;
}
@ -216,37 +216,46 @@ struct llarp_nodedb
};
// call request hook
void logic_threadworker_callback(void *user) {
void
logic_threadworker_callback(void *user)
{
llarp_async_verify_rc *verify_request =
static_cast < llarp_async_verify_rc * >(user);
static_cast< llarp_async_verify_rc * >(user);
verify_request->hook(verify_request);
}
// write it to disk
void disk_threadworker_setRC(void *user) {
void
disk_threadworker_setRC(void *user)
{
llarp_async_verify_rc *verify_request =
static_cast < llarp_async_verify_rc * >(user);
static_cast< llarp_async_verify_rc * >(user);
verify_request->valid = verify_request->nodedb->setRC(&verify_request->rc);
llarp_logic_queue_job(verify_request->logic, { verify_request, &logic_threadworker_callback });
llarp_logic_queue_job(verify_request->logic,
{verify_request, &logic_threadworker_callback});
}
// we run the crypto verify in the crypto threadpool worker
void crypto_threadworker_verifyrc(void *user)
void
crypto_threadworker_verifyrc(void *user)
{
llarp_async_verify_rc *verify_request =
static_cast< llarp_async_verify_rc * >(user);
verify_request->valid = llarp_rc_verify_sig(verify_request->nodedb->crypto, &verify_request->rc);
static_cast< llarp_async_verify_rc * >(user);
verify_request->valid =
llarp_rc_verify_sig(verify_request->nodedb->crypto, &verify_request->rc);
// if it's valid we need to set it
if (verify_request->valid)
if(verify_request->valid)
{
llarp::Debug("RC is valid, saving to disk");
llarp_threadpool_queue_job(verify_request->diskworker,
{ verify_request, &disk_threadworker_setRC });
} else {
{verify_request, &disk_threadworker_setRC});
}
else
{
// callback to logic thread
llarp::Warn("RC is not valid, can't save to disk");
llarp_logic_queue_job(verify_request->logic,
{ verify_request, &logic_threadworker_callback });
{verify_request, &logic_threadworker_callback});
}
}
@ -312,13 +321,14 @@ void
llarp_nodedb_async_verify(struct llarp_async_verify_rc *job)
{
// switch to crypto threadpool and continue with crypto_threadworker_verifyrc
llarp_threadpool_queue_job(job->cryptoworker, { job, &crypto_threadworker_verifyrc });
llarp_threadpool_queue_job(job->cryptoworker,
{job, &crypto_threadworker_verifyrc});
}
bool
llarp_nodedb_find_rc(struct llarp_nodedb *nodedb, struct llarp_rc *dst,
llarp_pubkey_t k)
const byte_t *k)
{
return false;
} // end function
} // end extern
} // end function
} // end extern

@ -0,0 +1,229 @@
#include <deque>
#include <llarp/encrypted_frame.hpp>
#include <llarp/path.hpp>
#include "router.hpp"
namespace llarp
{
PathContext::PathContext(llarp_router* router)
: m_Router(router), m_AllowTransit(false)
{
}
PathContext::~PathContext()
{
}
void
PathContext::AllowTransit()
{
m_AllowTransit = true;
}
struct LRCMFrameDecrypt
{
typedef AsyncFrameDecrypter< LRCMFrameDecrypt > Decrypter;
Decrypter* decrypter;
std::deque< EncryptedFrame > frames;
std::deque< EncryptedAck > acks;
EncryptedFrame lastFrame;
PathContext* context;
RouterID from;
LR_CommitRecord record;
LRCMFrameDecrypt(PathContext* ctx, Decrypter* dec,
const LR_CommitMessage* commit)
: decrypter(dec)
, lastFrame(commit->lasthopFrame)
, context(ctx)
, from(commit->remote)
{
for(const auto& f : commit->frames)
frames.push_front(f);
for(const auto& a : commit->acks)
acks.push_front(a);
}
~LRCMFrameDecrypt()
{
delete decrypter;
}
static void
HandleDecrypted(llarp_buffer_t* buf, LRCMFrameDecrypt* self)
{
if(!buf)
{
llarp::Error("LRCM decrypt failed from ", self->from);
delete self;
return;
}
llarp::Debug("decrypted LRCM from ", self->from);
// successful decrypt
if(!self->record.BDecode(buf))
{
llarp::Error("malformed frame inside LRCM from ", self->from);
delete self;
return;
}
TransitHopInfo info(self->from, self->record);
if(self->context->HasTransitHop(info))
{
llarp::Error("duplicate transit hop ", info);
delete self;
return;
}
TransitHop hop;
// choose rx id
// TODO: check for duplicates
info.rxID.Randomize();
// generate tx key as we are in a worker thread
auto DH = self->context->Crypto()->dh_server;
if(!DH(hop.txKey, self->record.commkey,
self->context->EncryptionSecretKey(), self->record.tunnelNonce))
{
llarp::Error("LRCM DH Failed ", info);
delete self;
return;
}
if(self->context->HopIsUs(self->record.nextHop))
{
// we are the farthest hop
llarp::Info("We are the farthest hop for ", info);
}
else
{
llarp::Info("Accepted ", info);
self->context->PutPendingRelayCommit(info.upstream, info.txID, info,
hop);
size_t sz = self->frames.front().size;
// we pop the front element it was ours
self->frames.pop_front();
// put random on the end
// TODO: should this be an encrypted frame?
self->frames.emplace_back(sz);
self->frames.back().Randomize();
// forward upstream
self->context->ForwardLRCM(info.upstream, self->frames, self->acks,
self->lastFrame);
}
}
};
bool
PathContext::HandleRelayCommit(const LR_CommitMessage* commit)
{
if(!m_AllowTransit)
{
llarp::Error("got LRCM from ", commit->remote,
" when not allowing transit traffic");
return false;
}
if(commit->frames.size() <= 1)
{
llarp::Error("got LRCM with too few frames from ", commit->remote);
return false;
}
LRCMFrameDecrypt::Decrypter* decrypter =
new LRCMFrameDecrypt::Decrypter(&m_Router->crypto, m_Router->encryption,
&LRCMFrameDecrypt::HandleDecrypted);
// copy frames so we own them
LRCMFrameDecrypt* frames = new LRCMFrameDecrypt(this, decrypter, commit);
// decrypt frames async
decrypter->AsyncDecrypt(m_Router->tp, &frames->frames.front(), frames);
return true;
}
llarp_threadpool*
PathContext::Worker()
{
return m_Router->tp;
}
llarp_crypto*
PathContext::Crypto()
{
return &m_Router->crypto;
}
byte_t*
PathContext::EncryptionSecretKey()
{
return m_Router->encryption;
}
bool
PathContext::HopIsUs(const PubKey& k) const
{
return memcmp(k, m_Router->pubkey(), PUBKEYSIZE) == 0;
}
bool
PathContext::ForwardLRCM(const RouterID& nextHop,
std::deque< EncryptedFrame >& frames,
std::deque< EncryptedAck >& acks,
EncryptedFrame& lastHop)
{
LR_CommitMessage* msg = new LR_CommitMessage;
while(frames.size())
{
msg->frames.push_back(frames.front());
frames.pop_front();
}
while(acks.size())
{
msg->acks.push_back(acks.front());
acks.pop_front();
}
msg->lasthopFrame = lastHop;
return m_Router->SendToOrQueue(nextHop, {msg});
}
template < typename Map_t, typename Value_t >
bool
MapHas(Map_t& map, const Value_t& val)
{
std::unique_lock< std::mutex > lock(map.first);
return map.second.find(val) != map.second.end();
}
template < typename Map_t, typename Key_t, typename Value_t >
void
MapPut(Map_t& map, const Key_t& k, const Value_t& v)
{
std::unique_lock< std::mutex > lock(map.first);
map.second[k] = v;
}
bool
PathContext::HasTransitHop(const TransitHopInfo& info)
{
return MapHas(m_TransitPaths, info);
}
void
PathContext::PutPendingRelayCommit(const RouterID& upstream,
const PathID_t& txid,
const TransitHopInfo& info,
const TransitHop& hop)
{
MapPut(m_WaitingForAcks, PendingPathKey(upstream, txid),
std::make_pair(info, hop));
}
bool
PathContext::HasPendingRelayCommit(const RouterID& upstream,
const PathID_t& txid)
{
return MapHas(m_WaitingForAcks, PendingPathKey(upstream, txid));
}
TransitHopInfo::TransitHopInfo(const RouterID& down,
const LR_CommitRecord& record)
: txID(record.txid), upstream(record.nextHop), downstream(down)
{
}
}

@ -0,0 +1,91 @@
#include <llarp/messages/relay_ack.hpp>
#include "router.hpp"
namespace llarp
{
bool
LR_AckRecord::BEncode(llarp_buffer_t* buf) const
{
return false;
}
bool
LR_AckRecord::BDecode(llarp_buffer_t* buf)
{
return false;
}
LR_AckMessage::LR_AckMessage(const RouterID& from) : ILinkMessage(from)
{
}
LR_AckMessage::~LR_AckMessage()
{
}
bool
LR_AckMessage::BEncode(llarp_buffer_t* buf) const
{
return false;
}
bool
LR_AckMessage::DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf)
{
return false;
}
struct LRAM_Decrypt
{
typedef AsyncFrameDecrypter< LRAM_Decrypt > Decrypter;
llarp_router* router;
Decrypter* decrypt;
std::vector< EncryptedFrame > frames;
LR_AckRecord record;
LRAM_Decrypt(llarp_router* r, byte_t* seckey,
const std::vector< EncryptedFrame >& f)
: router(r), frames(f)
{
decrypt = new Decrypter(&r->crypto, seckey, &Decrypted);
}
~LRAM_Decrypt()
{
delete decrypt;
}
static void
Decrypted(llarp_buffer_t* buf, LRAM_Decrypt* self)
{
if(!buf)
{
llarp::Error("Failed to decrypt LRAM frame");
delete self;
return;
}
if(!self->record.BDecode(buf))
{
llarp::Error("LRAR invalid format");
delete self;
return;
}
}
};
bool
LR_AckMessage::HandleMessage(llarp_router* router) const
{
if(!router->paths.HasPendingRelayCommit(remote, txPathID))
{
llarp::Warn("got LRAM from ", remote,
" with no previous LRCM txid=", txPathID);
return false;
}
// TODO: use different private key for different path contexts as client
LRAM_Decrypt* lram = new LRAM_Decrypt(router, router->encryption, acks);
lram->decrypt->AsyncDecrypt(router->tp, &lram->frames[0], lram);
return true;
}
}

@ -1,4 +1,7 @@
#include <llarp/bencode.hpp>
#include <llarp/messages/relay_commit.hpp>
#include "logger.hpp"
#include "router.hpp"
namespace llarp
{
@ -9,21 +12,117 @@ namespace llarp
bool
LR_CommitMessage::DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf)
{
// TODO: implement
return false;
if(llarp_buffer_eq(key, "c"))
{
return BEncodeReadList(frames, buf);
}
if(llarp_buffer_eq(key, "f"))
{
return lasthopFrame.BDecode(buf);
}
if(llarp_buffer_eq(key, "r"))
{
return BEncodeReadList(acks, buf);
}
bool read = false;
if(!BEncodeMaybeReadVersion("v", version, LLARP_PROTO_VERSION, read, key,
buf))
return false;
return read;
}
bool
LR_CommitMessage::BEncode(llarp_buffer_t* buf) const
{
// TODO: implement
return false;
if(!bencode_start_dict(buf))
return false;
// msg type
if(!BEncodeWriteDictMsgType(buf, "a", "c"))
return false;
// frames
if(!BEncodeWriteDictList("c", frames, buf))
return false;
// last hop
if(!BEncodeWriteDictEntry("f", lasthopFrame, buf))
return false;
// acks
if(!BEncodeWriteDictList("r", acks, buf))
return false;
// version
if(!bencode_write_version_entry(buf))
return false;
return bencode_end(buf);
}
bool
LR_CommitMessage::HandleMessage(llarp_router* router) const
{
// TODO: implement
return false;
return router->paths.HandleRelayCommit(this);
}
bool
LR_CommitRecord::BEncode(llarp_buffer_t* buf) const
{
if(!bencode_start_dict(buf))
return false;
if(!BEncodeWriteDictEntry("c", commkey, buf))
return false;
if(!BEncodeWriteDictEntry("i", nextHop, buf))
return false;
if(!BEncodeWriteDictEntry("n", tunnelNonce, buf))
return false;
if(!BEncodeWriteDictEntry("p", txid, buf))
return false;
if(!BEncodeWriteDictEntry("s", downstreamReplyKey, buf))
return false;
if(!BEncodeWriteDictEntry("u", downstreamReplyNonce, buf))
return false;
if(!bencode_write_version_entry(buf))
return false;
return bencode_end(buf);
}
bool
LR_CommitRecord::OnKey(dict_reader* r, llarp_buffer_t* key)
{
if(!key)
return true;
LR_CommitRecord* self = static_cast< LR_CommitRecord* >(r->user);
bool read = false;
if(!BEncodeMaybeReadDictEntry("c", self->commkey, read, *key, r->buffer))
return false;
if(!BEncodeMaybeReadDictEntry("i", self->nextHop, read, *key, r->buffer))
return false;
if(BEncodeMaybeReadDictEntry("n", self->tunnelNonce, read, *key, r->buffer))
return false;
if(!BEncodeMaybeReadDictEntry("p", self->txid, read, *key, r->buffer))
return false;
if(!BEncodeMaybeReadDictEntry("s", self->downstreamReplyKey, read, *key,
r->buffer))
return false;
if(!BEncodeMaybeReadDictEntry("u", self->downstreamReplyNonce, read, *key,
r->buffer))
return false;
if(!BEncodeMaybeReadVersion("v", self->version, LLARP_PROTO_VERSION, read,
*key, r->buffer))
return false;
return read;
}
bool
LR_CommitRecord::BDecode(llarp_buffer_t* buf)
{
dict_reader r;
r.user = this;
r.on_key = &OnKey;
return bencode_read_dict(buf, &r);
}
}

@ -0,0 +1,59 @@
#include <llarp/messages/relay.hpp>
namespace llarp
{
RelayUpstreamMessage::RelayUpstreamMessage(const RouterID &from)
: ILinkMessage(from)
{
}
RelayUpstreamMessage::~RelayUpstreamMessage()
{
}
bool
RelayUpstreamMessage::BEncode(llarp_buffer_t *buf) const
{
// TODO: implement me
return false;
}
bool
RelayUpstreamMessage::DecodeKey(llarp_buffer_t key, llarp_buffer_t *buf)
{
return false;
}
bool
RelayUpstreamMessage::HandleMessage(llarp_router *router) const
{
return false;
}
RelayDownstreamMessage::RelayDownstreamMessage(const RouterID &from)
: ILinkMessage(from)
{
}
RelayDownstreamMessage::~RelayDownstreamMessage()
{
}
bool
RelayDownstreamMessage::BEncode(llarp_buffer_t *buf) const
{
// TODO: implement me
return false;
}
bool
RelayDownstreamMessage::DecodeKey(llarp_buffer_t key, llarp_buffer_t *buf)
{
return false;
}
bool
RelayDownstreamMessage::HandleMessage(llarp_router *router) const
{
return false;
}
}

@ -29,7 +29,8 @@ namespace llarp
} // namespace llarp
llarp_router::llarp_router()
: ready(false), dht(llarp_dht_context_new(this)), inbound_msg_parser(this)
: ready(false), paths(this), inbound_msg_parser(this)
{
llarp_rc_clear(&rc);
}
@ -70,10 +71,8 @@ llarp_router::SendToOrQueue(const llarp::RouterID &remote,
{
llarp_rc rc;
llarp_rc_clear(&rc);
llarp_pubkey_t k;
memcpy(k, remote, sizeof(llarp_pubkey_t));
if(!llarp_nodedb_find_rc(nodedb, &rc, k))
if(!llarp_nodedb_find_rc(nodedb, &rc, remote))
{
llarp::Warn("cannot find router ", remote, " locally so we are dropping ",
msgs.size(), " messages to them");
@ -98,7 +97,7 @@ llarp_router::SendToOrQueue(const llarp::RouterID &remote,
for(const auto &msg : msgs)
{
outboundMesssageQueue[remote].push(msg);
outboundMesssageQueue[remote.data()].push(msg);
}
FlushOutboundFor(remote, chosen);
return true;
@ -154,9 +153,38 @@ llarp_router::try_connect(fs::path rcfile)
bool
llarp_router::EnsureIdentity()
{
if(!EnsureEncryptionKey())
return false;
return llarp_findOrCreateIdentity(&crypto, ident_keyfile.c_str(), identity);
}
bool
llarp_router::EnsureEncryptionKey()
{
std::error_code ec;
if(!fs::exists(encryption_keyfile, ec))
{
llarp::Info("generating encryption key");
crypto.encryption_keygen(encryption);
std::ofstream f(encryption_keyfile, std::ios::binary);
if(!f.is_open())
{
llarp::Error("could not save encryption private key to ",
encryption_keyfile, " ", ec);
return false;
}
f.write((char *)encryption.data(), encryption.size());
}
std::ifstream f(encryption_keyfile, std::ios::binary);
if(!f.is_open())
{
llarp::Error("could not read ", encryption_keyfile);
return false;
}
f.read((char *)encryption.data(), encryption.size());
return true;
}
void
llarp_router::AddInboundLink(struct llarp_link *link)
{
@ -258,27 +286,28 @@ llarp_router::on_verify_server_rc(llarp_async_verify_rc *job)
llarp::Debug("rc verified");
// track valid router in dht
llarp::pubkey pubkey;
memcpy(&pubkey[0], job->rc.pubkey, pubkey.size());
llarp::PubKey pk(job->rc.pubkey);
// refresh valid routers RC value if it's there
auto v = router->validRouters.find(pubkey);
auto v = router->validRouters.find(pk);
if(v != router->validRouters.end())
{
// free previous RC members
llarp_rc_free(&v->second);
}
router->validRouters[pubkey] = job->rc;
router->validRouters[pk] = job->rc;
// TODO: update nodedb here (?)
// track valid router in dht
llarp_dht_put_local_router(router->dht, &router->validRouters[pubkey]);
if(router->dht)
llarp_dht_put_local_router(router->dht, &router->validRouters[pk]);
// this was an outbound establish job
if(ctx->establish_job->session)
{
auto session = ctx->establish_job->session;
router->FlushOutboundFor(pubkey, session->get_parent(session));
router->FlushOutboundFor(pk, session->get_parent(session));
}
llarp_rc_free(&job->rc);
delete job;
@ -457,7 +486,8 @@ llarp_router::Run()
link->get_our_address(link, &addr);
llarp_ai_list_pushback(rc.addrs, &addr);
};
// set public key
// set public keys
memcpy(rc.enckey, llarp::seckey_topublic(encryption), PUBKEYSIZE);
llarp_rc_set_pubkey(&rc, pubkey());
llarp_rc_sign(&crypto, identity, &rc);
@ -467,31 +497,49 @@ llarp_router::Run()
return;
}
llarp::pubkey ourPubkey = pubkey();
llarp::Info("our router has public key ", ourPubkey);
llarp_dht_context_start(dht, ourPubkey);
llarp::Debug("starting outbound link");
if(!outboundLink->start_link(outboundLink, logic))
{
llarp::Warn("outbound link failed to start");
}
int IBLinksStarted = 0;
// start links
for(auto link : inboundLinks)
{
if(link->start_link(link, logic))
{
llarp::Debug("Link ", link->name(), " started");
IBLinksStarted++;
}
else
llarp::Warn("Link ", link->name(), " failed to start");
}
if(IBLinksStarted > 0)
{
// initialize as service node
InitServiceNode();
}
llarp_logic_call_later(logic, {1000, this, &ConnectAll});
ScheduleTicker(500);
}
void
llarp_router::InitServiceNode()
{
llarp::PubKey ourPubkey = pubkey();
llarp::Info("starting dht context as ", ourPubkey);
dht = llarp_dht_context_new(this);
llarp_dht_context_start(dht, ourPubkey);
llarp::Info("accepting transit traffic");
paths.AllowTransit();
}
void
llarp_router::ConnectAll(void *user, uint64_t orig, uint64_t left)
{
@ -656,7 +704,7 @@ llarp_rc_set_addrs(struct llarp_rc *rc, struct llarp_alloc *mem,
}
void
llarp_rc_set_pubkey(struct llarp_rc *rc, uint8_t *pubkey)
llarp_rc_set_pubkey(struct llarp_rc *rc, const uint8_t *pubkey)
{
// set public key
memcpy(rc->pubkey, pubkey, 32);
@ -676,13 +724,13 @@ llarp_findOrCreateIdentity(llarp_crypto *crypto, const char *fpath,
std::ofstream f(path, std::ios::binary);
if(f.is_open())
{
f.write((char *)secretkey, sizeof(llarp_seckey_t));
f.write((char *)secretkey, SECKEYSIZE);
}
}
std::ifstream f(path, std::ios::binary);
if(f.is_open())
{
f.read((char *)secretkey, sizeof(llarp_seckey_t));
f.read((char *)secretkey, SECKEYSIZE);
return true;
}
llarp::Info("failed to get identity key");
@ -827,6 +875,10 @@ namespace llarp
}
else if(StrEq(section, "router"))
{
if(StrEq(key, "encryption-privkey"))
{
self->encryption_keyfile = val;
}
if(StrEq(key, "contact-file"))
{
self->our_rc_file = val;

@ -3,9 +3,9 @@
#include <llarp/dht.h>
#include <llarp/link.h>
#include <llarp/nodedb.h>
#include <llarp/path.h>
#include <llarp/router.h>
#include <llarp/router_contact.h>
#include <llarp/path.hpp>
#include <functional>
#include <list>
@ -41,6 +41,8 @@ struct llarp_router
// long term identity key
fs::path ident_keyfile = "identity.key";
fs::path encryption_keyfile = "encryption.key";
// path to write our self signed rc to
fs::path our_rc_file = "rc.signed";
@ -51,10 +53,11 @@ struct llarp_router
llarp_threadpool *tp;
llarp_logic *logic;
llarp_crypto crypto;
llarp_path_context *paths;
llarp_seckey_t identity;
llarp::PathContext paths;
llarp::SecretKey identity;
llarp::SecretKey encryption;
llarp_threadpool *disk;
llarp_dht_context *dht;
llarp_dht_context *dht = nullptr;
llarp_nodedb *nodedb;
@ -74,11 +77,11 @@ struct llarp_router
typedef std::queue< llarp::ILinkMessage * > MessageQueue;
/// outbound message queue
std::unordered_map< llarp::pubkey, MessageQueue, llarp::pubkeyhash >
std::unordered_map< llarp::PubKey, MessageQueue, llarp::PubKeyHash >
outboundMesssageQueue;
/// loki verified routers
std::unordered_map< llarp::pubkey, llarp_rc, llarp::pubkeyhash > validRouters;
std::unordered_map< llarp::PubKey, llarp_rc, llarp::PubKeyHash > validRouters;
llarp_router();
~llarp_router();
@ -92,6 +95,10 @@ struct llarp_router
bool
InitOutboundLink();
/// initialize us as a service node
void
InitServiceNode();
void
Close();
@ -107,13 +114,16 @@ struct llarp_router
bool
EnsureIdentity();
bool
EnsureEncryptionKey();
bool
SaveRC();
uint8_t *
pubkey()
const byte_t *
pubkey() const
{
return llarp_seckey_topublic(identity);
return llarp::seckey_topublic(identity);
}
void

@ -1,7 +1,7 @@
#include <llarp/bencode.h>
#include <llarp/router_contact.h>
#include <llarp/version.h>
#include <llarp/crypto.hpp>
#include "buffer.hpp"
#include "logger.hpp"
@ -49,9 +49,19 @@ llarp_rc_decode_dict(struct dict_reader *r, llarp_buffer_t *key)
{
if(!bencode_read_string(r->buffer, &strbuf))
return false;
if(strbuf.sz != sizeof(llarp_pubkey_t))
if(strbuf.sz != PUBKEYSIZE)
return false;
memcpy(rc->pubkey, strbuf.base, PUBKEYSIZE);
return true;
}
if(llarp_buffer_eq(*key, "p"))
{
if(!bencode_read_string(r->buffer, &strbuf))
return false;
if(strbuf.sz != PUBKEYSIZE)
return false;
memcpy(rc->pubkey, strbuf.base, sizeof(llarp_pubkey_t));
memcpy(rc->enckey, strbuf.base, PUBKEYSIZE);
return true;
}
@ -83,9 +93,9 @@ llarp_rc_decode_dict(struct dict_reader *r, llarp_buffer_t *key)
{
if(!bencode_read_string(r->buffer, &strbuf))
return false;
if(strbuf.sz != sizeof(llarp_sig_t))
if(strbuf.sz != SIGSIZE)
return false;
memcpy(rc->signature, strbuf.base, sizeof(llarp_sig_t));
memcpy(rc->signature, strbuf.base, SIGSIZE);
return true;
}
@ -97,8 +107,9 @@ llarp_rc_copy(struct llarp_rc *dst, const struct llarp_rc *src)
{
llarp_rc_free(dst);
llarp_rc_clear(dst);
memcpy(dst->pubkey, src->pubkey, sizeof(llarp_pubkey_t));
memcpy(dst->signature, src->signature, sizeof(llarp_sig_t));
memcpy(dst->pubkey, src->pubkey, PUBKEYSIZE);
memcpy(dst->enckey, src->enckey, PUBKEYSIZE);
memcpy(dst->signature, src->signature, SIGSIZE);
dst->last_updated = src->last_updated;
if(src->addrs)
@ -127,15 +138,15 @@ llarp_rc_verify_sig(struct llarp_crypto *crypto, struct llarp_rc *rc)
// would that make it more thread safe?
// jeff agrees
bool result = false;
llarp_sig_t sig;
llarp::Signature sig;
byte_t tmp[MAX_RC_SIZE];
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
// copy sig
memcpy(sig, rc->signature, sizeof(llarp_sig_t));
memcpy(sig, rc->signature, SIGSIZE);
// zero sig
size_t sz = 0;
while(sz < sizeof(llarp_sig_t))
while(sz < SIGSIZE)
rc->signature[sz++] = 0;
// bencode
@ -148,7 +159,7 @@ llarp_rc_verify_sig(struct llarp_crypto *crypto, struct llarp_rc *rc)
else
llarp::Warn(__FILE__, "RC encode failed");
// restore sig
memcpy(rc->signature, sig, sizeof(llarp_sig_t));
memcpy(rc->signature, sig, SIGSIZE);
return result;
}
@ -167,10 +178,17 @@ llarp_rc_bencode(struct llarp_rc *rc, llarp_buffer_t *buff)
if(!llarp_ai_list_bencode(rc->addrs, buff))
return false;
}
/* write pubkey */
/* write signing pubkey */
if(!bencode_write_bytestring(buff, "k", 1))
return false;
if(!bencode_write_bytestring(buff, rc->pubkey, sizeof(llarp_pubkey_t)))
if(!bencode_write_bytestring(buff, rc->pubkey, PUBKEYSIZE))
return false;
/* write encryption pubkey */
if(!bencode_write_bytestring(buff, "p", 1))
return false;
if(!bencode_write_bytestring(buff, rc->enckey, PUBKEYSIZE))
return false;
/* write last updated */
@ -195,7 +213,7 @@ llarp_rc_bencode(struct llarp_rc *rc, llarp_buffer_t *buff)
/* write signature */
if(!bencode_write_bytestring(buff, "z", 1))
return false;
if(!bencode_write_bytestring(buff, rc->signature, sizeof(llarp_sig_t)))
if(!bencode_write_bytestring(buff, rc->signature, SIGSIZE))
return false;
return bencode_end(buff);
}

Loading…
Cancel
Save