From 71f45fedbca42a1d3e76fb5948f794d3ea73d21a Mon Sep 17 00:00:00 2001 From: Karel Miko Date: Sun, 3 May 2026 11:00:29 +0200 Subject: [PATCH] x25519/x448 - reject all-zero shared secrets --- src/pk/x25519/x25519_shared_secret.c | 7 +++++++ src/pk/x448/x448_shared_secret.c | 7 +++++++ tests/x25519_test.c | 25 +++++++++++++++++++++++++ tests/x448_test.c | 25 +++++++++++++++++++++++++ 4 files changed, 64 insertions(+) diff --git a/src/pk/x25519/x25519_shared_secret.c b/src/pk/x25519/x25519_shared_secret.c index d7e9ea8c..9261cbd5 100644 --- a/src/pk/x25519/x25519_shared_secret.c +++ b/src/pk/x25519/x25519_shared_secret.c @@ -21,6 +21,9 @@ int x25519_shared_secret(const curve25519_key *private_key, const curve25519_key *public_key, unsigned char *out, unsigned long *outlen) { + unsigned char nonzero = 0; + unsigned long x; + LTC_ARGCHK(private_key != NULL); LTC_ARGCHK(public_key != NULL); LTC_ARGCHK(out != NULL); @@ -37,6 +40,10 @@ int x25519_shared_secret(const curve25519_key *private_key, tweetnacl_crypto_scalarmult(out, private_key->priv, public_key->pub); *outlen = 32uL; + /* Reject all-zero shared secrets; RFC 7748 Section 6.1 says peers MAY check for this */ + for (x = 0; x < *outlen; ++x) nonzero |= out[x]; + if (nonzero == 0) return CRYPT_INVALID_PACKET; + return CRYPT_OK; } diff --git a/src/pk/x448/x448_shared_secret.c b/src/pk/x448/x448_shared_secret.c index f53d3e0f..f328d206 100644 --- a/src/pk/x448/x448_shared_secret.c +++ b/src/pk/x448/x448_shared_secret.c @@ -21,6 +21,9 @@ int x448_shared_secret(const curve448_key *private_key, const curve448_key *public_key, unsigned char *out, unsigned long *outlen) { + unsigned char nonzero = 0; + unsigned long x; + LTC_ARGCHK(private_key != NULL); LTC_ARGCHK(public_key != NULL); LTC_ARGCHK(out != NULL); @@ -37,6 +40,10 @@ int x448_shared_secret(const curve448_key *private_key, ec448_scalarmult_internal(out, private_key->priv, public_key->pub); *outlen = 56uL; + /* Reject all-zero shared secrets; RFC 7748 Section 6.2 says peers MAY check for this */ + for (x = 0; x < *outlen; ++x) nonzero |= out[x]; + if (nonzero == 0) return CRYPT_INVALID_PACKET; + return CRYPT_OK; } diff --git a/tests/x25519_test.c b/tests/x25519_test.c index f05a92b3..21728040 100644 --- a/tests/x25519_test.c +++ b/tests/x25519_test.c @@ -218,6 +218,30 @@ static int s_x25519_compat_test(void) return CRYPT_OK; } +static int s_x25519_zero_shared_secret_test(void) +{ + curve25519_key alice, bob, zero_pub; + unsigned char shared[32], zeros[32]; + unsigned long len; + int prng_idx = find_prng("yarrow"); + + zeromem(zeros, sizeof(zeros)); + + DO(x25519_make_key(&yarrow_prng, prng_idx, &alice)); + DO(x25519_make_key(&yarrow_prng, prng_idx, &bob)); + + len = sizeof(shared); + DO(x25519_shared_secret(&alice, &bob, shared, &len)); + ENSURE(len == sizeof(shared)); + + DO(x25519_import_raw(zeros, sizeof(zeros), PK_PUBLIC, &zero_pub)); + + len = sizeof(shared); + SHOULD_FAIL_WITH(x25519_shared_secret(&alice, &zero_pub, shared, &len), CRYPT_INVALID_PACKET); + + return CRYPT_OK; +} + /** Test the x25519 system @return CRYPT_OK if successful @@ -226,6 +250,7 @@ int x25519_test(void) { DO(s_rfc_7748_5_2_test()); DO(s_rfc_7748_6_test()); + DO(s_x25519_zero_shared_secret_test()); return CRYPT_OK; } diff --git a/tests/x448_test.c b/tests/x448_test.c index b2209995..55f3f2f0 100644 --- a/tests/x448_test.c +++ b/tests/x448_test.c @@ -227,12 +227,37 @@ static int s_x448_compat_test(void) return CRYPT_OK; } +static int s_x448_zero_shared_secret_test(void) +{ + curve448_key alice, bob, zero_pub; + unsigned char shared[56], zeros[56]; + unsigned long len; + int prng_idx = find_prng("yarrow"); + + zeromem(zeros, sizeof(zeros)); + + DO(x448_make_key(&yarrow_prng, prng_idx, &alice)); + DO(x448_make_key(&yarrow_prng, prng_idx, &bob)); + + len = sizeof(shared); + DO(x448_shared_secret(&alice, &bob, shared, &len)); + ENSURE(len == sizeof(shared)); + + DO(x448_import_raw(zeros, sizeof(zeros), PK_PUBLIC, &zero_pub)); + + len = sizeof(shared); + SHOULD_FAIL_WITH(x448_shared_secret(&alice, &zero_pub, shared, &len), CRYPT_INVALID_PACKET); + + return CRYPT_OK; +} + int x448_test(void) { DO(s_x448_rfc7748_scalarmult_test()); DO(s_x448_rfc7748_iter_test()); DO(s_x448_keygen_dh_test()); DO(s_x448_wycheproof_special_test()); + DO(s_x448_zero_shared_secret_test()); return CRYPT_OK; }