mirror of
https://github.com/oxen-io/lokinet.git
synced 2024-11-19 09:25:28 +00:00
555 lines
15 KiB
C++
555 lines
15 KiB
C++
#include <llarp/crypto_async.h>
|
|
#include <llarp/mem.h>
|
|
#include <llarp/router_contact.hpp>
|
|
#include <string.h>
|
|
#include <llarp/crypto.hpp>
|
|
#include <llarp/router_id.hpp>
|
|
#include "buffer.hpp"
|
|
#include "logger.hpp"
|
|
#include "mem.hpp"
|
|
|
|
struct llarp_async_iwp
|
|
{
|
|
struct llarp_crypto *crypto;
|
|
struct llarp_logic *logic;
|
|
struct llarp_threadpool *worker;
|
|
};
|
|
|
|
namespace iwp
|
|
{
|
|
void
|
|
inform_intro(void *user)
|
|
{
|
|
iwp_async_intro *intro = static_cast< iwp_async_intro * >(user);
|
|
intro->hook(intro);
|
|
}
|
|
|
|
void
|
|
gen_intro(void *user)
|
|
{
|
|
iwp_async_intro *intro = static_cast< iwp_async_intro * >(user);
|
|
|
|
char ftmp[68] = {0};
|
|
const char *hexname = llarp::HexEncode< llarp::PubKey, decltype(ftmp) >(
|
|
intro->remote_pubkey, ftmp);
|
|
llarp::LogDebug("gen_intro remote_pubkey: ", hexname);
|
|
|
|
llarp::SharedSecret sharedkey;
|
|
llarp_crypto *crypto = intro->iwp->crypto;
|
|
|
|
// S = TKE(a.k, b.k, n)
|
|
crypto->transport_dh_client(sharedkey, intro->remote_pubkey,
|
|
intro->secretkey, intro->nonce);
|
|
char ftmpShared[68] = {0};
|
|
const char *hexShared =
|
|
llarp::HexEncode< llarp::SharedSecret, decltype(ftmpShared) >(
|
|
sharedkey, ftmpShared);
|
|
llarp::LogDebug("gen_intro sharedkey ", hexShared);
|
|
|
|
byte_t tmp[64];
|
|
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
|
|
|
|
llarp::SymmNonce n;
|
|
// copy nonce
|
|
memcpy(n, intro->nonce, 32); // was 24 bytes
|
|
char ftmpN[68] = {0};
|
|
const char *hexN =
|
|
llarp::HexEncode< llarp::SymmNonce, decltype(ftmpN) >(n, ftmpN);
|
|
llarp::LogDebug("gen_intro nonce ", hexN);
|
|
|
|
// e_k = HS(b.k + n)
|
|
|
|
llarp::ShortHash e_k;
|
|
memcpy(tmp, intro->remote_pubkey, 32);
|
|
memcpy(tmp + 32, intro->nonce, 32);
|
|
crypto->shorthash(e_k, buf);
|
|
|
|
char ftmpEk[68] = {0};
|
|
const char *hexEk =
|
|
llarp::HexEncode< llarp::ShortHash, decltype(ftmpEk) >(e_k, ftmpEk);
|
|
llarp::LogDebug("gen_intro e_k ", hexEk, " used ", strlen(hexEk));
|
|
|
|
// put nonce
|
|
memcpy(intro->buf + 32, intro->nonce, 32);
|
|
|
|
// e = SE(a.k, e_k, n[0:24])
|
|
memcpy(intro->buf + 64, llarp::seckey_topublic(intro->secretkey), 32);
|
|
|
|
char ftmpSk[68] = {0};
|
|
const char *hexSk = llarp::HexEncode< llarp::PubKey, decltype(ftmpSk) >(
|
|
intro->secretkey, ftmpSk);
|
|
llarp::LogDebug("gen_intro SK ", hexSk);
|
|
|
|
char ftmpSkPub[68] = {0};
|
|
const char *hexSkPub =
|
|
llarp::HexEncode< llarp::PubKey, decltype(ftmpSkPub) >(
|
|
llarp::seckey_topublic(intro->secretkey), ftmpSkPub);
|
|
llarp::LogDebug("gen_intro SK pub ", hexSkPub);
|
|
|
|
buf.base = intro->buf + 64;
|
|
buf.cur = buf.base;
|
|
buf.sz = 32;
|
|
crypto->xchacha20(buf, e_k, intro->nonce);
|
|
|
|
// h = MDS( n + e + w0, S)
|
|
buf.base = intro->buf + 32;
|
|
buf.cur = buf.base;
|
|
buf.sz = intro->sz - 32;
|
|
crypto->hmac(intro->buf, buf, sharedkey);
|
|
|
|
char ftmpHmac[68] = {0}; // probably could be 65
|
|
const char *hexHmac = llarp::HexEncode< llarp::PubKey, decltype(ftmpHmac) >(
|
|
intro->buf, ftmpHmac);
|
|
llarp::LogDebug("gen_intro Hmac ", hexHmac);
|
|
|
|
// inform result
|
|
// intro->hook(intro);
|
|
llarp_logic_queue_job(intro->iwp->logic, {intro, &inform_intro});
|
|
}
|
|
|
|
void
|
|
verify_intro(void *user)
|
|
{
|
|
iwp_async_intro *intro = static_cast< iwp_async_intro * >(user);
|
|
auto crypto = intro->iwp->crypto;
|
|
llarp::SharedSecret sharedkey;
|
|
llarp::ShortHash e_K;
|
|
llarp::SharedSecret h;
|
|
byte_t tmp[64];
|
|
const auto OurPK = llarp::seckey_topublic(intro->secretkey);
|
|
|
|
char ftmp[68] = {0};
|
|
const char *hexPk =
|
|
llarp::HexEncode< llarp::PubKey, decltype(ftmp) >(OurPK, ftmp);
|
|
llarp::LogDebug("intro OurPK ", hexPk);
|
|
|
|
// e_k = HS(b.k + n)
|
|
memcpy(tmp, OurPK, 32);
|
|
memcpy(tmp + 32, intro->nonce, 32);
|
|
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
|
|
crypto->shorthash(e_K, buf);
|
|
|
|
buf.base = intro->remote_pubkey;
|
|
buf.cur = buf.base;
|
|
buf.sz = 32;
|
|
|
|
// was using remote_pubkey directly (use buffer wrapper? directly?)
|
|
// memcpy(intro->remote_pubkey, intro->buf + 64, 32);
|
|
memcpy(buf.base, intro->buf + 64, 32);
|
|
|
|
crypto->xchacha20(buf, e_K, intro->nonce);
|
|
llarp::LogInfo("handshake from ", llarp::RouterID(intro->remote_pubkey));
|
|
|
|
char ftmp2[68] = {0};
|
|
const char *hexRemotePK = llarp::HexEncode< llarp::PubKey, decltype(ftmp) >(
|
|
intro->remote_pubkey, ftmp2);
|
|
llarp::LogDebug("intro remote_pubkey ", hexRemotePK);
|
|
|
|
// S = TKE(a.k, b.k, n)
|
|
crypto->transport_dh_server(sharedkey, intro->remote_pubkey,
|
|
intro->secretkey, intro->nonce);
|
|
|
|
char ftmpShared[68] = {0};
|
|
const char *hexShared =
|
|
llarp::HexEncode< llarp::PubKey, decltype(ftmpShared) >(sharedkey,
|
|
ftmpShared);
|
|
llarp::LogDebug("intro sharedkey ", hexShared);
|
|
|
|
// h = MDS( n + e + w2, S)
|
|
buf.base = intro->buf + 32;
|
|
buf.cur = buf.base;
|
|
buf.sz = intro->sz - 32;
|
|
crypto->hmac(h, buf, sharedkey);
|
|
if(memcmp(h, intro->buf, 32))
|
|
{
|
|
llarp::LogWarn("intro HMAC failure");
|
|
// hmac fail
|
|
delete[] intro->buf;
|
|
intro->buf = nullptr;
|
|
}
|
|
// inform result
|
|
llarp_logic_queue_job(intro->iwp->logic, {intro, &inform_intro});
|
|
}
|
|
|
|
void
|
|
inform_introack(void *user)
|
|
{
|
|
iwp_async_introack *introack = static_cast< iwp_async_introack * >(user);
|
|
introack->hook(introack);
|
|
}
|
|
|
|
void
|
|
verify_introack(void *user)
|
|
{
|
|
iwp_async_introack *introack = static_cast< iwp_async_introack * >(user);
|
|
auto crypto = introack->iwp->crypto;
|
|
auto logic = introack->iwp->logic;
|
|
|
|
llarp::ShortHash digest;
|
|
llarp::SharedSecret sharedkey;
|
|
|
|
auto hmac = introack->buf;
|
|
auto body = introack->buf + 32;
|
|
const auto pubkey = introack->remote_pubkey;
|
|
auto secretkey = introack->secretkey;
|
|
auto nonce = introack->buf + 32;
|
|
auto token = introack->buf + 64;
|
|
size_t bodysz = introack->sz - 32;
|
|
llarp_buffer_t buf;
|
|
buf.base = body;
|
|
buf.cur = body;
|
|
buf.sz = bodysz;
|
|
|
|
// S = TKE(a.k, b.k, n)
|
|
crypto->transport_dh_client(sharedkey, pubkey, secretkey, nonce);
|
|
|
|
// h = MDS(n + x + w1, S)
|
|
crypto->hmac(digest, buf, sharedkey);
|
|
|
|
if(!llarp_eq(digest, hmac, 32))
|
|
{
|
|
// fail to verify hmac
|
|
introack->buf = nullptr;
|
|
}
|
|
else
|
|
{
|
|
buf.base = token;
|
|
buf.sz = 32;
|
|
// token = SD(S, x, n[0:24])
|
|
crypto->xchacha20(buf, sharedkey, nonce);
|
|
// copy token
|
|
memcpy(introack->token, token, 32);
|
|
}
|
|
// introack->hook(introack);
|
|
llarp_logic_queue_job(logic, {introack, &inform_introack});
|
|
}
|
|
|
|
void
|
|
gen_introack(void *user)
|
|
{
|
|
iwp_async_introack *introack = static_cast< iwp_async_introack * >(user);
|
|
llarp::SharedSecret sharedkey;
|
|
auto crypto = introack->iwp->crypto;
|
|
const auto pubkey = introack->remote_pubkey;
|
|
auto secretkey = introack->secretkey;
|
|
auto nonce = introack->nonce;
|
|
// S = TKE(a.k, b.k, n)
|
|
crypto->transport_dh_server(sharedkey, pubkey, secretkey, nonce);
|
|
|
|
// x = SE(S, token, n[0:24])
|
|
llarp_buffer_t buf;
|
|
buf.base = introack->buf + 64;
|
|
buf.sz = 32;
|
|
buf.cur = buf.base;
|
|
memcpy(buf.base, introack->token, 32);
|
|
crypto->xchacha20(buf, sharedkey, nonce);
|
|
|
|
// h = MDS(n + x + w1, S)
|
|
buf.base = introack->buf + 32;
|
|
buf.sz = introack->sz - 32;
|
|
buf.cur = buf.base;
|
|
crypto->hmac(introack->buf, buf, sharedkey);
|
|
// introack->hook(introack);
|
|
llarp_logic_queue_job(introack->iwp->logic, {introack, &inform_introack});
|
|
}
|
|
|
|
void
|
|
inform_session_start(void *user)
|
|
{
|
|
iwp_async_session_start *session =
|
|
static_cast< iwp_async_session_start * >(user);
|
|
session->hook(session);
|
|
}
|
|
|
|
void
|
|
gen_session_start(void *user)
|
|
{
|
|
iwp_async_session_start *session =
|
|
static_cast< iwp_async_session_start * >(user);
|
|
auto crypto = session->iwp->crypto;
|
|
auto logic = session->iwp->logic;
|
|
|
|
auto dh = crypto->transport_dh_client;
|
|
auto shorthash = crypto->shorthash;
|
|
auto hmac = crypto->hmac;
|
|
auto encrypt = crypto->xchacha20;
|
|
|
|
// auto logic = session->iwp->logic;
|
|
auto a_sK = session->secretkey;
|
|
const auto b_K = session->remote_pubkey;
|
|
auto N = session->nonce;
|
|
auto token = session->token;
|
|
auto K = session->sessionkey;
|
|
|
|
llarp::SharedSecret e_K;
|
|
llarp::ShortHash T;
|
|
|
|
byte_t tmp[64];
|
|
llarp_buffer_t buf = llarp::StackBuffer< decltype(tmp) >(tmp);
|
|
|
|
// T = HS(token + n)
|
|
memcpy(tmp, token, 32);
|
|
memcpy(tmp + 32, N, 32);
|
|
shorthash(T, buf);
|
|
|
|
// e_K = TKE(a.k, b.k, n)
|
|
dh(e_K, b_K, a_sK, N);
|
|
// K = TKE(a.k, b.k, T)
|
|
dh(K, b_K, a_sK, T);
|
|
|
|
// x = SE(e_K, token, n[0:24])
|
|
buf.base = (session->buf + 64);
|
|
buf.sz = 32;
|
|
memcpy(buf.base, token, 32);
|
|
encrypt(buf, e_K, N);
|
|
|
|
// h = MDS(n + x + w2, e_K)
|
|
buf.base = (session->buf + 32);
|
|
buf.sz = session->sz - 32;
|
|
hmac(session->buf, buf, e_K);
|
|
// session->hook(session);
|
|
llarp_logic_queue_job(logic, {session, &inform_session_start});
|
|
}
|
|
|
|
void
|
|
verify_session_start(void *user)
|
|
{
|
|
iwp_async_session_start *session =
|
|
static_cast< iwp_async_session_start * >(user);
|
|
// possible repeat job
|
|
if(session->buf == nullptr)
|
|
return;
|
|
|
|
auto crypto = session->iwp->crypto;
|
|
auto logic = session->iwp->logic;
|
|
|
|
auto dh = crypto->transport_dh_server;
|
|
auto shorthash = crypto->shorthash;
|
|
auto hmac = crypto->hmac;
|
|
auto decrypt = crypto->xchacha20;
|
|
|
|
auto b_sK = session->secretkey;
|
|
auto a_K = session->remote_pubkey;
|
|
auto N = session->nonce;
|
|
auto token = session->token;
|
|
auto K = session->sessionkey;
|
|
|
|
llarp::SharedSecret e_K;
|
|
llarp::ShortHash T;
|
|
|
|
byte_t tmp[64];
|
|
|
|
llarp_buffer_t buf;
|
|
|
|
// e_K = TKE(a.k, b.k, N)
|
|
dh(e_K, a_K, b_sK, N);
|
|
// h = MDS( n + x + w2, e_K)
|
|
buf.base = session->buf + 32;
|
|
buf.cur = buf.base;
|
|
buf.sz = session->sz - 32;
|
|
hmac(tmp, buf, e_K);
|
|
if(memcmp(tmp, session->buf, 32) == 0)
|
|
{
|
|
// hmac good
|
|
buf.base = session->buf + 64;
|
|
buf.cur = buf.base;
|
|
buf.sz = 32;
|
|
// token = SD(e_K, x, n[0:24])
|
|
decrypt(buf, e_K, N);
|
|
// ensure it's the same token
|
|
if(memcmp(buf.base, token, 32) == 0)
|
|
{
|
|
// T = HS(token + n)
|
|
memcpy(tmp, token, 32);
|
|
memcpy(tmp + 32, N, 32);
|
|
buf.base = tmp;
|
|
buf.cur = buf.base;
|
|
buf.sz = sizeof(tmp);
|
|
shorthash(T, buf);
|
|
// K = TKE(a.k, b.k, T)
|
|
dh(K, a_K, b_sK, T);
|
|
}
|
|
else // token missmatch
|
|
{
|
|
session->buf = nullptr;
|
|
}
|
|
}
|
|
else // hmac fail
|
|
session->buf = nullptr;
|
|
// session->hook(session);
|
|
llarp_logic_queue_job(logic, {session, &inform_session_start});
|
|
}
|
|
|
|
void
|
|
inform_frame_done(void *user)
|
|
{
|
|
iwp_async_frame *frame = static_cast< iwp_async_frame * >(user);
|
|
frame->hook(frame);
|
|
delete frame;
|
|
}
|
|
|
|
void
|
|
hmac_then_decrypt(void *user)
|
|
{
|
|
iwp_async_frame *frame = static_cast< iwp_async_frame * >(user);
|
|
iwp_decrypt_frame(frame);
|
|
// inform result
|
|
llarp_logic_queue_job(frame->iwp->logic, {frame, &inform_frame_done});
|
|
}
|
|
|
|
void
|
|
encrypt_then_hmac(void *user)
|
|
{
|
|
iwp_async_frame *frame = static_cast< iwp_async_frame * >(user);
|
|
iwp_encrypt_frame(frame);
|
|
// call result RIGHT HERE
|
|
frame->hook(frame);
|
|
delete frame;
|
|
}
|
|
} // namespace iwp
|
|
|
|
bool
|
|
iwp_decrypt_frame(struct iwp_async_frame *frame)
|
|
{
|
|
auto crypto = frame->iwp->crypto;
|
|
byte_t *hmac = frame->buf;
|
|
byte_t *nonce = frame->buf + 32;
|
|
byte_t *body = frame->buf + 64;
|
|
|
|
llarp::ShortHash digest;
|
|
|
|
llarp_buffer_t buf;
|
|
buf.base = nonce;
|
|
buf.cur = buf.base;
|
|
buf.sz = frame->sz - 32;
|
|
|
|
// h = MDS(n + x, S)
|
|
crypto->hmac(digest, buf, frame->sessionkey);
|
|
// check hmac
|
|
frame->success = memcmp(digest, hmac, 32) == 0;
|
|
if(!frame->success)
|
|
{
|
|
// [", digest, "] vs [", hmac, "]
|
|
llarp::LogWarn("crypto_async::iwp_decrypt_frame failed to decrypt");
|
|
//} else {
|
|
// llarp::Debug("crypto_async::iwp_decrypt_frame decrypted");
|
|
}
|
|
// x = SE(S, p, n[0:24])
|
|
buf.base = body;
|
|
buf.cur = buf.base;
|
|
buf.sz = frame->sz - 64;
|
|
crypto->xchacha20(buf, frame->sessionkey, nonce);
|
|
|
|
return frame->success;
|
|
}
|
|
|
|
bool
|
|
iwp_encrypt_frame(struct iwp_async_frame *frame)
|
|
{
|
|
auto crypto = frame->iwp->crypto;
|
|
byte_t *hmac = frame->buf;
|
|
byte_t *nonce = frame->buf + 32;
|
|
byte_t *body = frame->buf + 64;
|
|
|
|
llarp_buffer_t buf;
|
|
buf.base = body;
|
|
buf.cur = buf.base;
|
|
buf.sz = frame->sz - 64;
|
|
|
|
// randomize N
|
|
crypto->randbytes(nonce, 32);
|
|
// x = SE(S, p, n[0:24])
|
|
crypto->xchacha20(buf, frame->sessionkey, nonce);
|
|
// h = MDS(n + x, S)
|
|
buf.base = nonce;
|
|
buf.cur = buf.base;
|
|
buf.sz = frame->sz - 32;
|
|
crypto->hmac(hmac, buf, frame->sessionkey);
|
|
return true;
|
|
}
|
|
|
|
void
|
|
iwp_call_async_gen_intro(struct llarp_async_iwp *iwp,
|
|
struct iwp_async_intro *intro)
|
|
{
|
|
intro->iwp = iwp;
|
|
llarp_threadpool_queue_job(iwp->worker, {intro, &iwp::gen_intro});
|
|
}
|
|
|
|
void
|
|
iwp_call_async_verify_introack(struct llarp_async_iwp *iwp,
|
|
struct iwp_async_introack *introack)
|
|
{
|
|
introack->iwp = iwp;
|
|
llarp_threadpool_queue_job(iwp->worker, {introack, &iwp::verify_introack});
|
|
}
|
|
|
|
void
|
|
iwp_call_async_gen_session_start(struct llarp_async_iwp *iwp,
|
|
struct iwp_async_session_start *session)
|
|
{
|
|
session->iwp = iwp;
|
|
llarp_threadpool_queue_job(iwp->worker, {session, &iwp::gen_session_start});
|
|
}
|
|
|
|
void
|
|
iwp_call_async_verify_intro(struct llarp_async_iwp *iwp,
|
|
struct iwp_async_intro *intro)
|
|
{
|
|
intro->iwp = iwp;
|
|
llarp_threadpool_queue_job(iwp->worker, {intro, &iwp::verify_intro});
|
|
}
|
|
|
|
void
|
|
iwp_call_async_gen_introack(struct llarp_async_iwp *iwp,
|
|
struct iwp_async_introack *introack)
|
|
{
|
|
introack->iwp = iwp;
|
|
llarp_threadpool_queue_job(iwp->worker, {introack, &iwp::gen_introack});
|
|
}
|
|
|
|
void
|
|
iwp_call_async_frame_decrypt(struct llarp_async_iwp *iwp,
|
|
struct iwp_async_frame *frame)
|
|
{
|
|
frame->iwp = iwp;
|
|
llarp_threadpool_queue_job(iwp->worker, {frame, &iwp::hmac_then_decrypt});
|
|
}
|
|
|
|
void
|
|
iwp_call_async_frame_encrypt(struct llarp_async_iwp *iwp,
|
|
struct iwp_async_frame *frame)
|
|
{
|
|
frame->iwp = iwp;
|
|
llarp_threadpool_queue_job(iwp->worker, {frame, &iwp::encrypt_then_hmac});
|
|
}
|
|
|
|
void
|
|
iwp_call_async_verify_session_start(struct llarp_async_iwp *iwp,
|
|
struct iwp_async_session_start *session)
|
|
{
|
|
session->iwp = iwp;
|
|
llarp_threadpool_queue_job(iwp->worker,
|
|
{session, &iwp::verify_session_start});
|
|
}
|
|
|
|
struct llarp_async_iwp *
|
|
llarp_async_iwp_new(struct llarp_crypto *crypto, struct llarp_logic *logic,
|
|
struct llarp_threadpool *worker)
|
|
{
|
|
llarp_async_iwp *iwp = new llarp_async_iwp;
|
|
if(iwp)
|
|
{
|
|
iwp->crypto = crypto;
|
|
iwp->logic = logic;
|
|
iwp->worker = worker;
|
|
}
|
|
return iwp;
|
|
}
|
|
|
|
void
|
|
llarp_async_iwp_free(struct llarp_async_iwp *iwp)
|
|
{
|
|
delete iwp;
|
|
}
|