mirror of https://github.com/oxen-io/lokinet
use NTRU for introset end to end encryption
This commit is contained in:
parent
98c275ab87
commit
186bd7d573
|
@ -294,12 +294,8 @@ set(NTRU_SRC
|
|||
crypto/libntrup/src/ntru.c
|
||||
)
|
||||
|
||||
set(NTRU_LIB sntrup)
|
||||
add_library(${NTRU_LIB} ${NTRU_SRC})
|
||||
target_link_libraries(${NTRU_LIB} ${SODIUM_LIB})
|
||||
|
||||
|
||||
set(LIB_SRC
|
||||
set(LIB_SRC
|
||||
${NTRU_SRC}
|
||||
llarp/address_info.cpp
|
||||
llarp/bencode.cpp
|
||||
llarp/buffer.cpp
|
||||
|
@ -377,6 +373,7 @@ set(TEST_SRC
|
|||
test/dht_unittest.cpp
|
||||
test/encrypted_frame_unittest.cpp
|
||||
test/hiddenservice_unittest.cpp
|
||||
test/pq_unittest.cpp
|
||||
)
|
||||
|
||||
|
||||
|
@ -423,14 +420,10 @@ else()
|
|||
|
||||
|
||||
|
||||
if(WITH_TESTS)
|
||||
enable_testing()
|
||||
add_subdirectory(${GTEST_DIR})
|
||||
include_directories(${GTEST_DIR}/include ${GTEST_DIR})
|
||||
add_executable(${TEST_EXE} ${TEST_SRC})
|
||||
add_test(runAllTests ${TEST_EXE})
|
||||
target_link_libraries(${TEST_EXE} ${STATIC_LINK_LIBS} gtest_main ${STATIC_LIB})
|
||||
endif()
|
||||
add_subdirectory(${GTEST_DIR})
|
||||
include_directories(${GTEST_DIR}/include ${GTEST_DIR})
|
||||
add_executable(${TEST_EXE} ${TEST_SRC})
|
||||
target_link_libraries(${TEST_EXE} ${STATIC_LINK_LIBS} gtest_main ${STATIC_LIB})
|
||||
|
||||
if(WITH_STATIC)
|
||||
add_library(${STATIC_LIB} STATIC ${LIB_SRC})
|
||||
|
|
12
Makefile
12
Makefile
|
@ -1,5 +1,5 @@
|
|||
|
||||
all: debug
|
||||
all: test
|
||||
|
||||
SIGN = gpg --sign --detach
|
||||
|
||||
|
@ -27,6 +27,7 @@ TESTNET_CONF=$(TESTNET_ROOT)/supervisor.conf
|
|||
TESTNET_LOG=$(TESTNET_ROOT)/testnet.log
|
||||
|
||||
EXE = $(REPO)/lokinet
|
||||
TEST_EXE = $(REPO)/testAll
|
||||
|
||||
TESTNET_EXE=$(REPO)/lokinet-testnet
|
||||
TESTNET_CLIENTS ?= 50
|
||||
|
@ -42,18 +43,16 @@ clean:
|
|||
rm -f *.a *.so
|
||||
|
||||
debug-configure:
|
||||
cmake -GNinja -DCMAKE_BUILD_TYPE=Debug -DWITH_TESTS=ON -DCMAKE_C_COMPILER=$(CC) -DCMAKE_CXX_COMPILER=$(CXX) -DTUNTAP=ON
|
||||
cmake -GNinja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=$(CC) -DCMAKE_CXX_COMPILER=$(CXX) -DTUNTAP=ON
|
||||
|
||||
release-configure: clean
|
||||
cmake -GNinja -DSTATIC_LINK=ON -DCMAKE_BUILD_TYPE=Release -DRELEASE_MOTTO="$(shell cat motto.txt)" -DCMAKE_C_COMPILER=$(CC) -DCMAKE_CXX_COMPILER=$(CXX) -DTUNTAP=ON
|
||||
|
||||
debug: debug-configure
|
||||
ninja
|
||||
ninja test
|
||||
|
||||
release-compile: release-configure
|
||||
ninja
|
||||
cp llarpd lokinet
|
||||
strip $(TARGETS)
|
||||
|
||||
$(TARGETS): release-compile
|
||||
|
@ -101,9 +100,8 @@ testnet:
|
|||
python3 contrib/testnet/genconf.py --bin=$(TESTNET_EXE) --svc=$(TESTNET_SERVERS) --clients=$(TESTNET_CLIENTS) --dir=$(TESTNET_ROOT) --out $(TESTNET_CONF)
|
||||
LLARP_DEBUG=$(TESTNET_DEBUG) supervisord -n -d $(TESTNET_ROOT) -l $(TESTNET_LOG) -c $(TESTNET_CONF)
|
||||
|
||||
test: debug-configure
|
||||
ninja
|
||||
ninja test
|
||||
test: debug
|
||||
$(TEST_EXE)
|
||||
|
||||
format:
|
||||
clang-format -i $$(find daemon llarp include | grep -E '\.[h,c](pp)?$$')
|
||||
|
|
|
@ -18,6 +18,12 @@ int crypto_kem_keypair(unsigned char *pk, unsigned char * sk);
|
|||
#define crypto_kem_SECRETKEYBYTES 1600
|
||||
#define crypto_kem_PUBLICKEYBYTES 1218
|
||||
#define crypto_kem_CIPHERTEXTBYTES 1047
|
||||
|
||||
#define NTRU_SECRETKEYBYTES CRYPTO_SECRETKEYBYTES
|
||||
#define NTRU_PUBLICKEYBYTES CRYPTO_PUBLICKEYBYTES
|
||||
#define NTRU_CIPHERTEXTBYTES CRYPTO_CIPHERTEXTBYTES
|
||||
|
||||
|
||||
#define CRYPTO_BYTES 32
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -1,9 +1,4 @@
|
|||
|
||||
#define NTRU_SECRETKEYBYTES CRYPTO_SECRETKEYBYTES
|
||||
#define NTRU_PUBLICKEYBYTES CRYPTO_PUBLICKEYBYTES
|
||||
#define NTRU_CIPHERTEXTBYTES CRYPTO_CIPHERTEXTBYTES
|
||||
|
||||
|
||||
int crypto_kem_enc_ref(unsigned char *cstr, unsigned char *k, const unsigned char *pk);
|
||||
|
||||
int crypto_kem_dec_ref(unsigned char *k, const unsigned char *cstr, const unsigned char *sk);
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#error "crypto_kem_SECRETKEYBYTES must match rq_encode_len + 2 * small_encode_len"
|
||||
#endif
|
||||
|
||||
int crypto_kem_keypair_ax2(unsigned char *pk,unsigned char *sk)
|
||||
int crypto_kem_keypair_avx2(unsigned char *pk,unsigned char *sk)
|
||||
{
|
||||
small g[768];
|
||||
small grecip[768];
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#ifdef __AVX2__
|
||||
#if __AVX2__
|
||||
#include <string.h>
|
||||
#include <immintrin.h>
|
||||
#include "mod3.h"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#ifdef __AVX2__
|
||||
#if __AVX2__
|
||||
#include <immintrin.h>
|
||||
#include "params.h"
|
||||
#include "mod3.h"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#ifdef __AVX2__
|
||||
#if __AVX2__
|
||||
#include <immintrin.h>
|
||||
#include "params.h"
|
||||
#include "crypto_uint32.h"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#ifdef __AVX2__
|
||||
#if __AVX2__
|
||||
#include <immintrin.h>
|
||||
#include "mod3.h"
|
||||
#include "rq.h"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#ifdef __AVX2__
|
||||
#if __AVX2__
|
||||
#include <immintrin.h>
|
||||
#include "params.h"
|
||||
#include "swap.h"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#ifdef __AVX__
|
||||
#if __AVX2__
|
||||
#include <immintrin.h>
|
||||
#include "params.h"
|
||||
#include "rq.h"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#ifdef __AVX__
|
||||
#if __AVX2__
|
||||
#include <immintrin.h>
|
||||
#include "params.h"
|
||||
#include "crypto_uint32.h"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#ifdef __AVX2__
|
||||
#if __AVX2__
|
||||
#include <immintrin.h>
|
||||
#include "swap.h"
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#ifdef __AVX2__
|
||||
#if __AVX2__
|
||||
#include <immintrin.h>
|
||||
#include "params.h"
|
||||
#include "r3.h"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#include <stdbool.h>
|
||||
|
||||
|
||||
#if defined(__x86_64__) || defined(__i386__)
|
||||
#if __AVX__
|
||||
#include <cpuid.h>
|
||||
|
||||
static bool supports_avx2()
|
||||
|
@ -36,16 +36,19 @@ void ntru_init()
|
|||
{
|
||||
if(supports_avx2())
|
||||
{
|
||||
__crypto_kem_dec = crypto_kem_dec_avx2;
|
||||
__crypto_kem_enc = crypto_kem_enc_avx2;
|
||||
__crypto_kem_dec = crypto_kem_dec_avx2;
|
||||
__crypto_kem_dec = &crypto_kem_dec_avx2;
|
||||
__crypto_kem_enc = &crypto_kem_enc_avx2;
|
||||
__crypto_kem_dec = &crypto_kem_dec_avx2;
|
||||
__crypto_kem_keypair = &crypto_kem_keypair_avx2;
|
||||
}
|
||||
else
|
||||
{
|
||||
__crypto_kem_dec = crypto_kem_dec_ref;
|
||||
__crypto_kem_enc = crypto_kem_enc_ref;
|
||||
__crypto_kem_dec = crypto_kem_dec_ref;
|
||||
__crypto_kem_dec = &crypto_kem_dec_ref;
|
||||
__crypto_kem_enc = &crypto_kem_enc_ref;
|
||||
__crypto_kem_dec = &crypto_kem_dec_ref;
|
||||
__crypto_kem_keypair = &crypto_kem_keypair_ref;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -319,7 +319,7 @@ main(int argc, char *argv[])
|
|||
llarp_findOrCreateIdentity(&crypt, ident_keyfile.string().c_str(),
|
||||
identity);
|
||||
// get identity public key
|
||||
uint8_t *pubkey = llarp::seckey_topublic(identity);
|
||||
const uint8_t *pubkey = llarp::seckey_topublic(identity);
|
||||
llarp_rc_set_pubsigkey(&rc, pubkey);
|
||||
llarp_rc_sign(&crypt, identity, &rc);
|
||||
|
||||
|
|
|
@ -9,19 +9,18 @@ MDS(x, k) is 256 bit blake2b hmac of x with secret value k
|
|||
SE(k, n, x) is chacha20 encrypt data x using symettric key k and nounce n
|
||||
SD(k, n, x) is chacha20 dectypt data x using symettric key k and nounce n
|
||||
S(k, x) is sign x with ed25519 using secret key k
|
||||
EDKG() is generate ec keypair (p, s) public key p (32 bytes), secret key s (643 bytes)
|
||||
EDKG() is generate ec keypair (p, s) public key p (32 bytes), secret key s (64 bytes)
|
||||
V(k, x, sig) is verify x data using signature sig using public key k
|
||||
EDDH(a, b) is curve25519 scalar multiplication of a and b
|
||||
|
||||
HKE(a, b, x) is hashed key exchange between a and b using a secret key x HS(a + b + EDDH(x, b))
|
||||
TKE(a, b, sk, n) is a transport shared secret kdf using MDS(n, HKE(a, b, sk))
|
||||
TKE(a, b, x, n) is a transport shared secret kdf using MDS(n, HKE(a, b, x))
|
||||
|
||||
when A is client and B is server where n is a 32 bytes shared random
|
||||
|
||||
client computes TKE(A.pk, B.pk, A.sk, n)
|
||||
server computes TKE(A.pk, B.pk, B.sk, n)
|
||||
|
||||
PDH(a, b, x) is path shared secret generation HS(a + b + curve41417_scalar_mult(x, b))
|
||||
PDH(a, b, x) is path shared secret generation HS(a + b + EDDH(x, b))
|
||||
|
||||
PKE(a, b, x, n) is a path shared secret kdf using MDS(n, PDH(a, b, x))
|
||||
|
||||
|
@ -34,4 +33,7 @@ S_a is equal to S_b
|
|||
|
||||
RAND(n) is n random bytes
|
||||
|
||||
PQKG() is generate a sntrup4591761 key pair (sk, pk)
|
||||
PQKE_A(pk) is alice generating (x, k) where x is sntrup4591761 ciphertext block and k is the session key
|
||||
PQKE_B(x, sk) is bob calculating k where x is sntrup4591761 ciphertext block, sk is bob's sntrup4591761 secretkey and k is the session key
|
||||
|
||||
|
|
178
doc/proto_v0.txt
178
doc/proto_v0.txt
|
@ -176,8 +176,9 @@ x is the timestamp seconds since epoch that this introduction expires at
|
|||
introduction set (IS)
|
||||
|
||||
a signed set of introductions for a hidden service
|
||||
a is the service info
|
||||
a is the service info of the publisher
|
||||
i is the list of introductions that this service is advertising with
|
||||
k is the public key to use when doing encryption to this hidden service
|
||||
n is a 16 byte null padded utf-8 encoded string tagging the hidden service in
|
||||
a topic searchable via a lookup (optional)
|
||||
v is the protocol version
|
||||
|
@ -188,6 +189,7 @@ service's signing key.
|
|||
{
|
||||
a: SI,
|
||||
i: [ I, I, I, ... ],
|
||||
k: "<1218 bytes sntrup4591761 public key block>",
|
||||
n: "<16 bytes service topic (optional)>",
|
||||
v: 0,
|
||||
w: optional proof of work,
|
||||
|
@ -528,54 +530,6 @@ B is set to a backoff value.
|
|||
R contains additional metadata text describing why the exit was rejected.
|
||||
|
||||
|
||||
hidden service frame (HSF)
|
||||
|
||||
TODO: document this better
|
||||
|
||||
intro message (variant 1)
|
||||
|
||||
start a new session
|
||||
|
||||
{
|
||||
A: "H",
|
||||
D: "<N bytes encrypted HSD>",
|
||||
H: "<32 bytes ephemeral public encryption key>",
|
||||
N: "<32 bytes nonce for key exchange>",
|
||||
S: 0,
|
||||
V: 0,
|
||||
Z: "<64 bytes signature of entire message using sender's signing key>"
|
||||
}
|
||||
|
||||
D is encrypted with session key K which is derived by
|
||||
|
||||
K = PKE(H, SI.enckey, N)
|
||||
|
||||
ordered data message (variant 2)
|
||||
|
||||
{
|
||||
A: "H",
|
||||
D: "<N bytes encrypted HSD>",
|
||||
N: "<32 bytes nonce for symettric cipher>",
|
||||
S: sequence_number_uint64,
|
||||
T: "<16 bytes converstation tag>",
|
||||
V: 0,
|
||||
Z: "<64 bytes signature using sender's signing key>"
|
||||
}
|
||||
|
||||
hidden service data (HSD)
|
||||
|
||||
data sent anonymously over the network to a recipiant from a sender.
|
||||
sent inside a HSFM encrypted with a shared secret.
|
||||
|
||||
{
|
||||
a: protocol_number_uint,
|
||||
d: "<N bytes payload>",
|
||||
i: Introduction for reply,
|
||||
s: SI of sender,
|
||||
t: "<16 bytes converstation tag present only in message 0>",
|
||||
v: 0
|
||||
}
|
||||
|
||||
transfer data fragment message (TDFM)
|
||||
|
||||
transfer data between paths.
|
||||
|
@ -592,6 +546,132 @@ transfer data to another path with id P on the local router place a random 32 by
|
|||
into y and z values into a LRDM message (respectively) and send it in the
|
||||
downstream direction.
|
||||
|
||||
|
||||
|
||||
hidden service data (HSD)
|
||||
|
||||
data sent anonymously over the network to a recipiant from a sender.
|
||||
sent inside a HSFM encrypted with a shared secret.
|
||||
|
||||
{
|
||||
a: protocol_number_uint,
|
||||
d: "<N bytes payload>",
|
||||
i: Introduction for reply,
|
||||
n: uint_message_sequence_number,
|
||||
o: N seconds until this converstation plans terminate,
|
||||
s: SI of sender,
|
||||
t: "<16 bytes converstation tag present only when n is 0>",
|
||||
v: 0
|
||||
}
|
||||
|
||||
|
||||
hidden service frame (HSF)
|
||||
|
||||
TODO: document this better
|
||||
|
||||
intro message (variant 1)
|
||||
|
||||
start a new session
|
||||
|
||||
{
|
||||
A: "H",
|
||||
C: "<1048 bytes ciphertext block>",
|
||||
D: "<N bytes encrypted HSD>",
|
||||
N: "<32 bytes nonce for key exchange>",
|
||||
V: 0,
|
||||
Z: "<64 bytes signature of entire message using sender's signing key>"
|
||||
}
|
||||
|
||||
alice (A) wants to talk to bob (B) over the network, both have hidden services
|
||||
set up and are online on the network.
|
||||
|
||||
A and B are both SI.
|
||||
A_sk is alice's private signing key.
|
||||
|
||||
for alice (A) to send the string "beep" to bob (B), alice picks an introduction
|
||||
to use on one of her paths (I_A) such that I_A is aligning with one of bobs's
|
||||
paths (I_B)
|
||||
|
||||
alice generates:
|
||||
|
||||
T = RAND(16)
|
||||
|
||||
m = {
|
||||
a: 0,
|
||||
d: "beep",
|
||||
i: I_A,
|
||||
n: 0,
|
||||
s: A,
|
||||
t: T,
|
||||
v: 0
|
||||
}
|
||||
|
||||
X = BE(m)
|
||||
|
||||
C, K = PQKE_A(I_B.k)
|
||||
N = RAND(32)
|
||||
D = SE(X, K, N)
|
||||
|
||||
M = {
|
||||
A: "T",
|
||||
P: I_B.P,
|
||||
S: uint64_sequence_number,
|
||||
T: {
|
||||
A: "H",
|
||||
C: C,
|
||||
D: D,
|
||||
N: N,
|
||||
V: 0,
|
||||
Z: "\x00" * 32
|
||||
},
|
||||
V: 0
|
||||
}
|
||||
|
||||
Z = S(A_sk, BE(M))
|
||||
|
||||
alice transmits a TDFM to router with public key I_B.K via her path that ends
|
||||
with router with public key I_B.k
|
||||
|
||||
{
|
||||
A: "T",
|
||||
P: I_B.P,
|
||||
S: uint64_sequence_number,
|
||||
T: {
|
||||
A: "H",
|
||||
C: C,
|
||||
D: D,
|
||||
N: N,
|
||||
V: 0,
|
||||
Z: Z
|
||||
},
|
||||
V: 0
|
||||
}
|
||||
|
||||
the shared secret (S) for further message encryption is:
|
||||
|
||||
S = HS(K + PKE(A, B, sk, N))
|
||||
|
||||
given sk is the local secret encryption key used by the current hidden service
|
||||
|
||||
please note:
|
||||
signature verification can only be done after decryption
|
||||
|
||||
TODO: explain bob's side too (it's invsere of alice's process)
|
||||
|
||||
data from a previously made session (variant 2)
|
||||
|
||||
transfer data on a session previously made
|
||||
|
||||
{
|
||||
A: "H",
|
||||
D: "<N bytes encrypted HSD>",
|
||||
N: "<32 bytes nonce for symettric cipher>",
|
||||
T: "<16 bytes converstation tag>",
|
||||
V: 0,
|
||||
Z: "<64 bytes signature using sender's signing key>"
|
||||
}
|
||||
|
||||
|
||||
transfer ip traffic message (TITM)
|
||||
|
||||
transfer ip traffic for exit
|
||||
|
|
|
@ -11,12 +11,10 @@
|
|||
|
||||
namespace llarp
|
||||
{
|
||||
/// aligned buffer, sz must be multiple of 8 bytes
|
||||
/// aligned buffer, aligns to the nears 8 bytes
|
||||
template < size_t sz, bool randomize = false >
|
||||
struct AlignedBuffer
|
||||
{
|
||||
static_assert(sz % 8 == 0, "aligned buffer size is not a multiple of 8");
|
||||
|
||||
AlignedBuffer()
|
||||
{
|
||||
if(randomize)
|
||||
|
@ -212,7 +210,7 @@ namespace llarp
|
|||
protected:
|
||||
union {
|
||||
byte_t b[sz];
|
||||
uint64_t l[sz / 8];
|
||||
uint64_t l[(sz / 8) + (sz % 8)];
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
#define LLARP_BENCODE_HPP
|
||||
|
||||
#include <llarp/bencode.h>
|
||||
#include <llarp/buffer.hpp>
|
||||
#include <llarp/logger.hpp>
|
||||
|
||||
#include <llarp/mem.hpp>
|
||||
#include <set>
|
||||
|
||||
namespace llarp
|
||||
|
@ -197,6 +198,16 @@ namespace llarp
|
|||
r->buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
template < size_t bufsz, size_t align = 128 >
|
||||
void
|
||||
Dump() const
|
||||
{
|
||||
byte_t tmp[bufsz] = {0};
|
||||
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
|
||||
if(BEncode(&buf))
|
||||
llarp::DumpBuffer< decltype(buf), align >(buf);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace llarp
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
#ifndef LLARP_BUFFER_HPP
|
||||
#define LLARP_BUFFER_HPP
|
||||
|
||||
#include <llarp/buffer.h>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
template < typename T >
|
||||
llarp_buffer_t
|
||||
StackBuffer(T& stack)
|
||||
{
|
||||
llarp_buffer_t buff;
|
||||
buff.base = &stack[0];
|
||||
buff.cur = buff.base;
|
||||
buff.sz = sizeof(stack);
|
||||
return buff;
|
||||
}
|
||||
|
||||
/** initialize llarp_buffer_t from container */
|
||||
template < typename T >
|
||||
llarp_buffer_t
|
||||
Buffer(T& t)
|
||||
{
|
||||
llarp_buffer_t buff;
|
||||
buff.base = &t[0];
|
||||
buff.cur = buff.base;
|
||||
buff.sz = t.size();
|
||||
return buff;
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
llarp_buffer_t
|
||||
ConstBuffer(const T& t)
|
||||
{
|
||||
llarp_buffer_t buff;
|
||||
buff.base = (byte_t*)&t[0];
|
||||
buff.cur = buff.base;
|
||||
buff.sz = t.size();
|
||||
return buff;
|
||||
}
|
||||
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
|
@ -24,26 +24,22 @@
|
|||
#define HMACSIZE 32
|
||||
#define PATHIDSIZE 16
|
||||
|
||||
/*
|
||||
typedef byte_t llarp_pubkey_t[PUBKEYSIZE];
|
||||
typedef byte_t llarp_seckey_t[SECKEYSIZE];
|
||||
typedef byte_t llarp_nonce_t[NONCESIZE];
|
||||
typedef byte_t llarp_sharedkey_t[SHAREDKEYSIZE];
|
||||
typedef byte_t llarp_hash_t[HASHSIZE];
|
||||
typedef byte_t llarp_shorthash_t[SHORTHASHSIZE];
|
||||
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];
|
||||
*/
|
||||
#include <libntrup/ntru.h>
|
||||
|
||||
#define PQ_CIPHERTEXTSIZE crypto_kem_CIPHERTEXTBYTES
|
||||
#define PQ_PUBKEYSIZE crypto_kem_PUBLICKEYBYTES
|
||||
#define PQ_SECRETKEYSIZE crypto_kem_SECRETKEYBYTES
|
||||
#define PQ_KEYPAIRSIZE (PQ_SECRETKEYSIZE + PQ_SECRETKEYSIZE)
|
||||
|
||||
/// label functors
|
||||
|
||||
/// PKE(result, publickey, secretkey, nonce)
|
||||
typedef bool (*llarp_path_dh_func)(byte_t *, byte_t *, byte_t *, byte_t *);
|
||||
typedef bool (*llarp_path_dh_func)(byte_t *, const byte_t *, const byte_t *,
|
||||
const byte_t *);
|
||||
|
||||
/// TKE(result, publickey, secretkey, nonce)
|
||||
typedef bool (*llarp_transport_dh_func)(byte_t *, byte_t *, byte_t *, byte_t *);
|
||||
typedef bool (*llarp_transport_dh_func)(byte_t *, const byte_t *,
|
||||
const byte_t *, const byte_t *);
|
||||
|
||||
/// SD/SE(buffer, key, nonce)
|
||||
typedef bool (*llarp_sym_cipher_func)(llarp_buffer_t, const byte_t *,
|
||||
|
@ -96,6 +92,12 @@ struct llarp_crypto
|
|||
void (*identity_keygen)(byte_t *);
|
||||
/// generate encryption keypair
|
||||
void (*encryption_keygen)(byte_t *);
|
||||
/// generate post quantum encrytion key
|
||||
void (*pqe_keygen)(byte_t *);
|
||||
/// post quantum decrypt (buffer, sharedkey_dst, sec)
|
||||
bool (*pqe_decrypt)(const byte_t *, byte_t *, const byte_t *);
|
||||
/// post quantum encrypt (buffer, sharedkey_dst, pub)
|
||||
bool (*pqe_encrypt)(byte_t *, byte_t *, const byte_t *);
|
||||
};
|
||||
|
||||
/// set crypto function pointers to use libsodium
|
||||
|
|
|
@ -11,36 +11,26 @@ namespace llarp
|
|||
const byte_t*
|
||||
seckey_topublic(const byte_t* secret);
|
||||
|
||||
byte_t*
|
||||
seckey_topublic(byte_t* secret);
|
||||
const byte_t*
|
||||
pq_keypair_to_public(const byte_t* keypair);
|
||||
|
||||
typedef AlignedBuffer< 32 > SharedSecret;
|
||||
const byte_t*
|
||||
pq_keypair_to_secret(const byte_t* keypair);
|
||||
|
||||
typedef AlignedBuffer< SHAREDKEYSIZE > 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< NONCESIZE > SymmNonce;
|
||||
typedef AlignedBuffer< 32 > SymmKey;
|
||||
|
||||
typedef AlignedBuffer< PQ_CIPHERTEXTSIZE + 1 > PQCipherBlock;
|
||||
typedef AlignedBuffer< PQ_PUBKEYSIZE > PQPubKey;
|
||||
typedef AlignedBuffer< PQ_KEYPAIRSIZE > PQKeyPair;
|
||||
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace llarp
|
|||
{
|
||||
}
|
||||
|
||||
EncryptedFrame(byte_t* buf, size_t sz) : Encrypted(buf, sz)
|
||||
EncryptedFrame(const byte_t* buf, size_t sz) : Encrypted(buf, sz)
|
||||
{
|
||||
}
|
||||
EncryptedFrame(size_t sz)
|
||||
|
@ -42,10 +42,11 @@ namespace llarp
|
|||
}
|
||||
|
||||
bool
|
||||
DecryptInPlace(byte_t* seckey, llarp_crypto* crypto);
|
||||
DecryptInPlace(const byte_t* seckey, llarp_crypto* crypto);
|
||||
|
||||
bool
|
||||
EncryptInPlace(byte_t* seckey, byte_t* other, llarp_crypto* crypto);
|
||||
EncryptInPlace(const byte_t* seckey, const byte_t* other,
|
||||
llarp_crypto* crypto);
|
||||
};
|
||||
|
||||
/// TOOD: can only handle 1 frame at a time
|
||||
|
@ -116,7 +117,8 @@ namespace llarp
|
|||
ctx->result(nullptr, ctx->context);
|
||||
}
|
||||
|
||||
AsyncFrameDecrypter(llarp_crypto* c, byte_t* secretkey, DecryptHandler h)
|
||||
AsyncFrameDecrypter(llarp_crypto* c, const byte_t* secretkey,
|
||||
DecryptHandler h)
|
||||
: result(h), crypto(c), seckey(secretkey)
|
||||
{
|
||||
}
|
||||
|
@ -124,7 +126,7 @@ namespace llarp
|
|||
DecryptHandler result;
|
||||
User* context;
|
||||
llarp_crypto* crypto;
|
||||
byte_t* seckey;
|
||||
const byte_t* seckey;
|
||||
EncryptedFrame* target;
|
||||
|
||||
void
|
||||
|
|
|
@ -112,7 +112,7 @@ struct llarp_link
|
|||
void
|
||||
RemoveSession(llarp_link_session *s);
|
||||
|
||||
uint8_t *
|
||||
const uint8_t *
|
||||
pubkey();
|
||||
|
||||
bool
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
#ifndef LLARP_MEM_HPP
|
||||
#define LLARP_MEM_HPP
|
||||
#include <llarp/buffer.h>
|
||||
#include <llarp/mem.h>
|
||||
#include <cctype>
|
||||
#include <cstdio>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
void
|
||||
Zero(void *ptr, size_t sz);
|
||||
|
||||
template < typename T >
|
||||
void
|
||||
dumphex(const uint8_t *t)
|
||||
{
|
||||
size_t idx = 0;
|
||||
while(idx < sizeof(T))
|
||||
{
|
||||
printf("%.2x ", t[idx++]);
|
||||
if(idx % 8 == 0)
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
template < typename T, size_t align = 128 >
|
||||
void
|
||||
DumpBuffer(const T &buff)
|
||||
{
|
||||
size_t idx = 0;
|
||||
printf("buffer of size %zu\n", buff.sz);
|
||||
while(idx < buff.sz)
|
||||
{
|
||||
if(buff.base + idx == buff.cur)
|
||||
{
|
||||
printf("%c[1;31m", 27);
|
||||
}
|
||||
if(std::isprint(buff.base[idx]))
|
||||
{
|
||||
printf("%c", buff.base[idx]);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("X");
|
||||
}
|
||||
if(buff.base + idx == buff.cur)
|
||||
{
|
||||
printf("%c[0;0m", 27);
|
||||
}
|
||||
++idx;
|
||||
if(idx % align == 0)
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
|
@ -15,6 +15,7 @@ namespace llarp
|
|||
{
|
||||
llarp::SecretKey enckey;
|
||||
llarp::SecretKey signkey;
|
||||
llarp::PQKeyPair pq;
|
||||
uint64_t version = 0;
|
||||
VanityNonce vanity;
|
||||
|
||||
|
@ -37,11 +38,18 @@ namespace llarp
|
|||
bool
|
||||
EnsureKeys(const std::string& fpath, llarp_crypto* c);
|
||||
|
||||
bool
|
||||
KeyExchange(llarp_path_dh_func dh, byte_t* sharedkey,
|
||||
const ServiceInfo& other, const byte_t* N) const;
|
||||
|
||||
bool
|
||||
DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf);
|
||||
|
||||
bool
|
||||
SignIntroSet(IntroSet& i, llarp_crypto* c) const;
|
||||
|
||||
bool
|
||||
Sign(llarp_crypto*, byte_t* sig, llarp_buffer_t buf) const;
|
||||
};
|
||||
} // namespace service
|
||||
} // namespace llarp
|
||||
|
|
|
@ -49,8 +49,8 @@ namespace llarp
|
|||
return crypto->verify(signkey, payload, sig);
|
||||
}
|
||||
|
||||
byte_t*
|
||||
EncryptionPublicKey()
|
||||
const byte_t*
|
||||
EncryptionPublicKey() const
|
||||
{
|
||||
return enckey;
|
||||
}
|
||||
|
|
|
@ -15,12 +15,13 @@ namespace llarp
|
|||
{
|
||||
namespace service
|
||||
{
|
||||
constexpr std::size_t MAX_INTROSET_SIZE = 1024;
|
||||
constexpr std::size_t MAX_INTROSET_SIZE = 4096;
|
||||
|
||||
struct IntroSet : public llarp::IBEncodeMessage
|
||||
{
|
||||
ServiceInfo A;
|
||||
std::vector< Introduction > I;
|
||||
PQPubKey K;
|
||||
Tag topic;
|
||||
llarp::PoW* W = nullptr;
|
||||
llarp::Signature Z;
|
||||
|
@ -31,6 +32,7 @@ namespace llarp
|
|||
{
|
||||
A = std::move(other.A);
|
||||
I = std::move(other.I);
|
||||
K = std::move(other.K);
|
||||
version = std::move(other.version);
|
||||
topic = std::move(other.topic);
|
||||
W = std::move(other.W);
|
||||
|
@ -41,6 +43,7 @@ namespace llarp
|
|||
{
|
||||
A = other.A;
|
||||
I = other.I;
|
||||
K = other.K;
|
||||
version = other.version;
|
||||
topic = other.topic;
|
||||
if(other.W)
|
||||
|
@ -55,6 +58,7 @@ namespace llarp
|
|||
{
|
||||
A = other.A;
|
||||
I = other.I;
|
||||
K = other.K;
|
||||
version = other.version;
|
||||
topic = other.topic;
|
||||
if(W)
|
||||
|
@ -80,6 +84,7 @@ namespace llarp
|
|||
out << intro << ",";
|
||||
}
|
||||
out << "]";
|
||||
out << "K=" << i.K;
|
||||
auto topic = i.topic.ToString();
|
||||
if(topic.size())
|
||||
{
|
||||
|
|
|
@ -97,10 +97,10 @@ namespace llarp
|
|||
void
|
||||
EnsureRouterIsKnown(const RouterID& router);
|
||||
|
||||
Identity*
|
||||
const Identity&
|
||||
GetIdentity()
|
||||
{
|
||||
return &m_Identity;
|
||||
return m_Identity;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -194,7 +194,7 @@ namespace llarp
|
|||
|
||||
bool
|
||||
GetCachedSessionKeyFor(const ConvoTag& remote,
|
||||
SharedSecret& secret) const;
|
||||
const byte_t*& secret) const;
|
||||
void
|
||||
PutCachedSessionKeyFor(const ConvoTag& remote,
|
||||
const SharedSecret& secret);
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace llarp
|
|||
|
||||
virtual bool
|
||||
GetCachedSessionKeyFor(const ConvoTag& remote,
|
||||
SharedSecret& secret) const = 0;
|
||||
const byte_t*& secret) const = 0;
|
||||
virtual void
|
||||
PutCachedSessionKeyFor(const ConvoTag& remote,
|
||||
const SharedSecret& secret) = 0;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <llarp/crypto.hpp>
|
||||
#include <llarp/encrypted.hpp>
|
||||
#include <llarp/routing/message.hpp>
|
||||
#include <llarp/service/Identity.hpp>
|
||||
#include <llarp/service/Info.hpp>
|
||||
#include <llarp/service/Intro.hpp>
|
||||
#include <llarp/service/handler.hpp>
|
||||
|
@ -51,8 +52,8 @@ namespace llarp
|
|||
/// outer message
|
||||
struct ProtocolFrame : public llarp::routing::IMessage
|
||||
{
|
||||
llarp::PQCipherBlock C;
|
||||
llarp::Encrypted D;
|
||||
llarp::PubKey H;
|
||||
llarp::KeyExchangeNonce N;
|
||||
llarp::Signature Z;
|
||||
llarp::service::ConvoTag T;
|
||||
|
@ -63,17 +64,18 @@ namespace llarp
|
|||
~ProtocolFrame();
|
||||
|
||||
bool
|
||||
EncryptAndSign(llarp_crypto* c, const ProtocolMessage* msg,
|
||||
byte_t* sharedkey, byte_t* signingkey);
|
||||
EncryptAndSign(llarp_crypto* c, const ProtocolMessage& msg,
|
||||
const byte_t* sharedkey, const Identity& localIdent);
|
||||
|
||||
bool
|
||||
AsyncDecryptAndVerify(llarp_logic* logic, llarp_crypto* c,
|
||||
llarp_threadpool* worker, byte_t* localSecret,
|
||||
llarp_threadpool* worker,
|
||||
const Identity& localIdent,
|
||||
IDataHandler* handler) const;
|
||||
|
||||
bool
|
||||
DecryptPayloadInto(llarp_crypto* c, byte_t* sharedkey,
|
||||
ProtocolMessage* into) const;
|
||||
DecryptPayloadInto(llarp_crypto* c, const byte_t* sharedkey,
|
||||
ProtocolMessage& into) const;
|
||||
|
||||
bool
|
||||
DecodeKey(llarp_buffer_t key, llarp_buffer_t* val);
|
||||
|
|
|
@ -1,44 +1 @@
|
|||
#ifndef LLARP_BUFFER_HPP
|
||||
#define LLARP_BUFFER_HPP
|
||||
|
||||
#include <llarp/buffer.h>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
template < typename T >
|
||||
llarp_buffer_t
|
||||
StackBuffer(T& stack)
|
||||
{
|
||||
llarp_buffer_t buff;
|
||||
buff.base = &stack[0];
|
||||
buff.cur = buff.base;
|
||||
buff.sz = sizeof(stack);
|
||||
return buff;
|
||||
}
|
||||
|
||||
/** initialize llarp_buffer_t from container */
|
||||
template < typename T >
|
||||
llarp_buffer_t
|
||||
Buffer(T& t)
|
||||
{
|
||||
llarp_buffer_t buff;
|
||||
buff.base = &t[0];
|
||||
buff.cur = buff.base;
|
||||
buff.sz = t.size();
|
||||
return buff;
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
llarp_buffer_t
|
||||
ConstBuffer(const T& t)
|
||||
{
|
||||
llarp_buffer_t buff;
|
||||
buff.base = (byte_t*)&t[0];
|
||||
buff.cur = buff.base;
|
||||
buff.sz = t.size();
|
||||
return buff;
|
||||
}
|
||||
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
||||
#include <llarp/buffer.hpp>
|
|
@ -17,8 +17,8 @@ namespace llarp
|
|||
}
|
||||
|
||||
static bool
|
||||
dh(uint8_t *out, uint8_t *client_pk, uint8_t *server_pk, uint8_t *themPub,
|
||||
uint8_t *usSec)
|
||||
dh(uint8_t *out, const uint8_t *client_pk, const uint8_t *server_pk,
|
||||
const uint8_t *themPub, const uint8_t *usSec)
|
||||
{
|
||||
llarp::SharedSecret shared;
|
||||
crypto_generichash_state h;
|
||||
|
@ -35,7 +35,8 @@ namespace llarp
|
|||
}
|
||||
|
||||
static bool
|
||||
dh_client(uint8_t *shared, uint8_t *pk, uint8_t *sk, uint8_t *n)
|
||||
dh_client(uint8_t *shared, const uint8_t *pk, const uint8_t *sk,
|
||||
const uint8_t *n)
|
||||
{
|
||||
llarp::SharedSecret dh_result;
|
||||
if(dh(dh_result, llarp::seckey_topublic(sk), pk, pk, sk))
|
||||
|
@ -46,7 +47,8 @@ namespace llarp
|
|||
}
|
||||
|
||||
static bool
|
||||
dh_server(uint8_t *shared, uint8_t *pk, uint8_t *sk, uint8_t *n)
|
||||
dh_server(uint8_t *shared, const uint8_t *pk, const uint8_t *sk,
|
||||
const uint8_t *n)
|
||||
{
|
||||
llarp::SharedSecret dh_result;
|
||||
if(dh(dh_result, pk, llarp::seckey_topublic(sk), pk, sk))
|
||||
|
@ -124,24 +126,46 @@ namespace llarp
|
|||
return sec + 32;
|
||||
}
|
||||
|
||||
byte_t *
|
||||
seckey_topublic(byte_t *sec)
|
||||
namespace pq
|
||||
{
|
||||
return sec + 32;
|
||||
bool
|
||||
encrypt(byte_t *ciphertext, byte_t *sharedkey, const byte_t *pubkey)
|
||||
{
|
||||
return crypto_kem_enc(ciphertext, sharedkey, pubkey) != -1;
|
||||
}
|
||||
bool
|
||||
decrypt(const byte_t *ciphertext, byte_t *sharedkey,
|
||||
const byte_t *secretkey)
|
||||
{
|
||||
return crypto_kem_dec(sharedkey, ciphertext, secretkey) != -1;
|
||||
}
|
||||
|
||||
void
|
||||
keygen(byte_t *keypair)
|
||||
{
|
||||
crypto_kem_keypair(keypair + PQ_SECRETKEYSIZE, keypair);
|
||||
}
|
||||
} // namespace pq
|
||||
|
||||
const byte_t *
|
||||
pq_keypair_to_public(const byte_t *k)
|
||||
{
|
||||
return k + PQ_SECRETKEYSIZE;
|
||||
}
|
||||
|
||||
const byte_t *
|
||||
pq_keypair_to_secret(const byte_t *k)
|
||||
{
|
||||
return k;
|
||||
}
|
||||
|
||||
} // namespace llarp
|
||||
|
||||
const byte_t *
|
||||
llarp_seckey_topublic(const byte_t *secret)
|
||||
{
|
||||
return secret + 32;
|
||||
}
|
||||
|
||||
void
|
||||
llarp_crypto_libsodium_init(struct llarp_crypto *c)
|
||||
{
|
||||
assert(sodium_init() != -1);
|
||||
ntru_init();
|
||||
c->xchacha20 = llarp::sodium::xchacha20;
|
||||
c->dh_client = llarp::sodium::dh_client;
|
||||
c->dh_server = llarp::sodium::dh_server;
|
||||
|
@ -156,6 +180,9 @@ llarp_crypto_libsodium_init(struct llarp_crypto *c)
|
|||
c->randbytes = llarp::sodium::randbytes;
|
||||
c->identity_keygen = llarp::sodium::sigkeygen;
|
||||
c->encryption_keygen = llarp::sodium::enckeygen;
|
||||
c->pqe_encrypt = llarp::pq::encrypt;
|
||||
c->pqe_decrypt = llarp::pq::decrypt;
|
||||
c->pqe_keygen = llarp::pq::keygen;
|
||||
int seed;
|
||||
c->randbytes(&seed, sizeof(seed));
|
||||
srand(seed);
|
||||
|
|
|
@ -35,7 +35,8 @@ namespace llarp
|
|||
}
|
||||
|
||||
bool
|
||||
EncryptedFrame::EncryptInPlace(byte_t* ourSecretKey, byte_t* otherPubkey,
|
||||
EncryptedFrame::EncryptInPlace(const byte_t* ourSecretKey,
|
||||
const byte_t* otherPubkey,
|
||||
llarp_crypto* crypto)
|
||||
{
|
||||
// format of frame is
|
||||
|
@ -93,7 +94,8 @@ namespace llarp
|
|||
}
|
||||
|
||||
bool
|
||||
EncryptedFrame::DecryptInPlace(byte_t* ourSecretKey, llarp_crypto* crypto)
|
||||
EncryptedFrame::DecryptInPlace(const byte_t* ourSecretKey,
|
||||
llarp_crypto* crypto)
|
||||
{
|
||||
if(size() <= size_t(EncryptedFrame::OverheadSize))
|
||||
{
|
||||
|
|
|
@ -225,7 +225,7 @@ llarp_link::RemoveSession(llarp_link_session* s)
|
|||
delete s;
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
const uint8_t*
|
||||
llarp_link::pubkey()
|
||||
{
|
||||
return llarp::seckey_topublic(seckey);
|
||||
|
|
|
@ -1,60 +1 @@
|
|||
#ifndef LLARP_MEM_HPP
|
||||
#define LLARP_MEM_HPP
|
||||
#include <llarp/buffer.h>
|
||||
#include <llarp/mem.h>
|
||||
#include <cctype>
|
||||
#include <cstdio>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
void
|
||||
Zero(void *ptr, size_t sz);
|
||||
|
||||
template < typename T >
|
||||
void
|
||||
dumphex(const uint8_t *t)
|
||||
{
|
||||
size_t idx = 0;
|
||||
while(idx < sizeof(T))
|
||||
{
|
||||
printf("%.2x ", t[idx++]);
|
||||
if(idx % 8 == 0)
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
template < typename T, size_t align = 128 >
|
||||
void
|
||||
DumpBuffer(const T &buff)
|
||||
{
|
||||
size_t idx = 0;
|
||||
printf("buffer of size %zu\n", buff.sz);
|
||||
while(idx < buff.sz)
|
||||
{
|
||||
if(buff.base + idx == buff.cur)
|
||||
{
|
||||
printf("%c[1;31m", 27);
|
||||
}
|
||||
if(std::isprint(buff.base[idx]))
|
||||
{
|
||||
printf("%c", buff.base[idx]);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("X");
|
||||
}
|
||||
if(buff.base + idx == buff.cur)
|
||||
{
|
||||
printf("%c[0;0m", 27);
|
||||
}
|
||||
++idx;
|
||||
if(idx % align == 0)
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
||||
#include <llarp/mem.hpp>
|
|
@ -29,6 +29,8 @@ namespace llarp
|
|||
{
|
||||
return BEncodeReadList(I, buf);
|
||||
}
|
||||
if(!BEncodeMaybeReadDictEntry("k", K, read, key, buf))
|
||||
return false;
|
||||
|
||||
if(!BEncodeMaybeReadDictEntry("n", topic, read, key, buf))
|
||||
return false;
|
||||
|
@ -64,6 +66,10 @@ namespace llarp
|
|||
return false;
|
||||
// end introduction list
|
||||
|
||||
// pq pubkey
|
||||
if(!BEncodeWriteDictEntry("k", K, buf))
|
||||
return false;
|
||||
|
||||
// topic tag
|
||||
if(topic.ToString().size())
|
||||
{
|
||||
|
@ -165,6 +171,8 @@ namespace llarp
|
|||
return false;
|
||||
if(!BEncodeWriteDictEntry("e", enckey, buf))
|
||||
return false;
|
||||
if(!BEncodeWriteDictEntry("q", pq, buf))
|
||||
return false;
|
||||
if(!BEncodeWriteDictEntry("s", signkey, buf))
|
||||
return false;
|
||||
if(!BEncodeWriteDictInt("v", version, buf))
|
||||
|
@ -180,6 +188,8 @@ namespace llarp
|
|||
bool read = false;
|
||||
if(!BEncodeMaybeReadDictEntry("e", enckey, read, key, buf))
|
||||
return false;
|
||||
if(!BEncodeMaybeReadDictEntry("q", pq, read, key, buf))
|
||||
return false;
|
||||
if(!BEncodeMaybeReadDictEntry("s", signkey, read, key, buf))
|
||||
return false;
|
||||
if(!BEncodeMaybeReadDictInt("v", version, read, key, buf))
|
||||
|
@ -196,12 +206,26 @@ namespace llarp
|
|||
crypto->identity_keygen(signkey);
|
||||
pub.Update(llarp::seckey_topublic(enckey),
|
||||
llarp::seckey_topublic(signkey));
|
||||
crypto->pqe_keygen(pq);
|
||||
}
|
||||
|
||||
bool
|
||||
Identity::KeyExchange(llarp_path_dh_func dh, byte_t* result,
|
||||
const ServiceInfo& other, const byte_t* N) const
|
||||
{
|
||||
return dh(result, other.EncryptionPublicKey(), enckey, N);
|
||||
}
|
||||
|
||||
bool
|
||||
Identity::Sign(llarp_crypto* c, byte_t* sig, llarp_buffer_t buf) const
|
||||
{
|
||||
return c->sign(sig, signkey, buf);
|
||||
}
|
||||
|
||||
bool
|
||||
Identity::EnsureKeys(const std::string& fname, llarp_crypto* c)
|
||||
{
|
||||
byte_t tmp[256];
|
||||
byte_t tmp[4096];
|
||||
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
|
||||
std::error_code ec;
|
||||
// check for file
|
||||
|
@ -244,7 +268,10 @@ namespace llarp
|
|||
{
|
||||
if(i.I.size() == 0)
|
||||
return false;
|
||||
// set service info
|
||||
i.A = pub;
|
||||
// set public encryption key
|
||||
i.K = pq_keypair_to_public(pq);
|
||||
// zero out signature for signing process
|
||||
i.Z.Zero();
|
||||
byte_t tmp[MAX_INTROSET_SIZE];
|
||||
|
@ -254,7 +281,7 @@ namespace llarp
|
|||
// rewind and resize buffer
|
||||
buf.sz = buf.cur - buf.base;
|
||||
buf.cur = buf.base;
|
||||
return crypto->sign(i.Z, signkey, buf);
|
||||
return Sign(crypto, i.Z, buf);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -344,12 +344,12 @@ namespace llarp
|
|||
|
||||
bool
|
||||
Endpoint::GetCachedSessionKeyFor(const ConvoTag& tag,
|
||||
SharedSecret& secret) const
|
||||
const byte_t*& secret) const
|
||||
{
|
||||
auto itr = m_Sessions.find(tag);
|
||||
if(itr == m_Sessions.end())
|
||||
return false;
|
||||
secret = itr->second.sharedKey;
|
||||
secret = itr->second.sharedKey.data();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -626,7 +626,7 @@ namespace llarp
|
|||
Endpoint::HandleHiddenServiceFrame(const ProtocolFrame* frame)
|
||||
{
|
||||
return frame->AsyncDecryptAndVerify(EndpointLogic(), Crypto(), Worker(),
|
||||
m_Identity.enckey, m_DataHandler);
|
||||
m_Identity, m_DataHandler);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -760,15 +760,16 @@ namespace llarp
|
|||
llarp_crypto* crypto;
|
||||
byte_t* sharedKey;
|
||||
ServiceInfo remote;
|
||||
Identity* m_LocalIdentity;
|
||||
const Identity& m_LocalIdentity;
|
||||
ProtocolMessage msg;
|
||||
ProtocolFrame frame;
|
||||
Introduction intro;
|
||||
PQPubKey introPubKey;
|
||||
std::function< void(ProtocolFrame&) > hook;
|
||||
IDataHandler* handler;
|
||||
|
||||
AsyncIntroGen(llarp_logic* l, llarp_crypto* c, byte_t* key,
|
||||
const ServiceInfo& r, Identity* localident,
|
||||
const ServiceInfo& r, const Identity& localident,
|
||||
const Introduction& us, IDataHandler* h)
|
||||
: logic(l)
|
||||
, crypto(c)
|
||||
|
@ -796,28 +797,34 @@ namespace llarp
|
|||
Work(void* user)
|
||||
{
|
||||
AsyncIntroGen* self = static_cast< AsyncIntroGen* >(user);
|
||||
// derive ntru session key component
|
||||
SharedSecret K;
|
||||
self->crypto->pqe_encrypt(self->frame.C, K, self->introPubKey);
|
||||
// randomize Nounce
|
||||
self->frame.N.Randomize();
|
||||
// ephemeral public key
|
||||
SecretKey ephem;
|
||||
self->crypto->encryption_keygen(ephem);
|
||||
self->frame.H = llarp::seckey_topublic(ephem);
|
||||
// compure post handshake session key
|
||||
byte_t tmp[64];
|
||||
// K
|
||||
memcpy(tmp, K, 32);
|
||||
// PKE (A, B, N)
|
||||
if(!self->m_LocalIdentity.KeyExchange(self->crypto->dh_client, tmp + 64,
|
||||
self->remote, self->frame.N))
|
||||
llarp::LogError("failed to derive x25519 shared key component");
|
||||
// H (K + PKE(A, B, N))
|
||||
self->crypto->shorthash(self->sharedKey,
|
||||
llarp::StackBuffer< decltype(tmp) >(tmp));
|
||||
// randomize tag
|
||||
self->msg.tag.Randomize();
|
||||
// set sender
|
||||
self->msg.sender = self->m_LocalIdentity->pub;
|
||||
self->msg.sender = self->m_LocalIdentity.pub;
|
||||
// set our introduction
|
||||
self->msg.introReply = self->intro;
|
||||
// derive session key
|
||||
self->crypto->dh_server(self->sharedKey,
|
||||
self->remote.EncryptionPublicKey(), ephem,
|
||||
self->frame.N);
|
||||
|
||||
// encrypt and sign
|
||||
self->frame.EncryptAndSign(self->crypto, &self->msg, self->sharedKey,
|
||||
self->m_LocalIdentity->signkey);
|
||||
// inform result
|
||||
llarp_logic_queue_job(self->logic, {self, &Result});
|
||||
if(self->frame.EncryptAndSign(self->crypto, self->msg, K,
|
||||
self->m_LocalIdentity))
|
||||
llarp_logic_queue_job(self->logic, {self, &Result});
|
||||
else
|
||||
llarp::LogError("failed to encrypt and sign");
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -955,8 +962,8 @@ namespace llarp
|
|||
llarp::LogError("no open converstations with remote endpoint?");
|
||||
return;
|
||||
}
|
||||
auto crypto = m_Parent->Crypto();
|
||||
SharedSecret shared;
|
||||
auto crypto = m_Parent->Crypto();
|
||||
const byte_t* shared = nullptr;
|
||||
routing::PathTransferMessage msg;
|
||||
ProtocolFrame& f = msg.T;
|
||||
f.N.Randomize();
|
||||
|
@ -970,8 +977,7 @@ namespace llarp
|
|||
m.sender = m_Parent->m_Identity.pub;
|
||||
m.PutBuffer(payload);
|
||||
|
||||
if(!f.EncryptAndSign(crypto, &m, shared,
|
||||
m_Parent->m_Identity.signkey))
|
||||
if(!f.EncryptAndSign(crypto, m, shared, m_Parent->m_Identity))
|
||||
{
|
||||
llarp::LogError("failed to sign");
|
||||
return;
|
||||
|
|
|
@ -95,20 +95,20 @@ namespace llarp
|
|||
{
|
||||
if(!bencode_start_dict(buf))
|
||||
return false;
|
||||
|
||||
if(!BEncodeWriteDictMsgType(buf, "A", "H"))
|
||||
return false;
|
||||
if(!BEncodeWriteDictEntry("D", D, buf))
|
||||
return false;
|
||||
if(S == 0)
|
||||
if(!C.IsZero())
|
||||
{
|
||||
if(!BEncodeWriteDictEntry("H", H, buf))
|
||||
if(!BEncodeWriteDictEntry("C", C, buf))
|
||||
return false;
|
||||
}
|
||||
if(!BEncodeWriteDictEntry("D", D, buf))
|
||||
return false;
|
||||
|
||||
if(!BEncodeWriteDictEntry("N", N, buf))
|
||||
return false;
|
||||
if(!BEncodeWriteDictInt("S", S, buf))
|
||||
return false;
|
||||
if(S == 0)
|
||||
if(!T.IsZero())
|
||||
{
|
||||
if(!BEncodeWriteDictEntry("T", T, buf))
|
||||
return false;
|
||||
|
@ -135,7 +135,7 @@ namespace llarp
|
|||
}
|
||||
if(!BEncodeMaybeReadDictEntry("D", D, read, key, val))
|
||||
return false;
|
||||
if(!BEncodeMaybeReadDictEntry("H", H, read, key, val))
|
||||
if(!BEncodeMaybeReadDictEntry("C", C, read, key, val))
|
||||
return false;
|
||||
if(!BEncodeMaybeReadDictEntry("N", N, read, key, val))
|
||||
return false;
|
||||
|
@ -152,23 +152,25 @@ namespace llarp
|
|||
}
|
||||
|
||||
bool
|
||||
ProtocolFrame::DecryptPayloadInto(llarp_crypto* crypto, byte_t* sharedkey,
|
||||
ProtocolMessage* msg) const
|
||||
ProtocolFrame::DecryptPayloadInto(llarp_crypto* crypto,
|
||||
const byte_t* sharedkey,
|
||||
ProtocolMessage& msg) const
|
||||
{
|
||||
auto buf = D.Buffer();
|
||||
crypto->xchacha20(buf, sharedkey, N);
|
||||
msg->PutBuffer(buf);
|
||||
msg.PutBuffer(buf);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ProtocolFrame::EncryptAndSign(llarp_crypto* crypto,
|
||||
const ProtocolMessage* msg,
|
||||
byte_t* sessionKey, byte_t* signingkey)
|
||||
const ProtocolMessage& msg,
|
||||
const byte_t* sessionKey,
|
||||
const Identity& localIdent)
|
||||
{
|
||||
// put payload and encrypt
|
||||
D = llarp::ConstBuffer(msg->payload);
|
||||
memcpy(D.data(), msg->payload.data(), D.size());
|
||||
D = llarp::ConstBuffer(msg.payload);
|
||||
memcpy(D.data(), msg.payload.data(), D.size());
|
||||
auto dbuf = D.Buffer();
|
||||
crypto->xchacha20(*dbuf, sessionKey, N);
|
||||
// zero out signature
|
||||
|
@ -182,7 +184,7 @@ namespace llarp
|
|||
buf.sz = buf.cur - buf.base;
|
||||
buf.cur = buf.base;
|
||||
// sign
|
||||
return crypto->sign(Z, signingkey, buf);
|
||||
return localIdent.Sign(crypto, Z, buf);
|
||||
}
|
||||
|
||||
struct AsyncFrameDH
|
||||
|
@ -190,24 +192,22 @@ namespace llarp
|
|||
llarp_crypto* crypto;
|
||||
llarp_logic* logic;
|
||||
ProtocolMessage* msg;
|
||||
byte_t* localSecret;
|
||||
PubKey H;
|
||||
KeyExchangeNonce N;
|
||||
const Identity& m_LocalIdentity;
|
||||
PQPubKey introPubKey;
|
||||
IDataHandler* handler;
|
||||
Address remote;
|
||||
Encrypted D;
|
||||
const ProtocolFrame* frame;
|
||||
|
||||
AsyncFrameDH(llarp_logic* l, llarp_crypto* c, byte_t* sec,
|
||||
IDataHandler* h, ProtocolMessage* m,
|
||||
const ProtocolFrame* frame)
|
||||
AsyncFrameDH(llarp_logic* l, llarp_crypto* c, const Identity& localIdent,
|
||||
IDataHandler* h, ProtocolMessage* m, const ProtocolFrame* f)
|
||||
: crypto(c)
|
||||
, logic(l)
|
||||
, msg(m)
|
||||
, localSecret(sec)
|
||||
, H(frame->H)
|
||||
, N(frame->N)
|
||||
, m_LocalIdentity(localIdent)
|
||||
, handler(h)
|
||||
, D(frame->D)
|
||||
, D(f->D)
|
||||
, frame(f)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -216,18 +216,20 @@ namespace llarp
|
|||
{
|
||||
AsyncFrameDH* self = static_cast< AsyncFrameDH* >(user);
|
||||
auto crypto = self->crypto;
|
||||
SharedSecret shared;
|
||||
if(!crypto->dh_client(shared, self->H, self->localSecret, self->N))
|
||||
SharedSecret K;
|
||||
SharedSecret sharedKey;
|
||||
// copy
|
||||
ProtocolFrame frame = *self->frame;
|
||||
if(!crypto->pqe_decrypt(self->frame->C, K,
|
||||
pq_keypair_to_secret(self->m_LocalIdentity.pq)))
|
||||
{
|
||||
llarp::LogError(
|
||||
"Failed to derive shared secret for initial message H=", self->H,
|
||||
" N=", self->N);
|
||||
llarp::LogError("pqke failed");
|
||||
delete self->msg;
|
||||
delete self;
|
||||
return;
|
||||
}
|
||||
auto buf = self->D.Buffer();
|
||||
crypto->xchacha20(*buf, shared, self->N);
|
||||
crypto->xchacha20(*buf, K, self->frame->N);
|
||||
if(!self->msg->BDecode(buf))
|
||||
{
|
||||
llarp::LogError("failed to decode inner protocol message");
|
||||
|
@ -236,9 +238,35 @@ namespace llarp
|
|||
delete self;
|
||||
return;
|
||||
}
|
||||
// verify signature of outer message after we parsed the inner message
|
||||
if(!frame.Verify(crypto, self->msg->sender))
|
||||
{
|
||||
llarp::LogError("intro frame has invalid signature");
|
||||
frame.Dump< MAX_PROTOCOL_MESSAGE_SIZE >();
|
||||
delete self->msg;
|
||||
delete self;
|
||||
return;
|
||||
}
|
||||
byte_t tmp[64];
|
||||
// K
|
||||
memcpy(tmp, K, 32);
|
||||
// PKE (A, B, N)
|
||||
if(!self->m_LocalIdentity.KeyExchange(
|
||||
crypto->dh_server, tmp + 32, self->msg->sender, self->frame->N))
|
||||
{
|
||||
llarp::LogError("x25519 key exchange failed");
|
||||
frame.Dump< MAX_PROTOCOL_MESSAGE_SIZE >();
|
||||
delete self->msg;
|
||||
delete self;
|
||||
return;
|
||||
}
|
||||
// S = HS( K + PKE( A, B, N))
|
||||
crypto->shorthash(sharedKey, StackBuffer< decltype(tmp) >(tmp));
|
||||
|
||||
self->handler->PutIntroFor(self->msg->tag, self->msg->introReply);
|
||||
self->handler->PutSenderFor(self->msg->tag, self->msg->sender);
|
||||
self->handler->PutCachedSessionKeyFor(self->msg->tag, shared);
|
||||
self->handler->PutCachedSessionKeyFor(self->msg->tag, sharedKey);
|
||||
|
||||
self->msg->handler = self->handler;
|
||||
llarp_logic_queue_job(self->logic,
|
||||
{self->msg, &ProtocolMessage::ProcessAsync});
|
||||
|
@ -247,22 +275,20 @@ namespace llarp
|
|||
};
|
||||
|
||||
bool
|
||||
ProtocolFrame::AsyncDecryptAndVerify(llarp_logic* logic,
|
||||
llarp_crypto* crypto,
|
||||
ProtocolFrame::AsyncDecryptAndVerify(llarp_logic* logic, llarp_crypto* c,
|
||||
llarp_threadpool* worker,
|
||||
byte_t* localSecret,
|
||||
const Identity& localIdent,
|
||||
IDataHandler* handler) const
|
||||
{
|
||||
if(S == 0)
|
||||
{
|
||||
ProtocolMessage* msg = new ProtocolMessage();
|
||||
// we need to dh
|
||||
auto dh =
|
||||
new AsyncFrameDH(logic, crypto, localSecret, handler, msg, this);
|
||||
auto dh = new AsyncFrameDH(logic, c, localIdent, handler, msg, this);
|
||||
llarp_threadpool_queue_job(worker, {dh, &AsyncFrameDH::Work});
|
||||
return true;
|
||||
}
|
||||
SharedSecret shared;
|
||||
const byte_t* shared = nullptr;
|
||||
if(!handler->GetCachedSessionKeyFor(T, shared))
|
||||
{
|
||||
llarp::LogError("No cached session for T=", T);
|
||||
|
@ -274,13 +300,13 @@ namespace llarp
|
|||
llarp::LogError("No sender for T=", T);
|
||||
return false;
|
||||
}
|
||||
if(!Verify(crypto, si))
|
||||
if(!Verify(c, si))
|
||||
{
|
||||
llarp::LogError("Signature failure");
|
||||
return false;
|
||||
}
|
||||
ProtocolMessage* msg = new ProtocolMessage();
|
||||
if(!DecryptPayloadInto(crypto, shared, msg))
|
||||
if(!DecryptPayloadInto(c, shared, *msg))
|
||||
{
|
||||
llarp::LogError("failed to decrypt message");
|
||||
delete msg;
|
||||
|
@ -297,7 +323,7 @@ namespace llarp
|
|||
}
|
||||
|
||||
ProtocolFrame::ProtocolFrame(const ProtocolFrame& other)
|
||||
: D(other.D), H(other.H), N(other.N), Z(other.Z), T(other.T)
|
||||
: C(other.C), D(other.D), N(other.N), Z(other.Z), T(other.T)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <llarp/crypto.hpp>
|
||||
#include <iostream>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
struct PQCryptoTest : public ::testing::Test
|
||||
{
|
||||
llarp_crypto crypto;
|
||||
PQKeyPair keys;
|
||||
|
||||
PQCryptoTest()
|
||||
{
|
||||
llarp_crypto_libsodium_init(&crypto);
|
||||
}
|
||||
|
||||
llarp_crypto * Crypto()
|
||||
{
|
||||
return &crypto;
|
||||
}
|
||||
|
||||
void SetUp()
|
||||
{
|
||||
crypto.pqe_keygen(keys);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
TEST_F(PQCryptoTest, TestCrypto)
|
||||
{
|
||||
PQCipherBlock block;
|
||||
SharedSecret shared, otherShared;
|
||||
auto c = Crypto();
|
||||
|
||||
ASSERT_TRUE(keys.size() == PQ_KEYPAIRSIZE);
|
||||
ASSERT_TRUE(c->pqe_encrypt(block, shared, pq_keypair_to_public(keys)));
|
||||
ASSERT_TRUE(c->pqe_decrypt(block, otherShared, pq_keypair_to_secret(keys)));
|
||||
ASSERT_TRUE(otherShared == shared);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue