Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,8 @@ set(toxcore_SOURCES
toxcore/ccompat.h
toxcore/crypto_core.c
toxcore/crypto_core.h
toxcore/noise.c
toxcore/noise.h
toxcore/crypto_core_pack.c
toxcore/crypto_core_pack.h
toxcore/DHT.c
Expand Down Expand Up @@ -639,6 +641,7 @@ if(UNITTEST AND TARGET GTest::gtest AND TARGET GTest::gmock)
unit_test(toxcore mem)
unit_test(toxcore mono_time)
unit_test(toxcore net_crypto)
unit_test(toxcore noise)
unit_test(toxcore network)
unit_test(toxcore onion_client)
unit_test(toxcore ping_array)
Expand Down
2 changes: 1 addition & 1 deletion auto_tests/forwarding_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ static Forwarding_Subtox *new_forwarding_subtox(const Memory *mem, bool no_udp,
ck_assert(subtox->tcp_np != nullptr);

const TCP_Proxy_Info inf = {{{{0}}}};
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);
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);

subtox->forwarding = new_forwarding(subtox->log, mem, rng, subtox->mono_time, subtox->dht, subtox->net);
ck_assert(subtox->forwarding != nullptr);
Expand Down
2 changes: 1 addition & 1 deletion auto_tests/onion_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,7 @@ static Onions *new_onions(const Memory *mem, const Random *rng, uint16_t port, u
}

TCP_Proxy_Info inf = {{{{0}}}};
on->nc = new_net_crypto(on->log, mem, rng, ns, on->mono_time, net, dht, &auto_test_dht_funcs, &inf, on->tcp_np);
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);
on->onion_c = new_onion_client(on->log, mem, rng, on->mono_time, on->nc, dht, net);

if (!on->onion_c) {
Expand Down
2 changes: 1 addition & 1 deletion auto_tests/scenarios/scenario_toxav_peer_offline_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@

ToxScenarioStatus res = tox_scenario_run(s);
if (res != TOX_SCENARIO_DONE) {
fprintf(stderr, "Scenario failed with status %d\n", res);
fprintf(stderr, "Scenario failed with status %u\n", res);

Check warning on line 136 in auto_tests/scenarios/scenario_toxav_peer_offline_test.c

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

auto_tests/scenarios/scenario_toxav_peer_offline_test.c#L136

%u in format string (no. 1) requires 'unsigned int' but the argument type is 'ToxScenarioStatus {aka signed int}'.
return 1;
}

Expand Down
1 change: 1 addition & 0 deletions testing/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ sh_test(
args = ["$(locations %s)" % f for f in CIMPLE_FILES] + [
"-Wno-boolean-return",
"-Wno-callback-names",
"-Wno-callgraph",
"-Wno-enum-from-int",
"-Wno-nullability",
"-Wno-ownership-decls",
Expand Down
31 changes: 30 additions & 1 deletion toxcore/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,33 @@ cc_library(
],
)

cc_library(
name = "noise",
srcs = ["noise.c"],
hdrs = ["noise.h"],
visibility = ["//c-toxcore:__subpackages__"],
deps = [
":attributes",
":ccompat",
":crypto_core",
"@libsodium",
],
)

cc_test(
name = "noise_test",
size = "small",
srcs = ["noise_test.cc"],
deps = [
":crypto_core",
":crypto_core_test_util",
":noise",
"//c-toxcore/testing/support",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
],
)

cc_library(
name = "crypto_core_pack",
srcs = ["crypto_core_pack.c"],
Expand Down Expand Up @@ -375,6 +402,7 @@ cc_test(
deps = [
":crypto_core",
":crypto_core_test_util",
":noise",
":util",
"//c-toxcore/testing/support",
"@com_google_googletest//:gtest",
Expand Down Expand Up @@ -1030,6 +1058,7 @@ cc_library(
":net",
":net_profile",
":network",
":noise",
":rng",
":util",
"@pthread",
Expand All @@ -1038,7 +1067,7 @@ cc_library(

cc_test(
name = "net_crypto_test",
size = "small",
size = "medium",
srcs = ["net_crypto_test.cc"],
deps = [
":DHT_test_util",
Expand Down
2 changes: 2 additions & 0 deletions toxcore/Makefile.inc
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ libtoxcore_la_SOURCES = ../third_party/cmp/cmp.c \
../toxcore/crypto_core_pack.h \
../toxcore/crypto_core.c \
../toxcore/crypto_core.h \
../toxcore/noise.c \
../toxcore/noise.h \
../toxcore/DHT.c \
../toxcore/DHT.h \
../toxcore/ev.c \
Expand Down
2 changes: 1 addition & 1 deletion toxcore/Messenger.c
Original file line number Diff line number Diff line change
Expand Up @@ -3470,7 +3470,7 @@ Messenger *new_messenger(Mono_Time *mono_time, const Memory *mem, const Random *
}
m->tcp_np = tcp_np;

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);
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);

if (net_crypto == nullptr) {
LOGGER_WARNING(m->log, "net_crypto initialisation failed");
Expand Down
1 change: 1 addition & 0 deletions toxcore/Messenger.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
Logger *_Nonnull log;

bool ipv6enabled;
Crypto_Handshake_Mode handshake_mode;

Check warning on line 80 in toxcore/Messenger.h

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

toxcore/Messenger.h#L80

struct member 'Messenger_Options::handshake_mode' is never used.
bool udp_disabled;
TCP_Proxy_Info proxy_info;
uint16_t port_range[2];
Expand Down
110 changes: 100 additions & 10 deletions toxcore/crypto_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ static_assert(CRYPTO_MAC_SIZE == crypto_box_MACBYTES,
"CRYPTO_MAC_SIZE should be equal to crypto_box_MACBYTES");
static_assert(CRYPTO_NONCE_SIZE == crypto_box_NONCEBYTES,
"CRYPTO_NONCE_SIZE should be equal to crypto_box_NONCEBYTES");
static_assert(CRYPTO_NOISE_NONCE_SIZE == crypto_stream_chacha20_ietf_NONCEBYTES,
"CRYPTO_NOISE_NONCE_SIZE should be equal to crypto_stream_chacha20_ietf_NONCEBYTES");
static_assert(CRYPTO_HMAC_SIZE == crypto_auth_BYTES,
"CRYPTO_HMAC_SIZE should be equal to crypto_auth_BYTES");
static_assert(CRYPTO_HMAC_KEY_SIZE == crypto_auth_KEYBYTES,
Expand All @@ -46,6 +48,12 @@ static_assert(CRYPTO_SIGN_PUBLIC_KEY_SIZE == crypto_sign_PUBLICKEYBYTES,
static_assert(CRYPTO_SIGN_SECRET_KEY_SIZE == crypto_sign_SECRETKEYBYTES,
"CRYPTO_SIGN_SECRET_KEY_SIZE should be equal to crypto_sign_SECRETKEYBYTES");


static_assert(CRYPTO_MAC_SIZE == crypto_aead_chacha20poly1305_IETF_ABYTES,
"CRYPTO_MAC_SIZE should be equal to crypto_aead_chacha20poly1305_IETF_ABYTES");
static_assert(CRYPTO_SHARED_KEY_SIZE == CRYPTO_SYMMETRIC_KEY_SIZE,
"CRYPTO_SHARED_KEY_SIZE should be equal to CRYPTO_SYMMETRIC_KEY_SIZE");

bool create_extended_keypair(Extended_Public_Key *pk, Extended_Secret_Key *sk, const Random *rng)
{
/* create signature key pair */
Expand Down Expand Up @@ -235,7 +243,7 @@ int32_t encrypt_data_symmetric(const Memory *mem,
const uint8_t nonce[CRYPTO_NONCE_SIZE],
const uint8_t *plain, size_t length, uint8_t *encrypted)
{
if (length == 0 || shared_key == nullptr || nonce == nullptr || plain == nullptr || encrypted == nullptr) {
if (length == 0 || length >= INT32_MAX - crypto_box_MACBYTES || shared_key == nullptr || nonce == nullptr || plain == nullptr || encrypted == nullptr) {
return -1;
}

Expand Down Expand Up @@ -280,7 +288,6 @@ int32_t encrypt_data_symmetric(const Memory *mem,
crypto_free(mem, temp_plain, size_temp_plain);
crypto_free(mem, temp_encrypted, size_temp_encrypted);
#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
assert(length < INT32_MAX - crypto_box_MACBYTES);
return (int32_t)(length + crypto_box_MACBYTES);
}

Expand All @@ -289,13 +296,12 @@ int32_t decrypt_data_symmetric(const Memory *mem,
const uint8_t nonce[CRYPTO_NONCE_SIZE],
const uint8_t *encrypted, size_t length, uint8_t *plain)
{
if (length <= crypto_box_BOXZEROBYTES || shared_key == nullptr || nonce == nullptr || encrypted == nullptr
if (length <= crypto_box_BOXZEROBYTES || length >= INT32_MAX || shared_key == nullptr || nonce == nullptr || encrypted == nullptr
|| plain == nullptr) {
return -1;
}

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

Expand Down Expand Up @@ -332,8 +338,6 @@ int32_t decrypt_data_symmetric(const Memory *mem,
crypto_free(mem, temp_plain, size_temp_plain);
crypto_free(mem, temp_encrypted, size_temp_encrypted);
#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
assert(length > crypto_box_MACBYTES);
assert(length < INT32_MAX);
return (int32_t)(length - crypto_box_MACBYTES);
}

Expand Down Expand Up @@ -373,10 +377,7 @@ int32_t decrypt_data(const Memory *mem,

void increment_nonce(uint8_t nonce[CRYPTO_NONCE_SIZE])
{
/* TODO(irungentoo): use `increment_nonce_number(nonce, 1)` or
* sodium_increment (change to little endian).
*
* NOTE don't use breaks inside this loop.
/* NOTE don't use breaks inside this loop.
* In particular, make sure, as far as possible,
* that loop bounds and their potential underflow or overflow
* are independent of user-controlled input (you may have heard of the Heartbleed bug).
Expand Down Expand Up @@ -488,3 +489,92 @@ void random_bytes(const Random *rng, uint8_t *bytes, size_t length)
{
rng_bytes(rng, bytes, length);
}

// Necessary functions for Noise, cf. https://noiseprotocol.org/noise.html (Revision 34)

int32_t encrypt_data_symmetric_aead(const uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE], const uint8_t nonce[CRYPTO_NOISE_NONCE_SIZE],
const uint8_t *plain, size_t plain_length, uint8_t *encrypted,
const uint8_t *ad, size_t ad_length)
{
if (plain_length == 0 || plain_length >= INT32_MAX - crypto_aead_chacha20poly1305_IETF_ABYTES
|| shared_key == nullptr || nonce == nullptr || plain == nullptr || encrypted == nullptr) {
return -1;
}

#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
memcpy(encrypted, plain, plain_length);
memzero(encrypted + plain_length, crypto_aead_chacha20poly1305_IETF_ABYTES);
#else
if (crypto_aead_chacha20poly1305_ietf_encrypt(encrypted, nullptr, plain, plain_length,
ad, ad_length, nullptr, nonce, shared_key) != 0) {
return -1;
}
#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */

return (int32_t)(plain_length + crypto_aead_chacha20poly1305_IETF_ABYTES);
}

int32_t decrypt_data_symmetric_aead(const uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE], const uint8_t nonce[CRYPTO_NOISE_NONCE_SIZE],
const uint8_t *encrypted, size_t encrypted_length, uint8_t *plain,
const uint8_t *ad, size_t ad_length)
{
if (encrypted_length <= crypto_aead_chacha20poly1305_IETF_ABYTES || encrypted_length >= INT32_MAX
|| shared_key == nullptr || nonce == nullptr || encrypted == nullptr || plain == nullptr) {
return -1;
}

#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
memcpy(plain, encrypted, encrypted_length - crypto_aead_chacha20poly1305_IETF_ABYTES);
#else
if (crypto_aead_chacha20poly1305_ietf_decrypt(plain, nullptr, nullptr, encrypted,
encrypted_length, ad, ad_length, nonce, shared_key) != 0) {
return -1;
}
#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */

return (int32_t)(encrypted_length - crypto_aead_chacha20poly1305_IETF_ABYTES);
}

int32_t encrypt_data_symmetric_xaead(const uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE], const uint8_t nonce[CRYPTO_NONCE_SIZE],
const uint8_t *plain, size_t plain_length, uint8_t *encrypted,
const uint8_t *ad, size_t ad_length)
{
if (plain_length == 0 || plain_length >= INT32_MAX - crypto_aead_xchacha20poly1305_ietf_ABYTES
|| shared_key == nullptr || nonce == nullptr || plain == nullptr || encrypted == nullptr) {
return -1;
}

#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
memcpy(encrypted, plain, plain_length);
memzero(encrypted + plain_length, crypto_aead_xchacha20poly1305_ietf_ABYTES);
#else
if (crypto_aead_xchacha20poly1305_ietf_encrypt(encrypted, nullptr, plain, plain_length,
ad, ad_length, nullptr, nonce, shared_key) != 0) {
return -1;
}
#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */

return (int32_t)(plain_length + crypto_aead_xchacha20poly1305_ietf_ABYTES);
}

int32_t decrypt_data_symmetric_xaead(const uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE], const uint8_t nonce[CRYPTO_NONCE_SIZE],
const uint8_t *encrypted, size_t encrypted_length, uint8_t *plain,
const uint8_t *ad, size_t ad_length)
{
if (encrypted_length <= crypto_aead_xchacha20poly1305_ietf_ABYTES || encrypted_length >= INT32_MAX
|| shared_key == nullptr || nonce == nullptr || encrypted == nullptr || plain == nullptr) {
return -1;
}

#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
memcpy(plain, encrypted, encrypted_length - crypto_aead_xchacha20poly1305_ietf_ABYTES);
#else
if (crypto_aead_xchacha20poly1305_ietf_decrypt(plain, nullptr, nullptr, encrypted,
encrypted_length, ad, ad_length, nonce, shared_key) != 0) {
return -1;
}
#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */

return (int32_t)(encrypted_length - crypto_aead_xchacha20poly1305_ietf_ABYTES);
}

67 changes: 64 additions & 3 deletions toxcore/crypto_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ extern "C" {
*/
#define CRYPTO_NONCE_SIZE 24

/**
* @brief NoiseIK: The number of bytes in a nonce used for encryption/decryption (ChaChaPoly1305-IETF).
*/
#define CRYPTO_NOISE_NONCE_SIZE 12

/**
* @brief The number of bytes in a SHA256 hash.
*/
Expand All @@ -79,6 +84,7 @@ extern "C" {
*/
#define CRYPTO_SHA512_SIZE 64


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

/**
* @brief Encrypt message with precomputed shared key using ChaCha20-Poly1305-IETF (RFC7539).
*
* Encrypts plain of plain_length to encrypted of plain_length + @ref CRYPTO_MAC_SIZE
* using a shared key @ref CRYPTO_SHARED_KEY_SIZE big and a @ref CRYPTO_NOISE_NONCE_SIZE
* byte nonce. The encrypted message, as well as a tag authenticating both the confidential
* message m and adlen bytes of non-confidential data ad, are put into encrypted.
*
* @retval -1 if there was a problem.
* @return length of encrypted data if everything was fine.
*/
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,
size_t plain_length,
uint8_t encrypted[_Nonnull /*! plain_length + CRYPTO_MAC_SIZE */], const uint8_t *_Nullable ad, size_t ad_length);

/**
* @brief Decrypt message with precomputed shared key using ChaCha20-Poly1305-IETF (RFC7539).
*
* Decrypts encrypted of encrypted_length to plain of length
* `encrypted_length - CRYPTO_MAC_SIZE` using a shared key @ref CRYPTO_SHARED_KEY_SIZE
* big and a @ref CRYPTO_NOISE_NONCE_SIZE byte nonce.
*
* @retval -1 if there was a problem (decryption failed).
* @return length of plain data if everything was fine.
*/
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,
size_t encrypted_length,
uint8_t *_Nonnull plain, const uint8_t *_Nullable ad, size_t ad_length);

/**
* @brief Encrypt message with precomputed shared key using XChaCha20-Poly1305.
*
* Encrypts plain of plain_length to encrypted of plain_length + @ref CRYPTO_MAC_SIZE
* using a shared key @ref CRYPTO_SYMMETRIC_KEY_SIZE big and a @ref CRYPTO_NONCE_SIZE
* byte nonce. The encrypted message, as well as a tag authenticating both the confidential
* message m and adlen bytes of non-confidential data ad, are put into encrypted.
*
* @retval -1 if there was a problem.
* @return length of encrypted data if everything was fine.
*/
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,
uint8_t *_Nonnull encrypted, const uint8_t *_Nullable ad, size_t ad_length);

/**
* @brief Decrypt message with precomputed shared key using XChaCha20-Poly1305.
*
* Decrypts encrypted of encrypted_length to plain of length
* `encrypted_length - CRYPTO_MAC_SIZE` using a shared key @ref CRYPTO_SHARED_KEY_SIZE
* big and a @ref CRYPTO_NONCE_SIZE byte nonce.
*
* @retval -1 if there was a problem (decryption failed).
* @return length of plain data if everything was fine.
*/
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,
size_t encrypted_length,
uint8_t *_Nonnull plain, const uint8_t *_Nullable ad, size_t ad_length);


#ifdef __cplusplus
} /* extern "C" */
#endif
Expand Down
Loading
Loading