mirror of https://github.com/oxen-io/lokinet
more onion routing stuff
parent
a947806b57
commit
ec53cab169
@ -1,2 +1,3 @@
|
||||
{
|
||||
"editor.formatOnSave": true
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
#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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -1,12 +1,69 @@
|
||||
#ifndef LLARP_ENCRYPTED_FRAME_HPP
|
||||
#define LLARP_ENCRYPTED_FRAME_HPP
|
||||
|
||||
#include <llarp/crypto.h>
|
||||
#include <llarp/mem.h>
|
||||
#include <vector>
|
||||
#include <llarp/threadpool.h>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
typedef std::vector< byte_t > EncryptedFrame;
|
||||
struct EncryptedFrame
|
||||
{
|
||||
EncryptedFrame();
|
||||
EncryptedFrame(const byte_t* buf, size_t sz);
|
||||
~EncryptedFrame();
|
||||
|
||||
bool
|
||||
DecryptInPlace(const byte_t* ourSecretKey, llarp_crypto* crypto);
|
||||
|
||||
llarp_buffer_t*
|
||||
Buffer()
|
||||
{
|
||||
return &m_Buffer;
|
||||
}
|
||||
|
||||
private:
|
||||
byte_t* m_Buf;
|
||||
size_t m_Sz;
|
||||
llarp_buffer_t m_Buffer;
|
||||
};
|
||||
|
||||
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, const byte_t* secretkey,
|
||||
DecryptHandler h)
|
||||
: result(h), crypto(c), seckey(secretkey)
|
||||
{
|
||||
}
|
||||
|
||||
DecryptHandler result;
|
||||
User* context;
|
||||
llarp_crypto* crypto;
|
||||
const 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
|
||||
|
@ -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,233 @@
|
||||
#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
|
||||
{
|
||||
PathSymKey_t rxKey;
|
||||
PathSymKey_t 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
|
||||
PathSymKey_t shared;
|
||||
/// nonce for key exchange
|
||||
PathNonce_t 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);
|
||||
|
||||
typedef std::unordered_map< TransitHopInfo, TransitHop,
|
||||
TransitHopInfo::Hash >
|
||||
TransitHopsMap_t;
|
||||
|
||||
private:
|
||||
llarp_router* m_Router;
|
||||
std::mutex m_TransitPathsMutex;
|
||||
TransitHopsMap_t m_TransitPaths;
|
||||
bool m_AllowTransit;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,17 @@
|
||||
#ifndef LLARP_PATH_TYPES_HPP
|
||||
#define LLARP_PATH_TYPES_HPP
|
||||
|
||||
#include <llarp/aligned.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
typedef AlignedBuffer< 16 > PathID_t;
|
||||
|
||||
typedef AlignedBuffer< 32 > PathSymKey_t;
|
||||
|
||||
typedef AlignedBuffer< 32 > PathNonce_t;
|
||||
|
||||
typedef AlignedBuffer< 24 > SymmNonce_t;
|
||||
}
|
||||
|
||||
#endif
|
@ -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
|
@ -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
|
@ -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>
|
@ -0,0 +1,31 @@
|
||||
#include <llarp/encrypted_frame.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
EncryptedFrame::EncryptedFrame() : m_Buf(nullptr), m_Sz(0)
|
||||
{
|
||||
}
|
||||
|
||||
EncryptedFrame::EncryptedFrame(const byte_t* buf, size_t sz)
|
||||
{
|
||||
m_Sz = sz;
|
||||
m_Buf = new byte_t[m_Sz];
|
||||
memcpy(m_Buf, buf, sz);
|
||||
m_Buffer.base = m_Buf;
|
||||
m_Buffer.cur = m_Buf;
|
||||
m_Buffer.sz = sz;
|
||||
}
|
||||
|
||||
EncryptedFrame::~EncryptedFrame()
|
||||
{
|
||||
if(m_Buf)
|
||||
delete[] m_Buf;
|
||||
}
|
||||
|
||||
bool
|
||||
EncryptedFrame::DecryptInPlace(const byte_t* ourSecretKey,
|
||||
llarp_crypto* crypto)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,121 @@
|
||||
#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::vector< EncryptedFrame > leftovers;
|
||||
EncryptedFrame ourFrame;
|
||||
PathContext* context;
|
||||
RouterID from;
|
||||
LR_CommitRecord record;
|
||||
|
||||
LRCMFrameDecrypt(PathContext* ctx, Decrypter* dec,
|
||||
const LR_CommitMessage* commit)
|
||||
: decrypter(dec), context(ctx), from(commit->remote)
|
||||
{
|
||||
auto sz = commit->frames.size();
|
||||
size_t idx = 0;
|
||||
while(idx < sz)
|
||||
{
|
||||
if(sz == 0)
|
||||
ourFrame = commit->frames[idx];
|
||||
else
|
||||
leftovers.push_back(commit->frames[idx]);
|
||||
++idx;
|
||||
}
|
||||
}
|
||||
|
||||
~LRCMFrameDecrypt()
|
||||
{
|
||||
delete decrypter;
|
||||
}
|
||||
|
||||
static void
|
||||
HandleDecrypted(llarp_buffer_t* buf, LRCMFrameDecrypt* self)
|
||||
{
|
||||
if(buf)
|
||||
{
|
||||
llarp::Debug("decrypted LRCM from ", self->from);
|
||||
// successful decrypt
|
||||
if(self->record.BDecode(buf))
|
||||
{
|
||||
TransitHopInfo info(self->from, self->record);
|
||||
if(self->context->HasTransitHop(info))
|
||||
{
|
||||
// duplicate hop
|
||||
llarp::Warn("duplicate transit hop ", info);
|
||||
}
|
||||
else
|
||||
{
|
||||
// accepted
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
llarp::Error("malformed LR Commit Record from ", self->from);
|
||||
}
|
||||
else
|
||||
llarp::Debug("malformed frame inside LRCM from ", self->from);
|
||||
delete self;
|
||||
}
|
||||
};
|
||||
|
||||
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->ourFrame, frames);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
PathContext::HasTransitHop(const TransitHopInfo& info)
|
||||
{
|
||||
std::unique_lock< std::mutex > lock(m_TransitPathsMutex);
|
||||
return m_TransitPaths.find(info) != m_TransitPaths.end();
|
||||
}
|
||||
|
||||
TransitHopInfo::TransitHopInfo(const RouterID& down,
|
||||
const LR_CommitRecord& record)
|
||||
: txID(record.txid), upstream(record.nextHop), downstream(down)
|
||||
{
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue