Skip to content

Commit 6d448bb

Browse files
goldroomiphydf
authored andcommitted
feat: Noise IK handshake implementation
1 parent 8ffeabe commit 6d448bb

31 files changed

Lines changed: 3386 additions & 195 deletions

CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,8 @@ set(toxcore_SOURCES
243243
toxcore/ccompat.h
244244
toxcore/crypto_core.c
245245
toxcore/crypto_core.h
246+
toxcore/noise.c
247+
toxcore/noise.h
246248
toxcore/crypto_core_pack.c
247249
toxcore/crypto_core_pack.h
248250
toxcore/DHT.c
@@ -639,6 +641,7 @@ if(UNITTEST AND TARGET GTest::gtest AND TARGET GTest::gmock)
639641
unit_test(toxcore mem)
640642
unit_test(toxcore mono_time)
641643
unit_test(toxcore net_crypto)
644+
unit_test(toxcore noise)
642645
unit_test(toxcore network)
643646
unit_test(toxcore onion_client)
644647
unit_test(toxcore ping_array)

auto_tests/forwarding_test.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ static Forwarding_Subtox *new_forwarding_subtox(const Memory *mem, bool no_udp,
132132
ck_assert(subtox->tcp_np != nullptr);
133133

134134
const TCP_Proxy_Info inf = {{{{0}}}};
135-
subtox->c = new_net_crypto(subtox->log, mem, rng, ns, subtox->mono_time, subtox->net, subtox->dht, &auto_test_dht_funcs, &inf, subtox->tcp_np);
135+
subtox->c = new_net_crypto(subtox->log, mem, rng, ns, subtox->mono_time, subtox->net, subtox->dht, &auto_test_dht_funcs, &inf, subtox->tcp_np, CRYPTO_HANDSHAKE_MODE_NOISE_BOTH);
136136

137137
subtox->forwarding = new_forwarding(subtox->log, mem, rng, subtox->mono_time, subtox->dht, subtox->net);
138138
ck_assert(subtox->forwarding != nullptr);

auto_tests/onion_test.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,7 @@ static Onions *new_onions(const Memory *mem, const Random *rng, uint16_t port, u
492492
}
493493

494494
TCP_Proxy_Info inf = {{{{0}}}};
495-
on->nc = new_net_crypto(on->log, mem, rng, ns, on->mono_time, net, dht, &auto_test_dht_funcs, &inf, on->tcp_np);
495+
on->nc = new_net_crypto(on->log, mem, rng, ns, on->mono_time, net, dht, &auto_test_dht_funcs, &inf, on->tcp_np, CRYPTO_HANDSHAKE_MODE_NOISE_BOTH);
496496
on->onion_c = new_onion_client(on->log, mem, rng, on->mono_time, on->nc, dht, net);
497497

498498
if (!on->onion_c) {

auto_tests/scenarios/scenario_toxav_peer_offline_test.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ int main(int argc, char *argv[])
133133

134134
ToxScenarioStatus res = tox_scenario_run(s);
135135
if (res != TOX_SCENARIO_DONE) {
136-
fprintf(stderr, "Scenario failed with status %d\n", res);
136+
fprintf(stderr, "Scenario failed with status %u\n", res);
137137
return 1;
138138
}
139139

toxcore/BUILD.bazel

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,33 @@ cc_library(
340340
],
341341
)
342342

343+
cc_library(
344+
name = "noise",
345+
srcs = ["noise.c"],
346+
hdrs = ["noise.h"],
347+
visibility = ["//c-toxcore:__subpackages__"],
348+
deps = [
349+
":attributes",
350+
":ccompat",
351+
":crypto_core",
352+
"@libsodium",
353+
],
354+
)
355+
356+
cc_test(
357+
name = "noise_test",
358+
size = "small",
359+
srcs = ["noise_test.cc"],
360+
deps = [
361+
":crypto_core",
362+
":crypto_core_test_util",
363+
":noise",
364+
"//c-toxcore/testing/support",
365+
"@com_google_googletest//:gtest",
366+
"@com_google_googletest//:gtest_main",
367+
],
368+
)
369+
343370
cc_library(
344371
name = "crypto_core_pack",
345372
srcs = ["crypto_core_pack.c"],
@@ -375,6 +402,7 @@ cc_test(
375402
deps = [
376403
":crypto_core",
377404
":crypto_core_test_util",
405+
":noise",
378406
":util",
379407
"//c-toxcore/testing/support",
380408
"@com_google_googletest//:gtest",
@@ -1030,6 +1058,7 @@ cc_library(
10301058
":net",
10311059
":net_profile",
10321060
":network",
1061+
":noise",
10331062
":rng",
10341063
":util",
10351064
"@pthread",

toxcore/Makefile.inc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ libtoxcore_la_SOURCES = ../third_party/cmp/cmp.c \
6464
../toxcore/crypto_core_pack.h \
6565
../toxcore/crypto_core.c \
6666
../toxcore/crypto_core.h \
67+
../toxcore/noise.c \
68+
../toxcore/noise.h \
6769
../toxcore/DHT.c \
6870
../toxcore/DHT.h \
6971
../toxcore/ev.c \

toxcore/Messenger.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3470,7 +3470,7 @@ Messenger *new_messenger(Mono_Time *mono_time, const Memory *mem, const Random *
34703470
}
34713471
m->tcp_np = tcp_np;
34723472

3473-
Net_Crypto *net_crypto = new_net_crypto(m->log, m->mem, m->rng, m->ns, m->mono_time, m->net, m->dht, &m_dht_funcs, &options->proxy_info, m->tcp_np);
3473+
Net_Crypto *net_crypto = new_net_crypto(m->log, m->mem, m->rng, m->ns, m->mono_time, m->net, m->dht, &m_dht_funcs, &options->proxy_info, m->tcp_np, options->handshake_mode);
34743474

34753475
if (net_crypto == nullptr) {
34763476
LOGGER_WARNING(m->log, "net_crypto initialisation failed");

toxcore/Messenger.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ typedef struct Messenger_Options {
7777
Logger *_Nonnull log;
7878

7979
bool ipv6enabled;
80+
Crypto_Handshake_Mode handshake_mode;
8081
bool udp_disabled;
8182
TCP_Proxy_Info proxy_info;
8283
uint16_t port_range[2];

toxcore/crypto_core.c

Lines changed: 100 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ static_assert(CRYPTO_MAC_SIZE == crypto_box_MACBYTES,
2828
"CRYPTO_MAC_SIZE should be equal to crypto_box_MACBYTES");
2929
static_assert(CRYPTO_NONCE_SIZE == crypto_box_NONCEBYTES,
3030
"CRYPTO_NONCE_SIZE should be equal to crypto_box_NONCEBYTES");
31+
static_assert(CRYPTO_NOISE_NONCE_SIZE == crypto_stream_chacha20_ietf_NONCEBYTES,
32+
"CRYPTO_NOISE_NONCE_SIZE should be equal to crypto_stream_chacha20_ietf_NONCEBYTES");
3133
static_assert(CRYPTO_HMAC_SIZE == crypto_auth_BYTES,
3234
"CRYPTO_HMAC_SIZE should be equal to crypto_auth_BYTES");
3335
static_assert(CRYPTO_HMAC_KEY_SIZE == crypto_auth_KEYBYTES,
@@ -46,6 +48,12 @@ static_assert(CRYPTO_SIGN_PUBLIC_KEY_SIZE == crypto_sign_PUBLICKEYBYTES,
4648
static_assert(CRYPTO_SIGN_SECRET_KEY_SIZE == crypto_sign_SECRETKEYBYTES,
4749
"CRYPTO_SIGN_SECRET_KEY_SIZE should be equal to crypto_sign_SECRETKEYBYTES");
4850

51+
52+
static_assert(CRYPTO_MAC_SIZE == crypto_aead_chacha20poly1305_IETF_ABYTES,
53+
"CRYPTO_MAC_SIZE should be equal to crypto_aead_chacha20poly1305_IETF_ABYTES");
54+
static_assert(CRYPTO_SHARED_KEY_SIZE == CRYPTO_SYMMETRIC_KEY_SIZE,
55+
"CRYPTO_SHARED_KEY_SIZE should be equal to CRYPTO_SYMMETRIC_KEY_SIZE");
56+
4957
bool create_extended_keypair(Extended_Public_Key *pk, Extended_Secret_Key *sk, const Random *rng)
5058
{
5159
/* create signature key pair */
@@ -235,7 +243,7 @@ int32_t encrypt_data_symmetric(const Memory *mem,
235243
const uint8_t nonce[CRYPTO_NONCE_SIZE],
236244
const uint8_t *plain, size_t length, uint8_t *encrypted)
237245
{
238-
if (length == 0 || shared_key == nullptr || nonce == nullptr || plain == nullptr || encrypted == nullptr) {
246+
if (length == 0 || length >= INT32_MAX - crypto_box_MACBYTES || shared_key == nullptr || nonce == nullptr || plain == nullptr || encrypted == nullptr) {
239247
return -1;
240248
}
241249

@@ -280,7 +288,6 @@ int32_t encrypt_data_symmetric(const Memory *mem,
280288
crypto_free(mem, temp_plain, size_temp_plain);
281289
crypto_free(mem, temp_encrypted, size_temp_encrypted);
282290
#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
283-
assert(length < INT32_MAX - crypto_box_MACBYTES);
284291
return (int32_t)(length + crypto_box_MACBYTES);
285292
}
286293

@@ -289,13 +296,12 @@ int32_t decrypt_data_symmetric(const Memory *mem,
289296
const uint8_t nonce[CRYPTO_NONCE_SIZE],
290297
const uint8_t *encrypted, size_t length, uint8_t *plain)
291298
{
292-
if (length <= crypto_box_BOXZEROBYTES || shared_key == nullptr || nonce == nullptr || encrypted == nullptr
299+
if (length <= crypto_box_BOXZEROBYTES || length >= INT32_MAX || shared_key == nullptr || nonce == nullptr || encrypted == nullptr
293300
|| plain == nullptr) {
294301
return -1;
295302
}
296303

297304
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
298-
assert(length >= crypto_box_MACBYTES);
299305
memcpy(plain, encrypted, length - crypto_box_MACBYTES); // Don't encrypt anything
300306
#else
301307

@@ -332,8 +338,6 @@ int32_t decrypt_data_symmetric(const Memory *mem,
332338
crypto_free(mem, temp_plain, size_temp_plain);
333339
crypto_free(mem, temp_encrypted, size_temp_encrypted);
334340
#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
335-
assert(length > crypto_box_MACBYTES);
336-
assert(length < INT32_MAX);
337341
return (int32_t)(length - crypto_box_MACBYTES);
338342
}
339343

@@ -373,10 +377,7 @@ int32_t decrypt_data(const Memory *mem,
373377

374378
void increment_nonce(uint8_t nonce[CRYPTO_NONCE_SIZE])
375379
{
376-
/* TODO(irungentoo): use `increment_nonce_number(nonce, 1)` or
377-
* sodium_increment (change to little endian).
378-
*
379-
* NOTE don't use breaks inside this loop.
380+
/* NOTE don't use breaks inside this loop.
380381
* In particular, make sure, as far as possible,
381382
* that loop bounds and their potential underflow or overflow
382383
* are independent of user-controlled input (you may have heard of the Heartbleed bug).
@@ -488,3 +489,92 @@ void random_bytes(const Random *rng, uint8_t *bytes, size_t length)
488489
{
489490
rng_bytes(rng, bytes, length);
490491
}
492+
493+
// Necessary functions for Noise, cf. https://noiseprotocol.org/noise.html (Revision 34)
494+
495+
int32_t encrypt_data_symmetric_aead(const uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE], const uint8_t nonce[CRYPTO_NOISE_NONCE_SIZE],
496+
const uint8_t *plain, size_t plain_length, uint8_t *encrypted,
497+
const uint8_t *ad, size_t ad_length)
498+
{
499+
if (plain_length == 0 || plain_length >= INT32_MAX - crypto_aead_chacha20poly1305_IETF_ABYTES
500+
|| shared_key == nullptr || nonce == nullptr || plain == nullptr || encrypted == nullptr) {
501+
return -1;
502+
}
503+
504+
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
505+
memcpy(encrypted, plain, plain_length);
506+
memzero(encrypted + plain_length, crypto_aead_chacha20poly1305_IETF_ABYTES);
507+
#else
508+
if (crypto_aead_chacha20poly1305_ietf_encrypt(encrypted, nullptr, plain, plain_length,
509+
ad, ad_length, nullptr, nonce, shared_key) != 0) {
510+
return -1;
511+
}
512+
#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
513+
514+
return (int32_t)(plain_length + crypto_aead_chacha20poly1305_IETF_ABYTES);
515+
}
516+
517+
int32_t decrypt_data_symmetric_aead(const uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE], const uint8_t nonce[CRYPTO_NOISE_NONCE_SIZE],
518+
const uint8_t *encrypted, size_t encrypted_length, uint8_t *plain,
519+
const uint8_t *ad, size_t ad_length)
520+
{
521+
if (encrypted_length <= crypto_aead_chacha20poly1305_IETF_ABYTES || encrypted_length >= INT32_MAX
522+
|| shared_key == nullptr || nonce == nullptr || encrypted == nullptr || plain == nullptr) {
523+
return -1;
524+
}
525+
526+
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
527+
memcpy(plain, encrypted, encrypted_length - crypto_aead_chacha20poly1305_IETF_ABYTES);
528+
#else
529+
if (crypto_aead_chacha20poly1305_ietf_decrypt(plain, nullptr, nullptr, encrypted,
530+
encrypted_length, ad, ad_length, nonce, shared_key) != 0) {
531+
return -1;
532+
}
533+
#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
534+
535+
return (int32_t)(encrypted_length - crypto_aead_chacha20poly1305_IETF_ABYTES);
536+
}
537+
538+
int32_t encrypt_data_symmetric_xaead(const uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE], const uint8_t nonce[CRYPTO_NONCE_SIZE],
539+
const uint8_t *plain, size_t plain_length, uint8_t *encrypted,
540+
const uint8_t *ad, size_t ad_length)
541+
{
542+
if (plain_length == 0 || plain_length >= INT32_MAX - crypto_aead_xchacha20poly1305_ietf_ABYTES
543+
|| shared_key == nullptr || nonce == nullptr || plain == nullptr || encrypted == nullptr) {
544+
return -1;
545+
}
546+
547+
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
548+
memcpy(encrypted, plain, plain_length);
549+
memzero(encrypted + plain_length, crypto_aead_xchacha20poly1305_ietf_ABYTES);
550+
#else
551+
if (crypto_aead_xchacha20poly1305_ietf_encrypt(encrypted, nullptr, plain, plain_length,
552+
ad, ad_length, nullptr, nonce, shared_key) != 0) {
553+
return -1;
554+
}
555+
#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
556+
557+
return (int32_t)(plain_length + crypto_aead_xchacha20poly1305_ietf_ABYTES);
558+
}
559+
560+
int32_t decrypt_data_symmetric_xaead(const uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE], const uint8_t nonce[CRYPTO_NONCE_SIZE],
561+
const uint8_t *encrypted, size_t encrypted_length, uint8_t *plain,
562+
const uint8_t *ad, size_t ad_length)
563+
{
564+
if (encrypted_length <= crypto_aead_xchacha20poly1305_ietf_ABYTES || encrypted_length >= INT32_MAX
565+
|| shared_key == nullptr || nonce == nullptr || encrypted == nullptr || plain == nullptr) {
566+
return -1;
567+
}
568+
569+
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
570+
memcpy(plain, encrypted, encrypted_length - crypto_aead_xchacha20poly1305_ietf_ABYTES);
571+
#else
572+
if (crypto_aead_xchacha20poly1305_ietf_decrypt(plain, nullptr, nullptr, encrypted,
573+
encrypted_length, ad, ad_length, nonce, shared_key) != 0) {
574+
return -1;
575+
}
576+
#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
577+
578+
return (int32_t)(encrypted_length - crypto_aead_xchacha20poly1305_ietf_ABYTES);
579+
}
580+

toxcore/crypto_core.h

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ extern "C" {
6969
*/
7070
#define CRYPTO_NONCE_SIZE 24
7171

72+
/**
73+
* @brief NoiseIK: The number of bytes in a nonce used for encryption/decryption (ChaChaPoly1305-IETF).
74+
*/
75+
#define CRYPTO_NOISE_NONCE_SIZE 12
76+
7277
/**
7378
* @brief The number of bytes in a SHA256 hash.
7479
*/
@@ -79,6 +84,7 @@ extern "C" {
7984
*/
8085
#define CRYPTO_SHA512_SIZE 64
8186

87+
8288
/**
8389
* @brief The number of bytes in an encryption public key used by DHT group chats.
8490
*/
@@ -278,9 +284,6 @@ typedef struct Extended_Secret_Key {
278284
* @brief Creates an extended keypair: curve25519 and ed25519 for encryption and signing
279285
* respectively. The Encryption keys are derived from the signature keys.
280286
*
281-
* NOTE: This does *not* use Random, so any code using this will not be fuzzable.
282-
* TODO: Make it use Random.
283-
*
284287
* @param[out] pk The buffer where the public key will be stored. Must have room for EXT_PUBLIC_KEY_SIZE bytes.
285288
* @param[out] sk The buffer where the secret key will be stored. Must have room for EXT_SECRET_KEY_SIZE bytes.
286289
* @param rng The random number generator to use for the key generator seed.
@@ -417,6 +420,64 @@ bool crypto_memunlock(void *_Nonnull data, size_t length);
417420
*/
418421
void new_hmac_key(const Random *_Nonnull rng, uint8_t key[_Nonnull CRYPTO_HMAC_KEY_SIZE]);
419422

423+
/**
424+
* @brief Encrypt message with precomputed shared key using ChaCha20-Poly1305-IETF (RFC7539).
425+
*
426+
* Encrypts plain of plain_length to encrypted of plain_length + @ref CRYPTO_MAC_SIZE
427+
* using a shared key @ref CRYPTO_SHARED_KEY_SIZE big and a @ref CRYPTO_NOISE_NONCE_SIZE
428+
* byte nonce. The encrypted message, as well as a tag authenticating both the confidential
429+
* message m and adlen bytes of non-confidential data ad, are put into encrypted.
430+
*
431+
* @retval -1 if there was a problem.
432+
* @return length of encrypted data if everything was fine.
433+
*/
434+
int32_t encrypt_data_symmetric_aead(const uint8_t shared_key[_Nonnull CRYPTO_SHARED_KEY_SIZE], const uint8_t nonce[_Nonnull CRYPTO_NOISE_NONCE_SIZE], const uint8_t *_Nonnull plain,
435+
size_t plain_length,
436+
uint8_t encrypted[_Nonnull /*! plain_length + CRYPTO_MAC_SIZE */], const uint8_t *_Nullable ad, size_t ad_length);
437+
438+
/**
439+
* @brief Decrypt message with precomputed shared key using ChaCha20-Poly1305-IETF (RFC7539).
440+
*
441+
* Decrypts encrypted of encrypted_length to plain of length
442+
* `encrypted_length - CRYPTO_MAC_SIZE` using a shared key @ref CRYPTO_SHARED_KEY_SIZE
443+
* big and a @ref CRYPTO_NOISE_NONCE_SIZE byte nonce.
444+
*
445+
* @retval -1 if there was a problem (decryption failed).
446+
* @return length of plain data if everything was fine.
447+
*/
448+
int32_t decrypt_data_symmetric_aead(const uint8_t shared_key[_Nonnull CRYPTO_SHARED_KEY_SIZE], const uint8_t nonce[_Nonnull CRYPTO_NOISE_NONCE_SIZE], const uint8_t *_Nonnull encrypted,
449+
size_t encrypted_length,
450+
uint8_t *_Nonnull plain, const uint8_t *_Nullable ad, size_t ad_length);
451+
452+
/**
453+
* @brief Encrypt message with precomputed shared key using XChaCha20-Poly1305.
454+
*
455+
* Encrypts plain of plain_length to encrypted of plain_length + @ref CRYPTO_MAC_SIZE
456+
* using a shared key @ref CRYPTO_SYMMETRIC_KEY_SIZE big and a @ref CRYPTO_NONCE_SIZE
457+
* byte nonce. The encrypted message, as well as a tag authenticating both the confidential
458+
* message m and adlen bytes of non-confidential data ad, are put into encrypted.
459+
*
460+
* @retval -1 if there was a problem.
461+
* @return length of encrypted data if everything was fine.
462+
*/
463+
int32_t encrypt_data_symmetric_xaead(const uint8_t shared_key[_Nonnull CRYPTO_SHARED_KEY_SIZE], const uint8_t nonce[_Nonnull CRYPTO_NONCE_SIZE], const uint8_t *_Nonnull plain, size_t plain_length,
464+
uint8_t *_Nonnull encrypted, const uint8_t *_Nullable ad, size_t ad_length);
465+
466+
/**
467+
* @brief Decrypt message with precomputed shared key using XChaCha20-Poly1305.
468+
*
469+
* Decrypts encrypted of encrypted_length to plain of length
470+
* `encrypted_length - CRYPTO_MAC_SIZE` using a shared key @ref CRYPTO_SHARED_KEY_SIZE
471+
* big and a @ref CRYPTO_NONCE_SIZE byte nonce.
472+
*
473+
* @retval -1 if there was a problem (decryption failed).
474+
* @return length of plain data if everything was fine.
475+
*/
476+
int32_t decrypt_data_symmetric_xaead(const uint8_t shared_key[_Nonnull CRYPTO_SHARED_KEY_SIZE], const uint8_t nonce[_Nonnull CRYPTO_NONCE_SIZE], const uint8_t *_Nonnull encrypted,
477+
size_t encrypted_length,
478+
uint8_t *_Nonnull plain, const uint8_t *_Nullable ad, size_t ad_length);
479+
480+
420481
#ifdef __cplusplus
421482
} /* extern "C" */
422483
#endif

0 commit comments

Comments
 (0)