From ac5f4a1378f04369cf2f7ff78d893f34c0ffcb25 Mon Sep 17 00:00:00 2001 From: gcr Date: Wed, 31 Jul 2024 17:53:58 +0000 Subject: [PATCH] Add support for hybrid-PQ key exchange with x25519 This adds support for hybrid-PQ key exchanges with x25519. This allows for the implementation of `mlkem768x25519-sha256` as defined by [draft-kampanakis-curdle-ssh-pq-ke-02](https://datatracker.ietf.org/doc/draft-kampanakis-curdle-ssh-pq-ke/) and `sntrup761x25519-sha512@openssh.com` as defined by upstream OpenSSH. We also take the opportunity to add hybrid implementations for all existing PQ key exchanges which supported NIST P-256. Due to the conflicting implementation for `sntrup761x25519-sha512@openssh.com` we omit an OQS exclusive version for now and will plan for it in a future PR. Unlike in `oqs-provider`, we cannot provide support for x448 hybrid algorithms since the x448 algorithm is not available within OpenSSH. The way this all works is by introducing a new source file `kexoqsx25519.c` which is a synthesis of `kexoqsecdh.c` and `kexsntrup761x25519.c`. These files provide example implementations of hybrid-PQ for OQS-backed algorithms and x25519 usage. In that source file, we define functions to implement OpenSSH's KEX interface for each hybrid algorithm using an `oqs-template` file. Within the `generate.yml`, we add a new boolean key to flag `x25519` hybrids similar to how the `rsa` key works for hybrid signatures. Related to issue #163. Signed-off-by: Gerardo Ravago --- Makefile.in | 2 +- README.md | 12 +- kex.c | 9 + kex.h | 54 ++ kexgen.c | 90 +++ kexoqsx25519.c | 583 ++++++++++++++++++ monitor.c | 9 + myproposal.h | 9 + oqs-template/generate.py | 1 + oqs-template/generate.yml | 36 ++ oqs-template/kex.c/add_kex_algs.fragment | 5 +- oqs-template/kex.h/add_kex_enums.fragment | 5 +- .../kex.h/declare_kex_prototypes.fragment | 8 +- .../kex.h/define_kex_pretty_names.fragment | 5 +- .../kexgen.c/add_client_switch_cases.fragment | 7 +- .../kexgen.c/add_init_switch_cases.fragment | 8 +- .../kexgen.c/add_reply_switch_cases.fragment | 7 +- .../define_kex_with_ec_methods.fragment | 2 +- .../define_kex_with_x25519_methods.fragment | 46 ++ .../monitor.c/apply_keystate.fragment | 5 +- .../assign_kex_gen_client.fragment | 5 +- .../point_to_kex_gen_client.fragment | 5 +- .../point_to_kex_gen_server.fragment | 5 +- .../sshconnect2.c/point_to_kex_gen.fragment | 5 +- oqs-template/sshd.c/point_to_kex_gen.fragment | 5 +- oqs-test/try_connection.py | 9 + ssh-keyscan.c | 9 + ssh_api.c | 18 + sshconnect2.c | 9 + sshd.c | 9 + 30 files changed, 961 insertions(+), 21 deletions(-) create mode 100644 kexoqsx25519.c create mode 100644 oqs-template/kexoqsx25519.c/define_kex_with_x25519_methods.fragment diff --git a/Makefile.in b/Makefile.in index 60a3d22657c4..f63d9f8c9675 100644 --- a/Makefile.in +++ b/Makefile.in @@ -111,7 +111,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ hmac.o ed25519.o hash.o \ kex.o kexdh.o kexgex.o kexecdh.o kexc25519.o \ kexgexc.o kexgexs.o \ - kexoqs.o kexoqsecdh.o \ + kexoqs.o kexoqsecdh.o kexoqsx25519.o \ kexsntrup761x25519.o sntrup761.o kexgen.o \ sftp-realpath.o platform-pledge.o platform-tracing.o platform-misc.o \ sshbuf-io.o diff --git a/README.md b/README.md index baeefab63936..310e11bfe642 100644 --- a/README.md +++ b/README.md @@ -76,12 +76,12 @@ The following quantum-safe algorithms from liboqs are supported (assuming they h The following hybrid algorithms are made available: -- **BIKE**: `ecdh-nistp256-bike-l1r4-sha512@openquantumsafe.org` `ecdh-nistp384-bike-l3r4-sha512@openquantumsafe.org` `ecdh-nistp521-bike-l5r4-sha512@openquantumsafe.org` -- **ClassicMcEliece**: `ecdh-nistp256-classic-mceliece-348864r4-sha256@openquantumsafe.org` `ecdh-nistp256-classic-mceliece-348864fr4-sha256@openquantumsafe.org` `ecdh-nistp384-classic-mceliece-460896r4-sha512@openquantumsafe.org` `ecdh-nistp384-classic-mceliece-460896fr4-sha512@openquantumsafe.org` `ecdh-nistp521-classic-mceliece-6688128r4-sha512@openquantumsafe.org` `ecdh-nistp521-classic-mceliece-6688128fr4-sha512@openquantumsafe.org` `ecdh-nistp521-classic-mceliece-6960119r4-sha512@openquantumsafe.org` `ecdh-nistp521-classic-mceliece-6960119fr4-sha512@openquantumsafe.org` `ecdh-nistp521-classic-mceliece-8192128r4-sha512@openquantumsafe.org` `ecdh-nistp521-classic-mceliece-8192128fr4-sha512@openquantumsafe.org` -- **FrodoKEM**: `ecdh-nistp256-frodokem-640-aesr2-sha256@openquantumsafe.org` `ecdh-nistp384-frodokem-976-aesr2-sha384@openquantumsafe.org` `ecdh-nistp521-frodokem-1344-aesr2-sha512@openquantumsafe.org` `ecdh-nistp256-frodokem-640-shaker2-sha256@openquantumsafe.org` `ecdh-nistp384-frodokem-976-shaker2-sha384@openquantumsafe.org` `ecdh-nistp521-frodokem-1344-shaker2-sha512@openquantumsafe.org` -- **HQC**: `ecdh-nistp256-hqc-128r3-sha256@openquantumsafe.org` `ecdh-nistp384-hqc-192r3-sha384@openquantumsafe.org` `ecdh-nistp521-hqc-256r3-sha512@openquantumsafe.org` -- **Kyber**: `ecdh-nistp256-kyber-512r3-sha256-d00@openquantumsafe.org` `ecdh-nistp384-kyber-768r3-sha384-d00@openquantumsafe.org` `ecdh-nistp521-kyber-1024r3-sha512-d00@openquantumsafe.org` -- **ML-KEM**: `ecdh-nistp256-ml-kem-512-sha256@openquantumsafe.org` `mlkem768nistp256-sha256` `mlkem1024nistp384-sha384` +- **BIKE**: `ecdh-nistp256-bike-l1r4-sha512@openquantumsafe.org` `x25519-bike-l1r4-sha512@openquantumsafe.org` `ecdh-nistp384-bike-l3r4-sha512@openquantumsafe.org` `ecdh-nistp521-bike-l5r4-sha512@openquantumsafe.org` +- **ClassicMcEliece**: `ecdh-nistp256-classic-mceliece-348864r4-sha256@openquantumsafe.org` `x25519-classic-mceliece-348864r4-sha256@openquantumsafe.org` `ecdh-nistp256-classic-mceliece-348864fr4-sha256@openquantumsafe.org` `x25519-classic-mceliece-348864fr4-sha256@openquantumsafe.org` `ecdh-nistp384-classic-mceliece-460896r4-sha512@openquantumsafe.org` `ecdh-nistp384-classic-mceliece-460896fr4-sha512@openquantumsafe.org` `ecdh-nistp521-classic-mceliece-6688128r4-sha512@openquantumsafe.org` `ecdh-nistp521-classic-mceliece-6688128fr4-sha512@openquantumsafe.org` `ecdh-nistp521-classic-mceliece-6960119r4-sha512@openquantumsafe.org` `ecdh-nistp521-classic-mceliece-6960119fr4-sha512@openquantumsafe.org` `ecdh-nistp521-classic-mceliece-8192128r4-sha512@openquantumsafe.org` `ecdh-nistp521-classic-mceliece-8192128fr4-sha512@openquantumsafe.org` +- **FrodoKEM**: `ecdh-nistp256-frodokem-640-aesr2-sha256@openquantumsafe.org` `x25519-frodokem-640-aesr2-sha256@openquantumsafe.org` `ecdh-nistp384-frodokem-976-aesr2-sha384@openquantumsafe.org` `ecdh-nistp521-frodokem-1344-aesr2-sha512@openquantumsafe.org` `ecdh-nistp256-frodokem-640-shaker2-sha256@openquantumsafe.org` `x25519-frodokem-640-shaker2-sha256@openquantumsafe.org` `ecdh-nistp384-frodokem-976-shaker2-sha384@openquantumsafe.org` `ecdh-nistp521-frodokem-1344-shaker2-sha512@openquantumsafe.org` +- **HQC**: `ecdh-nistp256-hqc-128r3-sha256@openquantumsafe.org` `x25519-hqc-128r3-sha256@openquantumsafe.org` `ecdh-nistp384-hqc-192r3-sha384@openquantumsafe.org` `ecdh-nistp521-hqc-256r3-sha512@openquantumsafe.org` +- **Kyber**: `ecdh-nistp256-kyber-512r3-sha256-d00@openquantumsafe.org` `x25519-kyber-512r3-sha256-d00@amazon.com` `ecdh-nistp384-kyber-768r3-sha384-d00@openquantumsafe.org` `ecdh-nistp521-kyber-1024r3-sha512-d00@openquantumsafe.org` +- **ML-KEM**: `ecdh-nistp256-ml-kem-512-sha256@openquantumsafe.org` `x25519-ml-kem-512-sha256@openquantumsafe.org` `mlkem768nistp256-sha256` `mlkem768x25519-sha256` `mlkem1024nistp384-sha384` Note that algorithms marked with a dagger (†) have large stack usage and may cause failures when run on threads or in constrained environments. For example, McEliece require building `oqs-openssh` with a large(r) stack provision than is default: Adding `LDFLAGS="-Wl,--stack,20000000"` to [the `./configure` command below](#step-2-build-the-fork) is required to allow cygwin-based testing to pass. diff --git a/kex.c b/kex.c index a64e60493f8d..4440bd8f5d94 100644 --- a/kex.c +++ b/kex.c @@ -121,19 +121,25 @@ static const struct kexalg kexalgs[] = { ///// OQS_TEMPLATE_FRAGMENT_ADD_KEX_ALGS_START { KEX_FRODOKEM_640_AES_SHA256, KEX_KEM_FRODOKEM_640_AES_SHA256, 0, SSH_DIGEST_SHA256 }, + { KEX_FRODOKEM_640_AES_X25519_SHA256, KEX_KEM_FRODOKEM_640_AES_X25519_SHA256, 0, SSH_DIGEST_SHA256 }, { KEX_FRODOKEM_976_AES_SHA384, KEX_KEM_FRODOKEM_976_AES_SHA384, 0, SSH_DIGEST_SHA384 }, { KEX_FRODOKEM_1344_AES_SHA512, KEX_KEM_FRODOKEM_1344_AES_SHA512, 0, SSH_DIGEST_SHA512 }, { KEX_FRODOKEM_640_SHAKE_SHA256, KEX_KEM_FRODOKEM_640_SHAKE_SHA256, 0, SSH_DIGEST_SHA256 }, + { KEX_FRODOKEM_640_SHAKE_X25519_SHA256, KEX_KEM_FRODOKEM_640_SHAKE_X25519_SHA256, 0, SSH_DIGEST_SHA256 }, { KEX_FRODOKEM_976_SHAKE_SHA384, KEX_KEM_FRODOKEM_976_SHAKE_SHA384, 0, SSH_DIGEST_SHA384 }, { KEX_FRODOKEM_1344_SHAKE_SHA512, KEX_KEM_FRODOKEM_1344_SHAKE_SHA512, 0, SSH_DIGEST_SHA512 }, { KEX_KYBER_512_SHA256, KEX_KEM_KYBER_512_SHA256, 0, SSH_DIGEST_SHA256 }, + { KEX_KYBER_512_X25519_SHA256, KEX_KEM_KYBER_512_X25519_SHA256, 0, SSH_DIGEST_SHA256 }, { KEX_KYBER_768_SHA384, KEX_KEM_KYBER_768_SHA384, 0, SSH_DIGEST_SHA384 }, { KEX_KYBER_1024_SHA512, KEX_KEM_KYBER_1024_SHA512, 0, SSH_DIGEST_SHA512 }, { KEX_BIKE_L1_SHA512, KEX_KEM_BIKE_L1_SHA512, 0, SSH_DIGEST_SHA512 }, + { KEX_BIKE_L1_X25519_SHA512, KEX_KEM_BIKE_L1_X25519_SHA512, 0, SSH_DIGEST_SHA512 }, { KEX_BIKE_L3_SHA512, KEX_KEM_BIKE_L3_SHA512, 0, SSH_DIGEST_SHA512 }, { KEX_BIKE_L5_SHA512, KEX_KEM_BIKE_L5_SHA512, 0, SSH_DIGEST_SHA512 }, { KEX_CLASSIC_MCELIECE_348864_SHA256, KEX_KEM_CLASSIC_MCELIECE_348864_SHA256, 0, SSH_DIGEST_SHA256 }, + { KEX_CLASSIC_MCELIECE_348864_X25519_SHA256, KEX_KEM_CLASSIC_MCELIECE_348864_X25519_SHA256, 0, SSH_DIGEST_SHA256 }, { KEX_CLASSIC_MCELIECE_348864F_SHA256, KEX_KEM_CLASSIC_MCELIECE_348864F_SHA256, 0, SSH_DIGEST_SHA256 }, + { KEX_CLASSIC_MCELIECE_348864F_X25519_SHA256, KEX_KEM_CLASSIC_MCELIECE_348864F_X25519_SHA256, 0, SSH_DIGEST_SHA256 }, { KEX_CLASSIC_MCELIECE_460896_SHA512, KEX_KEM_CLASSIC_MCELIECE_460896_SHA512, 0, SSH_DIGEST_SHA512 }, { KEX_CLASSIC_MCELIECE_460896F_SHA512, KEX_KEM_CLASSIC_MCELIECE_460896F_SHA512, 0, SSH_DIGEST_SHA512 }, { KEX_CLASSIC_MCELIECE_6688128_SHA512, KEX_KEM_CLASSIC_MCELIECE_6688128_SHA512, 0, SSH_DIGEST_SHA512 }, @@ -143,10 +149,13 @@ static const struct kexalg kexalgs[] = { { KEX_CLASSIC_MCELIECE_8192128_SHA512, KEX_KEM_CLASSIC_MCELIECE_8192128_SHA512, 0, SSH_DIGEST_SHA512 }, { KEX_CLASSIC_MCELIECE_8192128F_SHA512, KEX_KEM_CLASSIC_MCELIECE_8192128F_SHA512, 0, SSH_DIGEST_SHA512 }, { KEX_HQC_128_SHA256, KEX_KEM_HQC_128_SHA256, 0, SSH_DIGEST_SHA256 }, + { KEX_HQC_128_X25519_SHA256, KEX_KEM_HQC_128_X25519_SHA256, 0, SSH_DIGEST_SHA256 }, { KEX_HQC_192_SHA384, KEX_KEM_HQC_192_SHA384, 0, SSH_DIGEST_SHA384 }, { KEX_HQC_256_SHA512, KEX_KEM_HQC_256_SHA512, 0, SSH_DIGEST_SHA512 }, { KEX_ML_KEM_512_SHA256, KEX_KEM_ML_KEM_512_SHA256, 0, SSH_DIGEST_SHA256 }, + { KEX_ML_KEM_512_X25519_SHA256, KEX_KEM_ML_KEM_512_X25519_SHA256, 0, SSH_DIGEST_SHA256 }, { KEX_ML_KEM_768_SHA256, KEX_KEM_ML_KEM_768_SHA256, 0, SSH_DIGEST_SHA256 }, + { KEX_ML_KEM_768_X25519_SHA256, KEX_KEM_ML_KEM_768_X25519_SHA256, 0, SSH_DIGEST_SHA256 }, { KEX_ML_KEM_1024_SHA384, KEX_KEM_ML_KEM_1024_SHA384, 0, SSH_DIGEST_SHA384 }, #ifdef OPENSSL_HAS_ECC { KEX_FRODOKEM_640_AES_ECDH_NISTP256_SHA256, KEX_KEM_FRODOKEM_640_AES_ECDH_NISTP256_SHA256, NID_X9_62_prime256v1, SSH_DIGEST_SHA256 }, diff --git a/kex.h b/kex.h index 0c4155a061fa..a752dc488012 100644 --- a/kex.h +++ b/kex.h @@ -66,19 +66,25 @@ #define KEX_SNTRUP761X25519_SHA512 "sntrup761x25519-sha512@openssh.com" ///// OQS_TEMPLATE_FRAGMENT_DEFINE_KEX_PRETTY_NAMES_START #define KEX_FRODOKEM_640_AES_SHA256 "frodokem-640-aes-sha256" +#define KEX_FRODOKEM_640_AES_X25519_SHA256 "x25519-frodokem-640-aesr2-sha256@openquantumsafe.org" #define KEX_FRODOKEM_976_AES_SHA384 "frodokem-976-aes-sha384" #define KEX_FRODOKEM_1344_AES_SHA512 "frodokem-1344-aes-sha512" #define KEX_FRODOKEM_640_SHAKE_SHA256 "frodokem-640-shake-sha256" +#define KEX_FRODOKEM_640_SHAKE_X25519_SHA256 "x25519-frodokem-640-shaker2-sha256@openquantumsafe.org" #define KEX_FRODOKEM_976_SHAKE_SHA384 "frodokem-976-shake-sha384" #define KEX_FRODOKEM_1344_SHAKE_SHA512 "frodokem-1344-shake-sha512" #define KEX_KYBER_512_SHA256 "kyber-512-sha256" +#define KEX_KYBER_512_X25519_SHA256 "x25519-kyber-512r3-sha256-d00@amazon.com" #define KEX_KYBER_768_SHA384 "kyber-768-sha384" #define KEX_KYBER_1024_SHA512 "kyber-1024-sha512" #define KEX_BIKE_L1_SHA512 "bike-l1-sha512" +#define KEX_BIKE_L1_X25519_SHA512 "x25519-bike-l1r4-sha512@openquantumsafe.org" #define KEX_BIKE_L3_SHA512 "bike-l3-sha512" #define KEX_BIKE_L5_SHA512 "bike-l5-sha512" #define KEX_CLASSIC_MCELIECE_348864_SHA256 "classic-mceliece-348864-sha256" +#define KEX_CLASSIC_MCELIECE_348864_X25519_SHA256 "x25519-classic-mceliece-348864r4-sha256@openquantumsafe.org" #define KEX_CLASSIC_MCELIECE_348864F_SHA256 "classic-mceliece-348864f-sha256" +#define KEX_CLASSIC_MCELIECE_348864F_X25519_SHA256 "x25519-classic-mceliece-348864fr4-sha256@openquantumsafe.org" #define KEX_CLASSIC_MCELIECE_460896_SHA512 "classic-mceliece-460896-sha512" #define KEX_CLASSIC_MCELIECE_460896F_SHA512 "classic-mceliece-460896f-sha512" #define KEX_CLASSIC_MCELIECE_6688128_SHA512 "classic-mceliece-6688128-sha512" @@ -88,10 +94,13 @@ #define KEX_CLASSIC_MCELIECE_8192128_SHA512 "classic-mceliece-8192128-sha512" #define KEX_CLASSIC_MCELIECE_8192128F_SHA512 "classic-mceliece-8192128f-sha512" #define KEX_HQC_128_SHA256 "hqc-128-sha256" +#define KEX_HQC_128_X25519_SHA256 "x25519-hqc-128r3-sha256@openquantumsafe.org" #define KEX_HQC_192_SHA384 "hqc-192-sha384" #define KEX_HQC_256_SHA512 "hqc-256-sha512" #define KEX_ML_KEM_512_SHA256 "ml-kem-512-sha256" +#define KEX_ML_KEM_512_X25519_SHA256 "x25519-ml-kem-512-sha256@openquantumsafe.org" #define KEX_ML_KEM_768_SHA256 "ml-kem-768-sha256" +#define KEX_ML_KEM_768_X25519_SHA256 "mlkem768x25519-sha256" #define KEX_ML_KEM_1024_SHA384 "ml-kem-1024-sha384" #ifdef WITH_OPENSSL #ifdef OPENSSL_HAS_ECC @@ -167,19 +176,25 @@ enum kex_exchange { KEX_KEM_SNTRUP761X25519_SHA512, ///// OQS_TEMPLATE_FRAGMENT_ADD_KEX_ENUMS_START KEX_KEM_FRODOKEM_640_AES_SHA256, + KEX_KEM_FRODOKEM_640_AES_X25519_SHA256, KEX_KEM_FRODOKEM_976_AES_SHA384, KEX_KEM_FRODOKEM_1344_AES_SHA512, KEX_KEM_FRODOKEM_640_SHAKE_SHA256, + KEX_KEM_FRODOKEM_640_SHAKE_X25519_SHA256, KEX_KEM_FRODOKEM_976_SHAKE_SHA384, KEX_KEM_FRODOKEM_1344_SHAKE_SHA512, KEX_KEM_KYBER_512_SHA256, + KEX_KEM_KYBER_512_X25519_SHA256, KEX_KEM_KYBER_768_SHA384, KEX_KEM_KYBER_1024_SHA512, KEX_KEM_BIKE_L1_SHA512, + KEX_KEM_BIKE_L1_X25519_SHA512, KEX_KEM_BIKE_L3_SHA512, KEX_KEM_BIKE_L5_SHA512, KEX_KEM_CLASSIC_MCELIECE_348864_SHA256, + KEX_KEM_CLASSIC_MCELIECE_348864_X25519_SHA256, KEX_KEM_CLASSIC_MCELIECE_348864F_SHA256, + KEX_KEM_CLASSIC_MCELIECE_348864F_X25519_SHA256, KEX_KEM_CLASSIC_MCELIECE_460896_SHA512, KEX_KEM_CLASSIC_MCELIECE_460896F_SHA512, KEX_KEM_CLASSIC_MCELIECE_6688128_SHA512, @@ -189,10 +204,13 @@ enum kex_exchange { KEX_KEM_CLASSIC_MCELIECE_8192128_SHA512, KEX_KEM_CLASSIC_MCELIECE_8192128F_SHA512, KEX_KEM_HQC_128_SHA256, + KEX_KEM_HQC_128_X25519_SHA256, KEX_KEM_HQC_192_SHA384, KEX_KEM_HQC_256_SHA512, KEX_KEM_ML_KEM_512_SHA256, + KEX_KEM_ML_KEM_512_X25519_SHA256, KEX_KEM_ML_KEM_768_SHA256, + KEX_KEM_ML_KEM_768_X25519_SHA256, KEX_KEM_ML_KEM_1024_SHA384, #ifdef WITH_OPENSSL #ifdef OPENSSL_HAS_ECC @@ -373,6 +391,10 @@ int kex_kem_sntrup761x25519_dec(struct kex *, const struct sshbuf *, int kex_kem_frodokem_640_aes_keypair(struct kex *); int kex_kem_frodokem_640_aes_enc(struct kex *, const struct sshbuf *, struct sshbuf **, struct sshbuf **); int kex_kem_frodokem_640_aes_dec(struct kex *, const struct sshbuf *, struct sshbuf **); +/* frodokem_640_aes_x25519 prototypes */ +int kex_kem_frodokem_640_aes_x25519_keypair(struct kex *); +int kex_kem_frodokem_640_aes_x25519_enc(struct kex *, const struct sshbuf *, struct sshbuf **, struct sshbuf **); +int kex_kem_frodokem_640_aes_x25519_dec(struct kex *, const struct sshbuf *, struct sshbuf **); /* frodokem_976_aes prototypes */ int kex_kem_frodokem_976_aes_keypair(struct kex *); int kex_kem_frodokem_976_aes_enc(struct kex *, const struct sshbuf *, struct sshbuf **, struct sshbuf **); @@ -385,6 +407,10 @@ int kex_kem_frodokem_1344_aes_dec(struct kex *, const struct sshbuf *, struct s int kex_kem_frodokem_640_shake_keypair(struct kex *); int kex_kem_frodokem_640_shake_enc(struct kex *, const struct sshbuf *, struct sshbuf **, struct sshbuf **); int kex_kem_frodokem_640_shake_dec(struct kex *, const struct sshbuf *, struct sshbuf **); +/* frodokem_640_shake_x25519 prototypes */ +int kex_kem_frodokem_640_shake_x25519_keypair(struct kex *); +int kex_kem_frodokem_640_shake_x25519_enc(struct kex *, const struct sshbuf *, struct sshbuf **, struct sshbuf **); +int kex_kem_frodokem_640_shake_x25519_dec(struct kex *, const struct sshbuf *, struct sshbuf **); /* frodokem_976_shake prototypes */ int kex_kem_frodokem_976_shake_keypair(struct kex *); int kex_kem_frodokem_976_shake_enc(struct kex *, const struct sshbuf *, struct sshbuf **, struct sshbuf **); @@ -397,6 +423,10 @@ int kex_kem_frodokem_1344_shake_dec(struct kex *, const struct sshbuf *, struct int kex_kem_kyber_512_keypair(struct kex *); int kex_kem_kyber_512_enc(struct kex *, const struct sshbuf *, struct sshbuf **, struct sshbuf **); int kex_kem_kyber_512_dec(struct kex *, const struct sshbuf *, struct sshbuf **); +/* kyber_512_x25519 prototypes */ +int kex_kem_kyber_512_x25519_keypair(struct kex *); +int kex_kem_kyber_512_x25519_enc(struct kex *, const struct sshbuf *, struct sshbuf **, struct sshbuf **); +int kex_kem_kyber_512_x25519_dec(struct kex *, const struct sshbuf *, struct sshbuf **); /* kyber_768 prototypes */ int kex_kem_kyber_768_keypair(struct kex *); int kex_kem_kyber_768_enc(struct kex *, const struct sshbuf *, struct sshbuf **, struct sshbuf **); @@ -409,6 +439,10 @@ int kex_kem_kyber_1024_dec(struct kex *, const struct sshbuf *, struct sshbuf * int kex_kem_bike_l1_keypair(struct kex *); int kex_kem_bike_l1_enc(struct kex *, const struct sshbuf *, struct sshbuf **, struct sshbuf **); int kex_kem_bike_l1_dec(struct kex *, const struct sshbuf *, struct sshbuf **); +/* bike_l1_x25519 prototypes */ +int kex_kem_bike_l1_x25519_keypair(struct kex *); +int kex_kem_bike_l1_x25519_enc(struct kex *, const struct sshbuf *, struct sshbuf **, struct sshbuf **); +int kex_kem_bike_l1_x25519_dec(struct kex *, const struct sshbuf *, struct sshbuf **); /* bike_l3 prototypes */ int kex_kem_bike_l3_keypair(struct kex *); int kex_kem_bike_l3_enc(struct kex *, const struct sshbuf *, struct sshbuf **, struct sshbuf **); @@ -421,10 +455,18 @@ int kex_kem_bike_l5_dec(struct kex *, const struct sshbuf *, struct sshbuf **); int kex_kem_classic_mceliece_348864_keypair(struct kex *); int kex_kem_classic_mceliece_348864_enc(struct kex *, const struct sshbuf *, struct sshbuf **, struct sshbuf **); int kex_kem_classic_mceliece_348864_dec(struct kex *, const struct sshbuf *, struct sshbuf **); +/* classic_mceliece_348864_x25519 prototypes */ +int kex_kem_classic_mceliece_348864_x25519_keypair(struct kex *); +int kex_kem_classic_mceliece_348864_x25519_enc(struct kex *, const struct sshbuf *, struct sshbuf **, struct sshbuf **); +int kex_kem_classic_mceliece_348864_x25519_dec(struct kex *, const struct sshbuf *, struct sshbuf **); /* classic_mceliece_348864f prototypes */ int kex_kem_classic_mceliece_348864f_keypair(struct kex *); int kex_kem_classic_mceliece_348864f_enc(struct kex *, const struct sshbuf *, struct sshbuf **, struct sshbuf **); int kex_kem_classic_mceliece_348864f_dec(struct kex *, const struct sshbuf *, struct sshbuf **); +/* classic_mceliece_348864f_x25519 prototypes */ +int kex_kem_classic_mceliece_348864f_x25519_keypair(struct kex *); +int kex_kem_classic_mceliece_348864f_x25519_enc(struct kex *, const struct sshbuf *, struct sshbuf **, struct sshbuf **); +int kex_kem_classic_mceliece_348864f_x25519_dec(struct kex *, const struct sshbuf *, struct sshbuf **); /* classic_mceliece_460896 prototypes */ int kex_kem_classic_mceliece_460896_keypair(struct kex *); int kex_kem_classic_mceliece_460896_enc(struct kex *, const struct sshbuf *, struct sshbuf **, struct sshbuf **); @@ -461,6 +503,10 @@ int kex_kem_classic_mceliece_8192128f_dec(struct kex *, const struct sshbuf *, int kex_kem_hqc_128_keypair(struct kex *); int kex_kem_hqc_128_enc(struct kex *, const struct sshbuf *, struct sshbuf **, struct sshbuf **); int kex_kem_hqc_128_dec(struct kex *, const struct sshbuf *, struct sshbuf **); +/* hqc_128_x25519 prototypes */ +int kex_kem_hqc_128_x25519_keypair(struct kex *); +int kex_kem_hqc_128_x25519_enc(struct kex *, const struct sshbuf *, struct sshbuf **, struct sshbuf **); +int kex_kem_hqc_128_x25519_dec(struct kex *, const struct sshbuf *, struct sshbuf **); /* hqc_192 prototypes */ int kex_kem_hqc_192_keypair(struct kex *); int kex_kem_hqc_192_enc(struct kex *, const struct sshbuf *, struct sshbuf **, struct sshbuf **); @@ -473,10 +519,18 @@ int kex_kem_hqc_256_dec(struct kex *, const struct sshbuf *, struct sshbuf **); int kex_kem_ml_kem_512_keypair(struct kex *); int kex_kem_ml_kem_512_enc(struct kex *, const struct sshbuf *, struct sshbuf **, struct sshbuf **); int kex_kem_ml_kem_512_dec(struct kex *, const struct sshbuf *, struct sshbuf **); +/* ml_kem_512_x25519 prototypes */ +int kex_kem_ml_kem_512_x25519_keypair(struct kex *); +int kex_kem_ml_kem_512_x25519_enc(struct kex *, const struct sshbuf *, struct sshbuf **, struct sshbuf **); +int kex_kem_ml_kem_512_x25519_dec(struct kex *, const struct sshbuf *, struct sshbuf **); /* ml_kem_768 prototypes */ int kex_kem_ml_kem_768_keypair(struct kex *); int kex_kem_ml_kem_768_enc(struct kex *, const struct sshbuf *, struct sshbuf **, struct sshbuf **); int kex_kem_ml_kem_768_dec(struct kex *, const struct sshbuf *, struct sshbuf **); +/* ml_kem_768_x25519 prototypes */ +int kex_kem_ml_kem_768_x25519_keypair(struct kex *); +int kex_kem_ml_kem_768_x25519_enc(struct kex *, const struct sshbuf *, struct sshbuf **, struct sshbuf **); +int kex_kem_ml_kem_768_x25519_dec(struct kex *, const struct sshbuf *, struct sshbuf **); /* ml_kem_1024 prototypes */ int kex_kem_ml_kem_1024_keypair(struct kex *); int kex_kem_ml_kem_1024_enc(struct kex *, const struct sshbuf *, struct sshbuf **, struct sshbuf **); diff --git a/kexgen.c b/kexgen.c index 13a4e34be540..2a04b40558dc 100644 --- a/kexgen.c +++ b/kexgen.c @@ -125,6 +125,9 @@ kex_gen_client(struct ssh *ssh) case KEX_KEM_FRODOKEM_640_AES_SHA256: r = kex_kem_frodokem_640_aes_keypair(kex); break; + case KEX_KEM_FRODOKEM_640_AES_X25519_SHA256: + r = kex_kem_frodokem_640_aes_x25519_keypair(kex); + break; case KEX_KEM_FRODOKEM_976_AES_SHA384: r = kex_kem_frodokem_976_aes_keypair(kex); break; @@ -134,6 +137,9 @@ kex_gen_client(struct ssh *ssh) case KEX_KEM_FRODOKEM_640_SHAKE_SHA256: r = kex_kem_frodokem_640_shake_keypair(kex); break; + case KEX_KEM_FRODOKEM_640_SHAKE_X25519_SHA256: + r = kex_kem_frodokem_640_shake_x25519_keypair(kex); + break; case KEX_KEM_FRODOKEM_976_SHAKE_SHA384: r = kex_kem_frodokem_976_shake_keypair(kex); break; @@ -143,6 +149,9 @@ kex_gen_client(struct ssh *ssh) case KEX_KEM_KYBER_512_SHA256: r = kex_kem_kyber_512_keypair(kex); break; + case KEX_KEM_KYBER_512_X25519_SHA256: + r = kex_kem_kyber_512_x25519_keypair(kex); + break; case KEX_KEM_KYBER_768_SHA384: r = kex_kem_kyber_768_keypair(kex); break; @@ -152,6 +161,9 @@ kex_gen_client(struct ssh *ssh) case KEX_KEM_BIKE_L1_SHA512: r = kex_kem_bike_l1_keypair(kex); break; + case KEX_KEM_BIKE_L1_X25519_SHA512: + r = kex_kem_bike_l1_x25519_keypair(kex); + break; case KEX_KEM_BIKE_L3_SHA512: r = kex_kem_bike_l3_keypair(kex); break; @@ -161,9 +173,15 @@ kex_gen_client(struct ssh *ssh) case KEX_KEM_CLASSIC_MCELIECE_348864_SHA256: r = kex_kem_classic_mceliece_348864_keypair(kex); break; + case KEX_KEM_CLASSIC_MCELIECE_348864_X25519_SHA256: + r = kex_kem_classic_mceliece_348864_x25519_keypair(kex); + break; case KEX_KEM_CLASSIC_MCELIECE_348864F_SHA256: r = kex_kem_classic_mceliece_348864f_keypair(kex); break; + case KEX_KEM_CLASSIC_MCELIECE_348864F_X25519_SHA256: + r = kex_kem_classic_mceliece_348864f_x25519_keypair(kex); + break; case KEX_KEM_CLASSIC_MCELIECE_460896_SHA512: r = kex_kem_classic_mceliece_460896_keypair(kex); break; @@ -191,6 +209,9 @@ kex_gen_client(struct ssh *ssh) case KEX_KEM_HQC_128_SHA256: r = kex_kem_hqc_128_keypair(kex); break; + case KEX_KEM_HQC_128_X25519_SHA256: + r = kex_kem_hqc_128_x25519_keypair(kex); + break; case KEX_KEM_HQC_192_SHA384: r = kex_kem_hqc_192_keypair(kex); break; @@ -200,9 +221,15 @@ kex_gen_client(struct ssh *ssh) case KEX_KEM_ML_KEM_512_SHA256: r = kex_kem_ml_kem_512_keypair(kex); break; + case KEX_KEM_ML_KEM_512_X25519_SHA256: + r = kex_kem_ml_kem_512_x25519_keypair(kex); + break; case KEX_KEM_ML_KEM_768_SHA256: r = kex_kem_ml_kem_768_keypair(kex); break; + case KEX_KEM_ML_KEM_768_X25519_SHA256: + r = kex_kem_ml_kem_768_x25519_keypair(kex); + break; case KEX_KEM_ML_KEM_1024_SHA384: r = kex_kem_ml_kem_1024_keypair(kex); break; @@ -371,6 +398,9 @@ input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh) case KEX_KEM_FRODOKEM_640_AES_SHA256: r = kex_kem_frodokem_640_aes_dec(kex, server_blob, &shared_secret); break; + case KEX_KEM_FRODOKEM_640_AES_X25519_SHA256: + r = kex_kem_frodokem_640_aes_x25519_dec(kex, server_blob, &shared_secret); + break; case KEX_KEM_FRODOKEM_976_AES_SHA384: r = kex_kem_frodokem_976_aes_dec(kex, server_blob, &shared_secret); break; @@ -380,6 +410,9 @@ input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh) case KEX_KEM_FRODOKEM_640_SHAKE_SHA256: r = kex_kem_frodokem_640_shake_dec(kex, server_blob, &shared_secret); break; + case KEX_KEM_FRODOKEM_640_SHAKE_X25519_SHA256: + r = kex_kem_frodokem_640_shake_x25519_dec(kex, server_blob, &shared_secret); + break; case KEX_KEM_FRODOKEM_976_SHAKE_SHA384: r = kex_kem_frodokem_976_shake_dec(kex, server_blob, &shared_secret); break; @@ -389,6 +422,9 @@ input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh) case KEX_KEM_KYBER_512_SHA256: r = kex_kem_kyber_512_dec(kex, server_blob, &shared_secret); break; + case KEX_KEM_KYBER_512_X25519_SHA256: + r = kex_kem_kyber_512_x25519_dec(kex, server_blob, &shared_secret); + break; case KEX_KEM_KYBER_768_SHA384: r = kex_kem_kyber_768_dec(kex, server_blob, &shared_secret); break; @@ -398,6 +434,9 @@ input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh) case KEX_KEM_BIKE_L1_SHA512: r = kex_kem_bike_l1_dec(kex, server_blob, &shared_secret); break; + case KEX_KEM_BIKE_L1_X25519_SHA512: + r = kex_kem_bike_l1_x25519_dec(kex, server_blob, &shared_secret); + break; case KEX_KEM_BIKE_L3_SHA512: r = kex_kem_bike_l3_dec(kex, server_blob, &shared_secret); break; @@ -407,9 +446,15 @@ input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh) case KEX_KEM_CLASSIC_MCELIECE_348864_SHA256: r = kex_kem_classic_mceliece_348864_dec(kex, server_blob, &shared_secret); break; + case KEX_KEM_CLASSIC_MCELIECE_348864_X25519_SHA256: + r = kex_kem_classic_mceliece_348864_x25519_dec(kex, server_blob, &shared_secret); + break; case KEX_KEM_CLASSIC_MCELIECE_348864F_SHA256: r = kex_kem_classic_mceliece_348864f_dec(kex, server_blob, &shared_secret); break; + case KEX_KEM_CLASSIC_MCELIECE_348864F_X25519_SHA256: + r = kex_kem_classic_mceliece_348864f_x25519_dec(kex, server_blob, &shared_secret); + break; case KEX_KEM_CLASSIC_MCELIECE_460896_SHA512: r = kex_kem_classic_mceliece_460896_dec(kex, server_blob, &shared_secret); break; @@ -437,6 +482,9 @@ input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh) case KEX_KEM_HQC_128_SHA256: r = kex_kem_hqc_128_dec(kex, server_blob, &shared_secret); break; + case KEX_KEM_HQC_128_X25519_SHA256: + r = kex_kem_hqc_128_x25519_dec(kex, server_blob, &shared_secret); + break; case KEX_KEM_HQC_192_SHA384: r = kex_kem_hqc_192_dec(kex, server_blob, &shared_secret); break; @@ -446,9 +494,15 @@ input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh) case KEX_KEM_ML_KEM_512_SHA256: r = kex_kem_ml_kem_512_dec(kex, server_blob, &shared_secret); break; + case KEX_KEM_ML_KEM_512_X25519_SHA256: + r = kex_kem_ml_kem_512_x25519_dec(kex, server_blob, &shared_secret); + break; case KEX_KEM_ML_KEM_768_SHA256: r = kex_kem_ml_kem_768_dec(kex, server_blob, &shared_secret); break; + case KEX_KEM_ML_KEM_768_X25519_SHA256: + r = kex_kem_ml_kem_768_x25519_dec(kex, server_blob, &shared_secret); + break; case KEX_KEM_ML_KEM_1024_SHA384: r = kex_kem_ml_kem_1024_dec(kex, server_blob, &shared_secret); break; @@ -669,6 +723,10 @@ input_kex_gen_init(int type, u_int32_t seq, struct ssh *ssh) r = kex_kem_frodokem_640_aes_enc(kex, client_pubkey, &server_pubkey, &shared_secret); break; + case KEX_KEM_FRODOKEM_640_AES_X25519_SHA256: + r = kex_kem_frodokem_640_aes_x25519_enc(kex, client_pubkey, + &server_pubkey, &shared_secret); + break; case KEX_KEM_FRODOKEM_976_AES_SHA384: r = kex_kem_frodokem_976_aes_enc(kex, client_pubkey, &server_pubkey, &shared_secret); @@ -681,6 +739,10 @@ input_kex_gen_init(int type, u_int32_t seq, struct ssh *ssh) r = kex_kem_frodokem_640_shake_enc(kex, client_pubkey, &server_pubkey, &shared_secret); break; + case KEX_KEM_FRODOKEM_640_SHAKE_X25519_SHA256: + r = kex_kem_frodokem_640_shake_x25519_enc(kex, client_pubkey, + &server_pubkey, &shared_secret); + break; case KEX_KEM_FRODOKEM_976_SHAKE_SHA384: r = kex_kem_frodokem_976_shake_enc(kex, client_pubkey, &server_pubkey, &shared_secret); @@ -693,6 +755,10 @@ input_kex_gen_init(int type, u_int32_t seq, struct ssh *ssh) r = kex_kem_kyber_512_enc(kex, client_pubkey, &server_pubkey, &shared_secret); break; + case KEX_KEM_KYBER_512_X25519_SHA256: + r = kex_kem_kyber_512_x25519_enc(kex, client_pubkey, + &server_pubkey, &shared_secret); + break; case KEX_KEM_KYBER_768_SHA384: r = kex_kem_kyber_768_enc(kex, client_pubkey, &server_pubkey, &shared_secret); @@ -705,6 +771,10 @@ input_kex_gen_init(int type, u_int32_t seq, struct ssh *ssh) r = kex_kem_bike_l1_enc(kex, client_pubkey, &server_pubkey, &shared_secret); break; + case KEX_KEM_BIKE_L1_X25519_SHA512: + r = kex_kem_bike_l1_x25519_enc(kex, client_pubkey, + &server_pubkey, &shared_secret); + break; case KEX_KEM_BIKE_L3_SHA512: r = kex_kem_bike_l3_enc(kex, client_pubkey, &server_pubkey, &shared_secret); @@ -717,10 +787,18 @@ input_kex_gen_init(int type, u_int32_t seq, struct ssh *ssh) r = kex_kem_classic_mceliece_348864_enc(kex, client_pubkey, &server_pubkey, &shared_secret); break; + case KEX_KEM_CLASSIC_MCELIECE_348864_X25519_SHA256: + r = kex_kem_classic_mceliece_348864_x25519_enc(kex, client_pubkey, + &server_pubkey, &shared_secret); + break; case KEX_KEM_CLASSIC_MCELIECE_348864F_SHA256: r = kex_kem_classic_mceliece_348864f_enc(kex, client_pubkey, &server_pubkey, &shared_secret); break; + case KEX_KEM_CLASSIC_MCELIECE_348864F_X25519_SHA256: + r = kex_kem_classic_mceliece_348864f_x25519_enc(kex, client_pubkey, + &server_pubkey, &shared_secret); + break; case KEX_KEM_CLASSIC_MCELIECE_460896_SHA512: r = kex_kem_classic_mceliece_460896_enc(kex, client_pubkey, &server_pubkey, &shared_secret); @@ -757,6 +835,10 @@ input_kex_gen_init(int type, u_int32_t seq, struct ssh *ssh) r = kex_kem_hqc_128_enc(kex, client_pubkey, &server_pubkey, &shared_secret); break; + case KEX_KEM_HQC_128_X25519_SHA256: + r = kex_kem_hqc_128_x25519_enc(kex, client_pubkey, + &server_pubkey, &shared_secret); + break; case KEX_KEM_HQC_192_SHA384: r = kex_kem_hqc_192_enc(kex, client_pubkey, &server_pubkey, &shared_secret); @@ -769,10 +851,18 @@ input_kex_gen_init(int type, u_int32_t seq, struct ssh *ssh) r = kex_kem_ml_kem_512_enc(kex, client_pubkey, &server_pubkey, &shared_secret); break; + case KEX_KEM_ML_KEM_512_X25519_SHA256: + r = kex_kem_ml_kem_512_x25519_enc(kex, client_pubkey, + &server_pubkey, &shared_secret); + break; case KEX_KEM_ML_KEM_768_SHA256: r = kex_kem_ml_kem_768_enc(kex, client_pubkey, &server_pubkey, &shared_secret); break; + case KEX_KEM_ML_KEM_768_X25519_SHA256: + r = kex_kem_ml_kem_768_x25519_enc(kex, client_pubkey, + &server_pubkey, &shared_secret); + break; case KEX_KEM_ML_KEM_1024_SHA384: r = kex_kem_ml_kem_1024_enc(kex, client_pubkey, &server_pubkey, &shared_secret); diff --git a/kexoqsx25519.c b/kexoqsx25519.c new file mode 100644 index 000000000000..313f5d18d8b5 --- /dev/null +++ b/kexoqsx25519.c @@ -0,0 +1,583 @@ +/* + * Adapted from kexoqsecdh.c and kexsntrup761x25519.c for hybrid PQC algs. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" + +#include "oqs/oqs.h" + +#include "digest.h" +#include "kex.h" +#include "sshbuf.h" +#include "ssherr.h" + +static int kex_kem_generic_with_x25519_keypair(OQS_KEM *kem, struct kex *kex) +{ + /* the client public key to send to the server. */ + struct sshbuf *buf = NULL; + u_char *public_key = NULL; + size_t hybrid_key_length = kem->length_public_key + CURVE25519_SIZE; + int r; + + /* allocate space for PQC public key (x25519 will be concatenated later) */ + if ((buf = sshbuf_new()) == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + if ((r = sshbuf_reserve(buf, hybrid_key_length, &public_key)) != 0) { + goto out; + } + + /* generate the PQC key */ + kex->oqs_client_key_size = kem->length_secret_key; + if ((kex->oqs_client_key = malloc(kex->oqs_client_key_size)) == NULL || + OQS_KEM_keypair(kem, public_key, kex->oqs_client_key) + != OQS_SUCCESS) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } + + /* generate the x25519 key */ + public_key += kem->length_public_key; + kexc25519_keygen(kex->c25519_client_key, public_key); + + /* store the values for decryption */ + kex->client_pub = buf; + buf = NULL; +out: + sshbuf_free(buf); + return r; +} + +static int kex_kem_generic_with_x25519_enc(OQS_KEM *kem, struct kex *kex, + const struct sshbuf *client_blob, + struct sshbuf **server_blobp, + struct sshbuf **shared_secretp) +{ + /* the server's PQC KEM key and x25519 shared secret */ + struct sshbuf *buf = NULL; + /* the server's PQC ciphertext and x25519 data to send to the client */ + struct sshbuf *server_blob = NULL; + const u_char *client_pub; + u_char *private_key, *public_key; + u_char server_key[CURVE25519_SIZE]; + u_char hash[SSH_DIGEST_MAX_LENGTH]; + size_t needed = 0; + int r; + + *server_blobp = NULL; + *shared_secretp = NULL; + + /* get a pointer to the client PQC public key */ + client_pub = sshbuf_ptr(client_blob); + + /* allocate buffer for concatenation of KEM key and x25519 shared key */ + /* the buffer will be hashed and the result is the shared secret */ + if ((buf = sshbuf_new()) == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } + needed = kem->length_shared_secret; + if ((r = sshbuf_reserve(buf, needed, &private_key)) + != 0) { + goto out; + } + + /* allocate buffer for encrypted KEM key and x25519 value */ + if ((server_blob = sshbuf_new()) == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } + needed = kem->length_ciphertext + CURVE25519_SIZE; + if ((r = sshbuf_reserve(server_blob, needed, + &public_key)) != 0) { + goto out; + } + + /* generate and encrypt KEM key with client key */ + if (OQS_KEM_encaps(kem, public_key, private_key, client_pub) + != OQS_SUCCESS) { + goto out; + } + client_pub += kem->length_public_key; + public_key += kem->length_ciphertext; + private_key += kem->length_shared_secret; + + kexc25519_keygen(server_key, public_key); + if ((r = kexc25519_shared_key_ext(server_key, client_pub, buf, 1)) < 0) { + goto out; + } + + /* hash concatenation of KEM key and x25519 shared key*/ + if ((r = ssh_digest_buffer(kex->hash_alg, buf, hash, sizeof(hash))) + != 0) { + goto out; + } + + /* string-encoded hash is resulting shared secret */ + sshbuf_reset(buf); + if ((r = sshbuf_put_string(buf, hash, + ssh_digest_bytes(kex->hash_alg))) != 0) { + goto out; + } + + *server_blobp = server_blob; + *shared_secretp = buf; + server_blob = NULL; + buf = NULL; +out: + explicit_bzero(server_key, CURVE25519_SIZE); + explicit_bzero(hash, sizeof(hash)); + sshbuf_free(server_blob); + sshbuf_free(buf); + return r; +} + +static int kex_kem_generic_with_x25519_dec(OQS_KEM *kem, struct kex *kex, + const struct sshbuf *server_blob, + struct sshbuf **shared_secretp) +{ + /* the server's PQC KEM key and x25519 shared secret */ + struct sshbuf *buf = NULL; + u_char *private_key = NULL; + const u_char *public_key; + size_t needed = 0; + /* x25519 values */ + u_char hash[SSH_DIGEST_MAX_LENGTH]; + int r; + + *shared_secretp = NULL; + + /* get a pointer to the server PQC ciphertext */ + public_key = sshbuf_ptr(server_blob); + + /* allocate buffer for concatenation of KEM key and x25519 shared key */ + /* the buffer will be hashed and the result is the shared secret */ + if ((buf = sshbuf_new()) == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } + needed = kem->length_shared_secret; + if ((r = sshbuf_reserve(buf, needed, &private_key)) != 0) { + goto out; + } + + /* decapsulate the post-quantum secret */ + if (OQS_KEM_decaps(kem, private_key, public_key, + kex->oqs_client_key) != OQS_SUCCESS) { + goto out; + } + public_key += kem->length_ciphertext; + + if ((r = kexc25519_shared_key_ext(kex->c25519_client_key, public_key, + buf, 1)) < 0) { + goto out; + } + + /* hash concatenation of KEM key and x25519 shared key*/ + if ((r = ssh_digest_buffer(kex->hash_alg, buf, hash, sizeof(hash))) != 0) { + goto out; + } + sshbuf_reset(buf); + if ((r = sshbuf_put_string(buf, hash, + ssh_digest_bytes(kex->hash_alg))) != 0) { + goto out; + } + *shared_secretp = buf; + buf = NULL; +out: + explicit_bzero(hash, sizeof(hash)); + sshbuf_free(buf); + return r; +} + +///// OQS_TEMPLATE_FRAGMENT_DEFINE_KEX_WITH_X25519_METHODS_START +/*--------------------------------------------------------------- + * FRODOKEM_640_AES_X25519 METHODS + *--------------------------------------------------------------- + */ +int kex_kem_frodokem_640_aes_x25519_keypair(struct kex *kex) +{ + OQS_KEM *kem = OQS_KEM_new(OQS_KEM_alg_frodokem_640_aes); + if (kem == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + int r = kex_kem_generic_with_x25519_keypair(kem, kex); + OQS_KEM_free(kem); + return r; +} + +int kex_kem_frodokem_640_aes_x25519_enc(struct kex *kex, + const struct sshbuf *client_blob, + struct sshbuf **server_blobp, + struct sshbuf **shared_secretp) +{ + OQS_KEM *kem = OQS_KEM_new(OQS_KEM_alg_frodokem_640_aes); + if (kem == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + int r = kex_kem_generic_with_x25519_enc(kem, kex, client_blob, server_blobp, shared_secretp); + OQS_KEM_free(kem); + return r; +} + +int kex_kem_frodokem_640_aes_x25519_dec(struct kex *kex, + const struct sshbuf *server_blobp, + struct sshbuf **shared_secretp) +{ + OQS_KEM *kem = OQS_KEM_new(OQS_KEM_alg_frodokem_640_aes); + if (kem == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + int r = kex_kem_generic_with_x25519_dec(kem, kex, server_blobp, shared_secretp); + OQS_KEM_free(kem); + return r; +} +/*--------------------------------------------------------------- + * FRODOKEM_640_SHAKE_X25519 METHODS + *--------------------------------------------------------------- + */ +int kex_kem_frodokem_640_shake_x25519_keypair(struct kex *kex) +{ + OQS_KEM *kem = OQS_KEM_new(OQS_KEM_alg_frodokem_640_shake); + if (kem == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + int r = kex_kem_generic_with_x25519_keypair(kem, kex); + OQS_KEM_free(kem); + return r; +} + +int kex_kem_frodokem_640_shake_x25519_enc(struct kex *kex, + const struct sshbuf *client_blob, + struct sshbuf **server_blobp, + struct sshbuf **shared_secretp) +{ + OQS_KEM *kem = OQS_KEM_new(OQS_KEM_alg_frodokem_640_shake); + if (kem == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + int r = kex_kem_generic_with_x25519_enc(kem, kex, client_blob, server_blobp, shared_secretp); + OQS_KEM_free(kem); + return r; +} + +int kex_kem_frodokem_640_shake_x25519_dec(struct kex *kex, + const struct sshbuf *server_blobp, + struct sshbuf **shared_secretp) +{ + OQS_KEM *kem = OQS_KEM_new(OQS_KEM_alg_frodokem_640_shake); + if (kem == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + int r = kex_kem_generic_with_x25519_dec(kem, kex, server_blobp, shared_secretp); + OQS_KEM_free(kem); + return r; +} +/*--------------------------------------------------------------- + * KYBER_512_X25519 METHODS + *--------------------------------------------------------------- + */ +int kex_kem_kyber_512_x25519_keypair(struct kex *kex) +{ + OQS_KEM *kem = OQS_KEM_new(OQS_KEM_alg_kyber_512); + if (kem == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + int r = kex_kem_generic_with_x25519_keypair(kem, kex); + OQS_KEM_free(kem); + return r; +} + +int kex_kem_kyber_512_x25519_enc(struct kex *kex, + const struct sshbuf *client_blob, + struct sshbuf **server_blobp, + struct sshbuf **shared_secretp) +{ + OQS_KEM *kem = OQS_KEM_new(OQS_KEM_alg_kyber_512); + if (kem == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + int r = kex_kem_generic_with_x25519_enc(kem, kex, client_blob, server_blobp, shared_secretp); + OQS_KEM_free(kem); + return r; +} + +int kex_kem_kyber_512_x25519_dec(struct kex *kex, + const struct sshbuf *server_blobp, + struct sshbuf **shared_secretp) +{ + OQS_KEM *kem = OQS_KEM_new(OQS_KEM_alg_kyber_512); + if (kem == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + int r = kex_kem_generic_with_x25519_dec(kem, kex, server_blobp, shared_secretp); + OQS_KEM_free(kem); + return r; +} +/*--------------------------------------------------------------- + * BIKE_L1_X25519 METHODS + *--------------------------------------------------------------- + */ +int kex_kem_bike_l1_x25519_keypair(struct kex *kex) +{ + OQS_KEM *kem = OQS_KEM_new(OQS_KEM_alg_bike_l1); + if (kem == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + int r = kex_kem_generic_with_x25519_keypair(kem, kex); + OQS_KEM_free(kem); + return r; +} + +int kex_kem_bike_l1_x25519_enc(struct kex *kex, + const struct sshbuf *client_blob, + struct sshbuf **server_blobp, + struct sshbuf **shared_secretp) +{ + OQS_KEM *kem = OQS_KEM_new(OQS_KEM_alg_bike_l1); + if (kem == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + int r = kex_kem_generic_with_x25519_enc(kem, kex, client_blob, server_blobp, shared_secretp); + OQS_KEM_free(kem); + return r; +} + +int kex_kem_bike_l1_x25519_dec(struct kex *kex, + const struct sshbuf *server_blobp, + struct sshbuf **shared_secretp) +{ + OQS_KEM *kem = OQS_KEM_new(OQS_KEM_alg_bike_l1); + if (kem == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + int r = kex_kem_generic_with_x25519_dec(kem, kex, server_blobp, shared_secretp); + OQS_KEM_free(kem); + return r; +} +/*--------------------------------------------------------------- + * CLASSIC_MCELIECE_348864_X25519 METHODS + *--------------------------------------------------------------- + */ +int kex_kem_classic_mceliece_348864_x25519_keypair(struct kex *kex) +{ + OQS_KEM *kem = OQS_KEM_new(OQS_KEM_alg_classic_mceliece_348864); + if (kem == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + int r = kex_kem_generic_with_x25519_keypair(kem, kex); + OQS_KEM_free(kem); + return r; +} + +int kex_kem_classic_mceliece_348864_x25519_enc(struct kex *kex, + const struct sshbuf *client_blob, + struct sshbuf **server_blobp, + struct sshbuf **shared_secretp) +{ + OQS_KEM *kem = OQS_KEM_new(OQS_KEM_alg_classic_mceliece_348864); + if (kem == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + int r = kex_kem_generic_with_x25519_enc(kem, kex, client_blob, server_blobp, shared_secretp); + OQS_KEM_free(kem); + return r; +} + +int kex_kem_classic_mceliece_348864_x25519_dec(struct kex *kex, + const struct sshbuf *server_blobp, + struct sshbuf **shared_secretp) +{ + OQS_KEM *kem = OQS_KEM_new(OQS_KEM_alg_classic_mceliece_348864); + if (kem == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + int r = kex_kem_generic_with_x25519_dec(kem, kex, server_blobp, shared_secretp); + OQS_KEM_free(kem); + return r; +} +/*--------------------------------------------------------------- + * CLASSIC_MCELIECE_348864F_X25519 METHODS + *--------------------------------------------------------------- + */ +int kex_kem_classic_mceliece_348864f_x25519_keypair(struct kex *kex) +{ + OQS_KEM *kem = OQS_KEM_new(OQS_KEM_alg_classic_mceliece_348864f); + if (kem == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + int r = kex_kem_generic_with_x25519_keypair(kem, kex); + OQS_KEM_free(kem); + return r; +} + +int kex_kem_classic_mceliece_348864f_x25519_enc(struct kex *kex, + const struct sshbuf *client_blob, + struct sshbuf **server_blobp, + struct sshbuf **shared_secretp) +{ + OQS_KEM *kem = OQS_KEM_new(OQS_KEM_alg_classic_mceliece_348864f); + if (kem == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + int r = kex_kem_generic_with_x25519_enc(kem, kex, client_blob, server_blobp, shared_secretp); + OQS_KEM_free(kem); + return r; +} + +int kex_kem_classic_mceliece_348864f_x25519_dec(struct kex *kex, + const struct sshbuf *server_blobp, + struct sshbuf **shared_secretp) +{ + OQS_KEM *kem = OQS_KEM_new(OQS_KEM_alg_classic_mceliece_348864f); + if (kem == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + int r = kex_kem_generic_with_x25519_dec(kem, kex, server_blobp, shared_secretp); + OQS_KEM_free(kem); + return r; +} +/*--------------------------------------------------------------- + * HQC_128_X25519 METHODS + *--------------------------------------------------------------- + */ +int kex_kem_hqc_128_x25519_keypair(struct kex *kex) +{ + OQS_KEM *kem = OQS_KEM_new(OQS_KEM_alg_hqc_128); + if (kem == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + int r = kex_kem_generic_with_x25519_keypair(kem, kex); + OQS_KEM_free(kem); + return r; +} + +int kex_kem_hqc_128_x25519_enc(struct kex *kex, + const struct sshbuf *client_blob, + struct sshbuf **server_blobp, + struct sshbuf **shared_secretp) +{ + OQS_KEM *kem = OQS_KEM_new(OQS_KEM_alg_hqc_128); + if (kem == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + int r = kex_kem_generic_with_x25519_enc(kem, kex, client_blob, server_blobp, shared_secretp); + OQS_KEM_free(kem); + return r; +} + +int kex_kem_hqc_128_x25519_dec(struct kex *kex, + const struct sshbuf *server_blobp, + struct sshbuf **shared_secretp) +{ + OQS_KEM *kem = OQS_KEM_new(OQS_KEM_alg_hqc_128); + if (kem == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + int r = kex_kem_generic_with_x25519_dec(kem, kex, server_blobp, shared_secretp); + OQS_KEM_free(kem); + return r; +} +/*--------------------------------------------------------------- + * ML_KEM_512_X25519 METHODS + *--------------------------------------------------------------- + */ +int kex_kem_ml_kem_512_x25519_keypair(struct kex *kex) +{ + OQS_KEM *kem = OQS_KEM_new(OQS_KEM_alg_ml_kem_512); + if (kem == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + int r = kex_kem_generic_with_x25519_keypair(kem, kex); + OQS_KEM_free(kem); + return r; +} + +int kex_kem_ml_kem_512_x25519_enc(struct kex *kex, + const struct sshbuf *client_blob, + struct sshbuf **server_blobp, + struct sshbuf **shared_secretp) +{ + OQS_KEM *kem = OQS_KEM_new(OQS_KEM_alg_ml_kem_512); + if (kem == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + int r = kex_kem_generic_with_x25519_enc(kem, kex, client_blob, server_blobp, shared_secretp); + OQS_KEM_free(kem); + return r; +} + +int kex_kem_ml_kem_512_x25519_dec(struct kex *kex, + const struct sshbuf *server_blobp, + struct sshbuf **shared_secretp) +{ + OQS_KEM *kem = OQS_KEM_new(OQS_KEM_alg_ml_kem_512); + if (kem == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + int r = kex_kem_generic_with_x25519_dec(kem, kex, server_blobp, shared_secretp); + OQS_KEM_free(kem); + return r; +} +/*--------------------------------------------------------------- + * ML_KEM_768_X25519 METHODS + *--------------------------------------------------------------- + */ +int kex_kem_ml_kem_768_x25519_keypair(struct kex *kex) +{ + OQS_KEM *kem = OQS_KEM_new(OQS_KEM_alg_ml_kem_768); + if (kem == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + int r = kex_kem_generic_with_x25519_keypair(kem, kex); + OQS_KEM_free(kem); + return r; +} + +int kex_kem_ml_kem_768_x25519_enc(struct kex *kex, + const struct sshbuf *client_blob, + struct sshbuf **server_blobp, + struct sshbuf **shared_secretp) +{ + OQS_KEM *kem = OQS_KEM_new(OQS_KEM_alg_ml_kem_768); + if (kem == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + int r = kex_kem_generic_with_x25519_enc(kem, kex, client_blob, server_blobp, shared_secretp); + OQS_KEM_free(kem); + return r; +} + +int kex_kem_ml_kem_768_x25519_dec(struct kex *kex, + const struct sshbuf *server_blobp, + struct sshbuf **shared_secretp) +{ + OQS_KEM *kem = OQS_KEM_new(OQS_KEM_alg_ml_kem_768); + if (kem == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + int r = kex_kem_generic_with_x25519_dec(kem, kex, server_blobp, shared_secretp); + OQS_KEM_free(kem); + return r; +} +///// OQS_TEMPLATE_FRAGMENT_DEFINE_KEX_WITH_X25519_METHODS_END diff --git a/monitor.c b/monitor.c index dc0d3cbd60a7..cf31bc3b5ab6 100644 --- a/monitor.c +++ b/monitor.c @@ -1751,19 +1751,25 @@ monitor_apply_keystate(struct ssh *ssh, struct monitor *pmonitor) kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_server; ///// OQS_TEMPLATE_FRAGMENT_APPLY_KEYSTATE_START kex->kex[KEX_KEM_FRODOKEM_640_AES_SHA256] = kex_gen_server; + kex->kex[KEX_KEM_FRODOKEM_640_AES_X25519_SHA256] = kex_gen_server; kex->kex[KEX_KEM_FRODOKEM_976_AES_SHA384] = kex_gen_server; kex->kex[KEX_KEM_FRODOKEM_1344_AES_SHA512] = kex_gen_server; kex->kex[KEX_KEM_FRODOKEM_640_SHAKE_SHA256] = kex_gen_server; + kex->kex[KEX_KEM_FRODOKEM_640_SHAKE_X25519_SHA256] = kex_gen_server; kex->kex[KEX_KEM_FRODOKEM_976_SHAKE_SHA384] = kex_gen_server; kex->kex[KEX_KEM_FRODOKEM_1344_SHAKE_SHA512] = kex_gen_server; kex->kex[KEX_KEM_KYBER_512_SHA256] = kex_gen_server; + kex->kex[KEX_KEM_KYBER_512_X25519_SHA256] = kex_gen_server; kex->kex[KEX_KEM_KYBER_768_SHA384] = kex_gen_server; kex->kex[KEX_KEM_KYBER_1024_SHA512] = kex_gen_server; kex->kex[KEX_KEM_BIKE_L1_SHA512] = kex_gen_server; + kex->kex[KEX_KEM_BIKE_L1_X25519_SHA512] = kex_gen_server; kex->kex[KEX_KEM_BIKE_L3_SHA512] = kex_gen_server; kex->kex[KEX_KEM_BIKE_L5_SHA512] = kex_gen_server; kex->kex[KEX_KEM_CLASSIC_MCELIECE_348864_SHA256] = kex_gen_server; + kex->kex[KEX_KEM_CLASSIC_MCELIECE_348864_X25519_SHA256] = kex_gen_server; kex->kex[KEX_KEM_CLASSIC_MCELIECE_348864F_SHA256] = kex_gen_server; + kex->kex[KEX_KEM_CLASSIC_MCELIECE_348864F_X25519_SHA256] = kex_gen_server; kex->kex[KEX_KEM_CLASSIC_MCELIECE_460896_SHA512] = kex_gen_server; kex->kex[KEX_KEM_CLASSIC_MCELIECE_460896F_SHA512] = kex_gen_server; kex->kex[KEX_KEM_CLASSIC_MCELIECE_6688128_SHA512] = kex_gen_server; @@ -1773,10 +1779,13 @@ monitor_apply_keystate(struct ssh *ssh, struct monitor *pmonitor) kex->kex[KEX_KEM_CLASSIC_MCELIECE_8192128_SHA512] = kex_gen_server; kex->kex[KEX_KEM_CLASSIC_MCELIECE_8192128F_SHA512] = kex_gen_server; kex->kex[KEX_KEM_HQC_128_SHA256] = kex_gen_server; + kex->kex[KEX_KEM_HQC_128_X25519_SHA256] = kex_gen_server; kex->kex[KEX_KEM_HQC_192_SHA384] = kex_gen_server; kex->kex[KEX_KEM_HQC_256_SHA512] = kex_gen_server; kex->kex[KEX_KEM_ML_KEM_512_SHA256] = kex_gen_server; + kex->kex[KEX_KEM_ML_KEM_512_X25519_SHA256] = kex_gen_server; kex->kex[KEX_KEM_ML_KEM_768_SHA256] = kex_gen_server; + kex->kex[KEX_KEM_ML_KEM_768_X25519_SHA256] = kex_gen_server; kex->kex[KEX_KEM_ML_KEM_1024_SHA384] = kex_gen_server; #ifdef WITH_OPENSSL #ifdef OPENSSL_HAS_ECC diff --git a/myproposal.h b/myproposal.h index 9a66cff8d984..b833aa9970b4 100644 --- a/myproposal.h +++ b/myproposal.h @@ -41,32 +41,38 @@ /*/// OQS_TEMPLATE_FRAGMENT_ADD_SERVER_KEXS_START */ \ "frodokem-640-aes-sha256," \ "ecdh-nistp256-frodokem-640-aesr2-sha256@openquantumsafe.org," \ + "x25519-frodokem-640-aesr2-sha256@openquantumsafe.org," \ "frodokem-976-aes-sha384," \ "ecdh-nistp384-frodokem-976-aesr2-sha384@openquantumsafe.org," \ "frodokem-1344-aes-sha512," \ "ecdh-nistp521-frodokem-1344-aesr2-sha512@openquantumsafe.org," \ "frodokem-640-shake-sha256," \ "ecdh-nistp256-frodokem-640-shaker2-sha256@openquantumsafe.org," \ + "x25519-frodokem-640-shaker2-sha256@openquantumsafe.org," \ "frodokem-976-shake-sha384," \ "ecdh-nistp384-frodokem-976-shaker2-sha384@openquantumsafe.org," \ "frodokem-1344-shake-sha512," \ "ecdh-nistp521-frodokem-1344-shaker2-sha512@openquantumsafe.org," \ "kyber-512-sha256," \ "ecdh-nistp256-kyber-512r3-sha256-d00@openquantumsafe.org," \ + "x25519-kyber-512r3-sha256-d00@amazon.com," \ "kyber-768-sha384," \ "ecdh-nistp384-kyber-768r3-sha384-d00@openquantumsafe.org," \ "kyber-1024-sha512," \ "ecdh-nistp521-kyber-1024r3-sha512-d00@openquantumsafe.org," \ "bike-l1-sha512," \ "ecdh-nistp256-bike-l1r4-sha512@openquantumsafe.org," \ + "x25519-bike-l1r4-sha512@openquantumsafe.org," \ "bike-l3-sha512," \ "ecdh-nistp384-bike-l3r4-sha512@openquantumsafe.org," \ "bike-l5-sha512," \ "ecdh-nistp521-bike-l5r4-sha512@openquantumsafe.org," \ "classic-mceliece-348864-sha256," \ "ecdh-nistp256-classic-mceliece-348864r4-sha256@openquantumsafe.org," \ + "x25519-classic-mceliece-348864r4-sha256@openquantumsafe.org," \ "classic-mceliece-348864f-sha256," \ "ecdh-nistp256-classic-mceliece-348864fr4-sha256@openquantumsafe.org," \ + "x25519-classic-mceliece-348864fr4-sha256@openquantumsafe.org," \ "classic-mceliece-460896-sha512," \ "ecdh-nistp384-classic-mceliece-460896r4-sha512@openquantumsafe.org," \ "classic-mceliece-460896f-sha512," \ @@ -85,14 +91,17 @@ "ecdh-nistp521-classic-mceliece-8192128fr4-sha512@openquantumsafe.org," \ "hqc-128-sha256," \ "ecdh-nistp256-hqc-128r3-sha256@openquantumsafe.org," \ + "x25519-hqc-128r3-sha256@openquantumsafe.org," \ "hqc-192-sha384," \ "ecdh-nistp384-hqc-192r3-sha384@openquantumsafe.org," \ "hqc-256-sha512," \ "ecdh-nistp521-hqc-256r3-sha512@openquantumsafe.org," \ "ml-kem-512-sha256," \ "ecdh-nistp256-ml-kem-512-sha256@openquantumsafe.org," \ + "x25519-ml-kem-512-sha256@openquantumsafe.org," \ "ml-kem-768-sha256," \ "mlkem768nistp256-sha256," \ + "mlkem768x25519-sha256," \ "ml-kem-1024-sha384," \ "mlkem1024nistp384-sha384" /*/// OQS_TEMPLATE_FRAGMENT_ADD_SERVER_KEXS_END */ diff --git a/oqs-template/generate.py b/oqs-template/generate.py index 027b41ee9b9b..8172df0d522e 100755 --- a/oqs-template/generate.py +++ b/oqs-template/generate.py @@ -64,6 +64,7 @@ def load_config(include_disabled_algs=False): populate('kexgen.c', config, '/////') populate('kexoqs.c', config, '/////') populate('kexoqsecdh.c', config, '/////') +populate('kexoqsx25519.c', config, '/////') populate('monitor.c', config, '/////') populate('sshd.c', config, '/////') populate('sshconnect2.c', config, '/////') diff --git a/oqs-template/generate.yml b/oqs-template/generate.yml index 811460fe5a58..ddd9b065825b 100644 --- a/oqs-template/generate.yml +++ b/oqs-template/generate.yml @@ -10,6 +10,10 @@ kexs: name: 'nistp256' openssl_nid: 'NID_X9_62_prime256v1' pretty_name: 'ecdh-nistp256-frodokem-640-aesr2-sha256@openquantumsafe.org' + - + name: 'x25519' + x25519: true + pretty_name: 'x25519-frodokem-640-aesr2-sha256@openquantumsafe.org' - family: 'FrodoKEM' name: 'frodokem_976_aes' @@ -40,6 +44,10 @@ kexs: name: 'nistp256' openssl_nid: 'NID_X9_62_prime256v1' pretty_name: 'ecdh-nistp256-frodokem-640-shaker2-sha256@openquantumsafe.org' + - + name: 'x25519' + x25519: true + pretty_name: 'x25519-frodokem-640-shaker2-sha256@openquantumsafe.org' - family: 'FrodoKEM' name: 'frodokem_976_shake' @@ -70,6 +78,10 @@ kexs: name: 'nistp256' openssl_nid: 'NID_X9_62_prime256v1' pretty_name: 'ecdh-nistp256-kyber-512r3-sha256-d00@openquantumsafe.org' + - + name: 'x25519' + x25519: true + pretty_name: 'x25519-kyber-512r3-sha256-d00@amazon.com' - family: 'Kyber' name: 'kyber_768' @@ -100,6 +112,10 @@ kexs: name: 'nistp256' openssl_nid: 'NID_X9_62_prime256v1' pretty_name: 'ecdh-nistp256-bike-l1r4-sha512@openquantumsafe.org' + - + name: 'x25519' + x25519: true + pretty_name: 'x25519-bike-l1r4-sha512@openquantumsafe.org' - family: 'BIKE' name: 'bike_l3' @@ -130,6 +146,10 @@ kexs: name: 'nistp256' openssl_nid: 'NID_X9_62_prime256v1' pretty_name: 'ecdh-nistp256-classic-mceliece-348864r4-sha256@openquantumsafe.org' + - + name: 'x25519' + x25519: true + pretty_name: 'x25519-classic-mceliece-348864r4-sha256@openquantumsafe.org' - family: 'ClassicMcEliece' name: 'classic_mceliece_348864f' @@ -140,6 +160,10 @@ kexs: name: 'nistp256' openssl_nid: 'NID_X9_62_prime256v1' pretty_name: 'ecdh-nistp256-classic-mceliece-348864fr4-sha256@openquantumsafe.org' + - + name: 'x25519' + x25519: true + pretty_name: 'x25519-classic-mceliece-348864fr4-sha256@openquantumsafe.org' - family: 'ClassicMcEliece' name: 'classic_mceliece_460896' @@ -230,6 +254,10 @@ kexs: name: 'nistp256' openssl_nid: 'NID_X9_62_prime256v1' pretty_name: 'ecdh-nistp256-hqc-128r3-sha256@openquantumsafe.org' + - + name: 'x25519' + x25519: true + pretty_name: 'x25519-hqc-128r3-sha256@openquantumsafe.org' - family: 'HQC' name: 'hqc_192' @@ -260,6 +288,10 @@ kexs: name: 'nistp256' openssl_nid: 'NID_X9_62_prime256v1' pretty_name: 'ecdh-nistp256-ml-kem-512-sha256@openquantumsafe.org' + - + name: 'x25519' + x25519: true + pretty_name: 'x25519-ml-kem-512-sha256@openquantumsafe.org' - family: 'ML-KEM' name: 'ml_kem_768' @@ -270,6 +302,10 @@ kexs: name: 'nistp256' openssl_nid: 'NID_X9_62_prime256v1' pretty_name: 'mlkem768nistp256-sha256' + - + name: 'x25519' + x25519: true + pretty_name: 'mlkem768x25519-sha256' - family: 'ML-KEM' name: 'ml_kem_1024' diff --git a/oqs-template/kex.c/add_kex_algs.fragment b/oqs-template/kex.c/add_kex_algs.fragment index a538df44b77e..54bd1eb23abc 100644 --- a/oqs-template/kex.c/add_kex_algs.fragment +++ b/oqs-template/kex.c/add_kex_algs.fragment @@ -1,9 +1,12 @@ {% for kex in config['kexs'] %} { KEX_{{ kex['name']|upper }}_{{ kex['hash']|upper }}, KEX_KEM_{{ kex['name']|upper }}_{{ kex['hash']|upper }}, 0, SSH_DIGEST_{{ kex['hash']|upper }} }, +{%- for curve in kex['mix_with'] if curve['x25519'] %} + { KEX_{{ kex['name']|upper }}_{{ curve['name']|upper }}_{{ kex['hash']|upper }}, KEX_KEM_{{ kex['name']|upper }}_{{ curve['name']|upper }}_{{ kex['hash']|upper }}, 0, SSH_DIGEST_{{ kex['hash']|upper }} }, +{%- endfor %} {%- endfor %} #ifdef OPENSSL_HAS_ECC {%- for kex in config['kexs'] -%} - {%- for curve in kex['mix_with'] %} + {%- for curve in kex['mix_with'] if not curve['x25519'] %} { KEX_{{ kex['name']|upper }}_ECDH_{{ curve['name']|upper }}_{{ kex['hash']|upper }}, KEX_KEM_{{ kex['name']|upper }}_ECDH_{{ curve['name']|upper }}_{{ kex['hash']|upper }}, {{ curve['openssl_nid'] }}, SSH_DIGEST_{{ kex['hash']|upper }} }, {%- endfor %} {%- endfor %} diff --git a/oqs-template/kex.h/add_kex_enums.fragment b/oqs-template/kex.h/add_kex_enums.fragment index 25118115ebb3..aa3f81b1a125 100644 --- a/oqs-template/kex.h/add_kex_enums.fragment +++ b/oqs-template/kex.h/add_kex_enums.fragment @@ -1,10 +1,13 @@ {%- for kex in config['kexs'] %} KEX_KEM_{{ kex['name']|upper }}_{{ kex['hash']|upper }}, +{%- for curve in kex['mix_with'] if curve['x25519'] %} + KEX_KEM_{{ kex['name']|upper }}_{{ curve['name']|upper }}_{{ kex['hash']|upper }}, +{%- endfor %} {%- endfor %} #ifdef WITH_OPENSSL #ifdef OPENSSL_HAS_ECC {%- for kex in config['kexs'] -%} - {%- for curve in kex['mix_with'] %} + {%- for curve in kex['mix_with'] if not curve['x25519'] %} KEX_KEM_{{ kex['name']|upper }}_ECDH_{{ curve['name']|upper }}_{{ kex['hash']|upper }}, {%- endfor %} {%- endfor %} diff --git a/oqs-template/kex.h/declare_kex_prototypes.fragment b/oqs-template/kex.h/declare_kex_prototypes.fragment index 35163c6289bd..3e71b603e4eb 100644 --- a/oqs-template/kex.h/declare_kex_prototypes.fragment +++ b/oqs-template/kex.h/declare_kex_prototypes.fragment @@ -3,11 +3,17 @@ int kex_kem_{{ kex['name'] }}_keypair(struct kex *); int kex_kem_{{ kex['name'] }}_enc(struct kex *, const struct sshbuf *, struct sshbuf **, struct sshbuf **); int kex_kem_{{ kex['name'] }}_dec(struct kex *, const struct sshbuf *, struct sshbuf **); +{%- for curve in kex['mix_with'] if curve['x25519'] %} +/* {{ kex['name'] }}_{{ curve['name'] }} prototypes */ +int kex_kem_{{ kex['name'] }}_{{ curve['name'] }}_keypair(struct kex *); +int kex_kem_{{ kex['name'] }}_{{ curve['name'] }}_enc(struct kex *, const struct sshbuf *, struct sshbuf **, struct sshbuf **); +int kex_kem_{{ kex['name'] }}_{{ curve['name'] }}_dec(struct kex *, const struct sshbuf *, struct sshbuf **); +{%- endfor %} {%- endfor %} #ifdef WITH_OPENSSL #ifdef OPENSSL_HAS_ECC {%- for kex in config['kexs'] -%} - {%- for curve in kex['mix_with'] %} + {%- for curve in kex['mix_with'] if not curve['x25519'] %} /* {{ kex['name'] }}_{{ curve['name'] }} prototypes */ int kex_kem_{{ kex['name'] }}_ecdh_{{ curve['name'] }}_keypair(struct kex *); int kex_kem_{{ kex['name'] }}_ecdh_{{ curve['name'] }}_enc(struct kex *, const struct sshbuf *, struct sshbuf **, struct sshbuf **); diff --git a/oqs-template/kex.h/define_kex_pretty_names.fragment b/oqs-template/kex.h/define_kex_pretty_names.fragment index c1bfcaef814f..26b6373c8181 100644 --- a/oqs-template/kex.h/define_kex_pretty_names.fragment +++ b/oqs-template/kex.h/define_kex_pretty_names.fragment @@ -1,10 +1,13 @@ {%- for kex in config['kexs'] %} #define KEX_{{ kex['name']|upper }}_{{ kex['hash']|upper }} "{{ kex['pretty_name'] }}" +{%- for curve in kex['mix_with'] if curve['x25519'] %} +#define KEX_{{ kex['name']|upper }}_{{ curve['name']|upper }}_{{ kex['hash']|upper }} "{{ curve['pretty_name'] }}" +{%- endfor %} {%- endfor %} #ifdef WITH_OPENSSL #ifdef OPENSSL_HAS_ECC {%- for kex in config['kexs'] -%} - {%- for curve in kex['mix_with'] %} + {%- for curve in kex['mix_with'] if not curve['x25519'] %} #define KEX_{{ kex['name']|upper }}_ECDH_{{ curve['name']|upper }}_{{ kex['hash']|upper }} "{{ curve['pretty_name'] }}" {%- endfor %} {%- endfor %} diff --git a/oqs-template/kexgen.c/add_client_switch_cases.fragment b/oqs-template/kexgen.c/add_client_switch_cases.fragment index 0c5210d2b7d0..bf797f3fb650 100644 --- a/oqs-template/kexgen.c/add_client_switch_cases.fragment +++ b/oqs-template/kexgen.c/add_client_switch_cases.fragment @@ -2,11 +2,16 @@ case KEX_KEM_{{ kex['name']|upper }}_{{ kex['hash']|upper }}: r = kex_kem_{{ kex['name'] }}_keypair(kex); break; +{%- for curve in kex['mix_with'] if curve['x25519'] %} + case KEX_KEM_{{ kex['name']|upper }}_{{ curve['name']|upper }}_{{ kex['hash']|upper }}: + r = kex_kem_{{ kex['name'] }}_{{ curve['name'] }}_keypair(kex); + break; +{%- endfor %} {%- endfor %} #ifdef WITH_OPENSSL #ifdef OPENSSL_HAS_ECC {%- for kex in config['kexs'] -%} - {%- for curve in kex['mix_with'] %} + {%- for curve in kex['mix_with'] if not curve['x25519'] %} case KEX_KEM_{{ kex['name']|upper }}_ECDH_{{ curve['name']|upper }}_{{ kex['hash']|upper }}: r = kex_kem_{{ kex['name'] }}_ecdh_{{ curve['name'] }}_keypair(kex); break; diff --git a/oqs-template/kexgen.c/add_init_switch_cases.fragment b/oqs-template/kexgen.c/add_init_switch_cases.fragment index 9ebaa5544bb5..2d7bd4c66b4f 100644 --- a/oqs-template/kexgen.c/add_init_switch_cases.fragment +++ b/oqs-template/kexgen.c/add_init_switch_cases.fragment @@ -3,11 +3,17 @@ r = kex_kem_{{ kex['name'] }}_enc(kex, client_pubkey, &server_pubkey, &shared_secret); break; +{%- for curve in kex['mix_with'] if curve['x25519'] %} + case KEX_KEM_{{ kex['name']|upper }}_{{ curve['name']|upper }}_{{ kex['hash']|upper }}: + r = kex_kem_{{ kex['name'] }}_{{ curve['name'] }}_enc(kex, client_pubkey, + &server_pubkey, &shared_secret); + break; +{%- endfor %} {%- endfor %} #ifdef WITH_OPENSSL #ifdef OPENSSL_HAS_ECC {%- for kex in config['kexs'] -%} - {%- for curve in kex['mix_with'] %} + {%- for curve in kex['mix_with'] if not curve['x25519'] %} case KEX_KEM_{{ kex['name']|upper }}_ECDH_{{ curve['name']|upper }}_{{ kex['hash']|upper }}: r = kex_kem_{{ kex['name'] }}_ecdh_{{ curve['name'] }}_enc(kex, client_pubkey, &server_pubkey, &shared_secret); diff --git a/oqs-template/kexgen.c/add_reply_switch_cases.fragment b/oqs-template/kexgen.c/add_reply_switch_cases.fragment index 0745aa59f61f..a65cc34c21c4 100644 --- a/oqs-template/kexgen.c/add_reply_switch_cases.fragment +++ b/oqs-template/kexgen.c/add_reply_switch_cases.fragment @@ -2,11 +2,16 @@ case KEX_KEM_{{ kex['name']|upper }}_{{ kex['hash']|upper }}: r = kex_kem_{{ kex['name'] }}_dec(kex, server_blob, &shared_secret); break; +{%- for curve in kex['mix_with'] if curve['x25519'] %} + case KEX_KEM_{{ kex['name']|upper }}_{{ curve['name']|upper }}_{{ kex['hash']|upper }}: + r = kex_kem_{{ kex['name'] }}_{{ curve['name'] }}_dec(kex, server_blob, &shared_secret); + break; +{%- endfor %} {%- endfor %} #ifdef WITH_OPENSSL #ifdef OPENSSL_HAS_ECC {%- for kex in config['kexs'] -%} - {%- for curve in kex['mix_with'] %} + {%- for curve in kex['mix_with'] if not curve['x25519'] %} case KEX_KEM_{{ kex['name']|upper }}_ECDH_{{ curve['name']|upper }}_{{ kex['hash']|upper }}: r = kex_kem_{{ kex['name'] }}_ecdh_{{ curve['name'] }}_dec(kex, server_blob, &shared_secret); break; diff --git a/oqs-template/kexoqsecdh.c/define_kex_with_ec_methods.fragment b/oqs-template/kexoqsecdh.c/define_kex_with_ec_methods.fragment index cb3e83fd3b82..21d592530cc2 100644 --- a/oqs-template/kexoqsecdh.c/define_kex_with_ec_methods.fragment +++ b/oqs-template/kexoqsecdh.c/define_kex_with_ec_methods.fragment @@ -1,5 +1,5 @@ {% for kex in config['kexs'] %} - {%- for curve in kex['mix_with'] %} + {%- for curve in kex['mix_with'] if not curve['x25519'] %} /*--------------------------------------------------------------- * {{ kex['name']|upper }}_ECDH_{{ curve['name']|upper }} METHODS *--------------------------------------------------------------- diff --git a/oqs-template/kexoqsx25519.c/define_kex_with_x25519_methods.fragment b/oqs-template/kexoqsx25519.c/define_kex_with_x25519_methods.fragment new file mode 100644 index 000000000000..198a29e66cb4 --- /dev/null +++ b/oqs-template/kexoqsx25519.c/define_kex_with_x25519_methods.fragment @@ -0,0 +1,46 @@ +{% for kex in config['kexs'] %} + {%- for curve in kex['mix_with'] if curve['x25519'] %} +/*--------------------------------------------------------------- + * {{ kex['name']|upper }}_{{ curve['name']|upper }} METHODS + *--------------------------------------------------------------- + */ +int kex_kem_{{ kex['name'] }}_{{ curve['name'] }}_keypair(struct kex *kex) +{ + OQS_KEM *kem = OQS_KEM_new(OQS_KEM_alg_{{ kex['name'] }}); + if (kem == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + int r = kex_kem_generic_with_x25519_keypair(kem, kex); + OQS_KEM_free(kem); + return r; +} + +int kex_kem_{{ kex['name'] }}_{{ curve['name'] }}_enc(struct kex *kex, + const struct sshbuf *client_blob, + struct sshbuf **server_blobp, + struct sshbuf **shared_secretp) +{ + OQS_KEM *kem = OQS_KEM_new(OQS_KEM_alg_{{ kex['name'] }}); + if (kem == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + int r = kex_kem_generic_with_x25519_enc(kem, kex, client_blob, server_blobp, shared_secretp); + OQS_KEM_free(kem); + return r; +} + +int kex_kem_{{ kex['name'] }}_{{ curve['name'] }}_dec(struct kex *kex, + const struct sshbuf *server_blobp, + struct sshbuf **shared_secretp) +{ + OQS_KEM *kem = OQS_KEM_new(OQS_KEM_alg_{{ kex['name'] }}); + if (kem == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + int r = kex_kem_generic_with_x25519_dec(kem, kex, server_blobp, shared_secretp); + OQS_KEM_free(kem); + return r; +} + {%- endfor %} +{%- endfor %} + diff --git a/oqs-template/monitor.c/apply_keystate.fragment b/oqs-template/monitor.c/apply_keystate.fragment index c0d8330118a2..49b5eb4dba90 100644 --- a/oqs-template/monitor.c/apply_keystate.fragment +++ b/oqs-template/monitor.c/apply_keystate.fragment @@ -1,10 +1,13 @@ {%- for kex in config['kexs'] %} kex->kex[KEX_KEM_{{ kex['name']|upper }}_{{ kex['hash']|upper }}] = kex_gen_server; + {%- for curve in kex['mix_with'] if curve['x25519'] %} + kex->kex[KEX_KEM_{{ kex['name']|upper }}_{{ curve['name']|upper }}_{{ kex['hash']|upper }}] = kex_gen_server; + {%- endfor %} {%- endfor %} #ifdef WITH_OPENSSL #ifdef OPENSSL_HAS_ECC {%- for kex in config['kexs'] -%} - {%- for curve in kex['mix_with'] %} + {%- for curve in kex['mix_with'] if not curve['x25519'] %} kex->kex[KEX_KEM_{{ kex['name']|upper }}_ECDH_{{ curve['name']|upper }}_{{ kex['hash']|upper }}] = kex_gen_server; {%- endfor %} {%- endfor %} diff --git a/oqs-template/ssh-keyscan.c/assign_kex_gen_client.fragment b/oqs-template/ssh-keyscan.c/assign_kex_gen_client.fragment index df1b73346e78..aaa5f3cbb6e0 100644 --- a/oqs-template/ssh-keyscan.c/assign_kex_gen_client.fragment +++ b/oqs-template/ssh-keyscan.c/assign_kex_gen_client.fragment @@ -1,10 +1,13 @@ {%- for kex in config['kexs'] %} c->c_ssh->kex->kex[KEX_KEM_{{ kex['name']|upper }}_{{ kex['hash']|upper }}] = kex_gen_client; + {%- for curve in kex['mix_with'] if curve['x25519'] %} + c->c_ssh->kex->kex[KEX_KEM_{{ kex['name']|upper }}_{{ curve['name']|upper }}_{{ kex['hash']|upper }}] = kex_gen_client; + {%- endfor %} {%- endfor %} #ifdef WITH_OPENSSL #ifdef OPENSSL_HAS_ECC {%- for kex in config['kexs'] -%} - {%- for curve in kex['mix_with'] %} + {%- for curve in kex['mix_with'] if not curve['x25519'] %} c->c_ssh->kex->kex[KEX_KEM_{{ kex['name']|upper }}_ECDH_{{ curve['name']|upper }}_{{ kex['hash']|upper }}] = kex_gen_client; {%- endfor %} {%- endfor %} diff --git a/oqs-template/ssh_api.c/point_to_kex_gen_client.fragment b/oqs-template/ssh_api.c/point_to_kex_gen_client.fragment index 1678e9f1f383..32857cbe04e7 100644 --- a/oqs-template/ssh_api.c/point_to_kex_gen_client.fragment +++ b/oqs-template/ssh_api.c/point_to_kex_gen_client.fragment @@ -1,10 +1,13 @@ {%- for kex in config['kexs'] %} ssh->kex->kex[KEX_KEM_{{ kex['name']|upper }}_{{ kex['hash']|upper }}] = kex_gen_client; + {%- for curve in kex['mix_with'] if curve['x25519'] %} + ssh->kex->kex[KEX_KEM_{{ kex['name']|upper }}_{{ curve['name']|upper }}_{{ kex['hash']|upper }}] = kex_gen_client; + {%- endfor %} {%- endfor %} #ifdef WITH_OPENSSL #ifdef OPENSSL_HAS_ECC {%- for kex in config['kexs'] -%} - {%- for curve in kex['mix_with'] %} + {%- for curve in kex['mix_with'] if not curve['x25519'] %} ssh->kex->kex[KEX_KEM_{{ kex['name']|upper }}_ECDH_{{ curve['name']|upper }}_{{ kex['hash']|upper }}] = kex_gen_client; {%- endfor %} {%- endfor %} diff --git a/oqs-template/ssh_api.c/point_to_kex_gen_server.fragment b/oqs-template/ssh_api.c/point_to_kex_gen_server.fragment index 3e9a6c578d00..8fc556bcd484 100644 --- a/oqs-template/ssh_api.c/point_to_kex_gen_server.fragment +++ b/oqs-template/ssh_api.c/point_to_kex_gen_server.fragment @@ -1,10 +1,13 @@ {%- for kex in config['kexs'] %} ssh->kex->kex[KEX_KEM_{{ kex['name']|upper }}_{{ kex['hash']|upper }}] = kex_gen_server; + {%- for curve in kex['mix_with'] if curve['x25519'] %} + ssh->kex->kex[KEX_KEM_{{ kex['name']|upper }}_{{ curve['name']|upper }}_{{ kex['hash']|upper }}] = kex_gen_server; + {%- endfor %} {%- endfor %} #ifdef WITH_OPENSSL #ifdef OPENSSL_HAS_ECC {%- for kex in config['kexs'] -%} - {%- for curve in kex['mix_with'] %} + {%- for curve in kex['mix_with'] if not curve['x25519'] %} ssh->kex->kex[KEX_KEM_{{ kex['name']|upper }}_ECDH_{{ curve['name']|upper }}_{{ kex['hash']|upper }}] = kex_gen_server; {%- endfor %} {%- endfor %} diff --git a/oqs-template/sshconnect2.c/point_to_kex_gen.fragment b/oqs-template/sshconnect2.c/point_to_kex_gen.fragment index 8721232b3859..0786322ef3ec 100644 --- a/oqs-template/sshconnect2.c/point_to_kex_gen.fragment +++ b/oqs-template/sshconnect2.c/point_to_kex_gen.fragment @@ -1,10 +1,13 @@ {%- for kex in config['kexs'] %} ssh->kex->kex[KEX_KEM_{{ kex['name']|upper }}_{{ kex['hash']|upper }}] = kex_gen_client; + {%- for curve in kex['mix_with'] if curve['x25519'] %} + ssh->kex->kex[KEX_KEM_{{ kex['name']|upper }}_{{ curve['name']|upper }}_{{ kex['hash']|upper }}] = kex_gen_client; + {%- endfor %} {%- endfor %} #ifdef WITH_OPENSSL #ifdef OPENSSL_HAS_ECC {%- for kex in config['kexs'] -%} - {%- for curve in kex['mix_with'] %} + {%- for curve in kex['mix_with'] if not curve['x25519'] %} ssh->kex->kex[KEX_KEM_{{ kex['name']|upper }}_ECDH_{{ curve['name']|upper }}_{{ kex['hash']|upper }}] = kex_gen_client; {%- endfor %} {%- endfor %} diff --git a/oqs-template/sshd.c/point_to_kex_gen.fragment b/oqs-template/sshd.c/point_to_kex_gen.fragment index 8ad24cae5fe2..81e41cd31f12 100644 --- a/oqs-template/sshd.c/point_to_kex_gen.fragment +++ b/oqs-template/sshd.c/point_to_kex_gen.fragment @@ -1,10 +1,13 @@ {%- for kex in config['kexs'] %} kex->kex[KEX_KEM_{{ kex['name']|upper }}_{{ kex['hash']|upper }}] = kex_gen_server; + {%- for curve in kex['mix_with'] if curve['x25519'] %} + kex->kex[KEX_KEM_{{ kex['name']|upper }}_{{ curve['name']|upper }}_{{ kex['hash']|upper }}] = kex_gen_server; + {%- endfor %} {%- endfor %} #ifdef WITH_OPENSSL #ifdef OPENSSL_HAS_ECC {%- for kex in config['kexs'] -%} - {%- for curve in kex['mix_with'] %} + {%- for curve in kex['mix_with'] if not curve['x25519'] %} kex->kex[KEX_KEM_{{ kex['name']|upper }}_ECDH_{{ curve['name']|upper }}_{{ kex['hash']|upper }}] = kex_gen_server; {%- endfor %} {%- endfor %} diff --git a/oqs-test/try_connection.py b/oqs-test/try_connection.py index 7671ee8d3c46..fe4c210ee495 100644 --- a/oqs-test/try_connection.py +++ b/oqs-test/try_connection.py @@ -15,32 +15,38 @@ ##### OQS_TEMPLATE_FRAGMENT_LIST_ALL_KEXS_START "frodokem-640-aes-sha256", "ecdh-nistp256-frodokem-640-aesr2-sha256@openquantumsafe.org", + "x25519-frodokem-640-aesr2-sha256@openquantumsafe.org", "frodokem-976-aes-sha384", "ecdh-nistp384-frodokem-976-aesr2-sha384@openquantumsafe.org", "frodokem-1344-aes-sha512", "ecdh-nistp521-frodokem-1344-aesr2-sha512@openquantumsafe.org", "frodokem-640-shake-sha256", "ecdh-nistp256-frodokem-640-shaker2-sha256@openquantumsafe.org", + "x25519-frodokem-640-shaker2-sha256@openquantumsafe.org", "frodokem-976-shake-sha384", "ecdh-nistp384-frodokem-976-shaker2-sha384@openquantumsafe.org", "frodokem-1344-shake-sha512", "ecdh-nistp521-frodokem-1344-shaker2-sha512@openquantumsafe.org", "kyber-512-sha256", "ecdh-nistp256-kyber-512r3-sha256-d00@openquantumsafe.org", + "x25519-kyber-512r3-sha256-d00@amazon.com", "kyber-768-sha384", "ecdh-nistp384-kyber-768r3-sha384-d00@openquantumsafe.org", "kyber-1024-sha512", "ecdh-nistp521-kyber-1024r3-sha512-d00@openquantumsafe.org", "bike-l1-sha512", "ecdh-nistp256-bike-l1r4-sha512@openquantumsafe.org", + "x25519-bike-l1r4-sha512@openquantumsafe.org", "bike-l3-sha512", "ecdh-nistp384-bike-l3r4-sha512@openquantumsafe.org", "bike-l5-sha512", "ecdh-nistp521-bike-l5r4-sha512@openquantumsafe.org", "classic-mceliece-348864-sha256", "ecdh-nistp256-classic-mceliece-348864r4-sha256@openquantumsafe.org", + "x25519-classic-mceliece-348864r4-sha256@openquantumsafe.org", "classic-mceliece-348864f-sha256", "ecdh-nistp256-classic-mceliece-348864fr4-sha256@openquantumsafe.org", + "x25519-classic-mceliece-348864fr4-sha256@openquantumsafe.org", "classic-mceliece-460896-sha512", "ecdh-nistp384-classic-mceliece-460896r4-sha512@openquantumsafe.org", "classic-mceliece-460896f-sha512", @@ -59,14 +65,17 @@ "ecdh-nistp521-classic-mceliece-8192128fr4-sha512@openquantumsafe.org", "hqc-128-sha256", "ecdh-nistp256-hqc-128r3-sha256@openquantumsafe.org", + "x25519-hqc-128r3-sha256@openquantumsafe.org", "hqc-192-sha384", "ecdh-nistp384-hqc-192r3-sha384@openquantumsafe.org", "hqc-256-sha512", "ecdh-nistp521-hqc-256r3-sha512@openquantumsafe.org", "ml-kem-512-sha256", "ecdh-nistp256-ml-kem-512-sha256@openquantumsafe.org", + "x25519-ml-kem-512-sha256@openquantumsafe.org", "ml-kem-768-sha256", "mlkem768nistp256-sha256", + "mlkem768x25519-sha256", "ml-kem-1024-sha384", "mlkem1024nistp384-sha384", ##### OQS_TEMPLATE_FRAGMENT_LIST_ALL_KEXS_END diff --git a/ssh-keyscan.c b/ssh-keyscan.c index ae796e1a52c3..635ebc13bbb5 100644 --- a/ssh-keyscan.c +++ b/ssh-keyscan.c @@ -438,19 +438,25 @@ keygrab_ssh2(con *c) c->c_ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client; ///// OQS_TEMPLATE_FRAGMENT_ASSIGN_KEX_GEN_CLIENT_START c->c_ssh->kex->kex[KEX_KEM_FRODOKEM_640_AES_SHA256] = kex_gen_client; + c->c_ssh->kex->kex[KEX_KEM_FRODOKEM_640_AES_X25519_SHA256] = kex_gen_client; c->c_ssh->kex->kex[KEX_KEM_FRODOKEM_976_AES_SHA384] = kex_gen_client; c->c_ssh->kex->kex[KEX_KEM_FRODOKEM_1344_AES_SHA512] = kex_gen_client; c->c_ssh->kex->kex[KEX_KEM_FRODOKEM_640_SHAKE_SHA256] = kex_gen_client; + c->c_ssh->kex->kex[KEX_KEM_FRODOKEM_640_SHAKE_X25519_SHA256] = kex_gen_client; c->c_ssh->kex->kex[KEX_KEM_FRODOKEM_976_SHAKE_SHA384] = kex_gen_client; c->c_ssh->kex->kex[KEX_KEM_FRODOKEM_1344_SHAKE_SHA512] = kex_gen_client; c->c_ssh->kex->kex[KEX_KEM_KYBER_512_SHA256] = kex_gen_client; + c->c_ssh->kex->kex[KEX_KEM_KYBER_512_X25519_SHA256] = kex_gen_client; c->c_ssh->kex->kex[KEX_KEM_KYBER_768_SHA384] = kex_gen_client; c->c_ssh->kex->kex[KEX_KEM_KYBER_1024_SHA512] = kex_gen_client; c->c_ssh->kex->kex[KEX_KEM_BIKE_L1_SHA512] = kex_gen_client; + c->c_ssh->kex->kex[KEX_KEM_BIKE_L1_X25519_SHA512] = kex_gen_client; c->c_ssh->kex->kex[KEX_KEM_BIKE_L3_SHA512] = kex_gen_client; c->c_ssh->kex->kex[KEX_KEM_BIKE_L5_SHA512] = kex_gen_client; c->c_ssh->kex->kex[KEX_KEM_CLASSIC_MCELIECE_348864_SHA256] = kex_gen_client; + c->c_ssh->kex->kex[KEX_KEM_CLASSIC_MCELIECE_348864_X25519_SHA256] = kex_gen_client; c->c_ssh->kex->kex[KEX_KEM_CLASSIC_MCELIECE_348864F_SHA256] = kex_gen_client; + c->c_ssh->kex->kex[KEX_KEM_CLASSIC_MCELIECE_348864F_X25519_SHA256] = kex_gen_client; c->c_ssh->kex->kex[KEX_KEM_CLASSIC_MCELIECE_460896_SHA512] = kex_gen_client; c->c_ssh->kex->kex[KEX_KEM_CLASSIC_MCELIECE_460896F_SHA512] = kex_gen_client; c->c_ssh->kex->kex[KEX_KEM_CLASSIC_MCELIECE_6688128_SHA512] = kex_gen_client; @@ -460,10 +466,13 @@ keygrab_ssh2(con *c) c->c_ssh->kex->kex[KEX_KEM_CLASSIC_MCELIECE_8192128_SHA512] = kex_gen_client; c->c_ssh->kex->kex[KEX_KEM_CLASSIC_MCELIECE_8192128F_SHA512] = kex_gen_client; c->c_ssh->kex->kex[KEX_KEM_HQC_128_SHA256] = kex_gen_client; + c->c_ssh->kex->kex[KEX_KEM_HQC_128_X25519_SHA256] = kex_gen_client; c->c_ssh->kex->kex[KEX_KEM_HQC_192_SHA384] = kex_gen_client; c->c_ssh->kex->kex[KEX_KEM_HQC_256_SHA512] = kex_gen_client; c->c_ssh->kex->kex[KEX_KEM_ML_KEM_512_SHA256] = kex_gen_client; + c->c_ssh->kex->kex[KEX_KEM_ML_KEM_512_X25519_SHA256] = kex_gen_client; c->c_ssh->kex->kex[KEX_KEM_ML_KEM_768_SHA256] = kex_gen_client; + c->c_ssh->kex->kex[KEX_KEM_ML_KEM_768_X25519_SHA256] = kex_gen_client; c->c_ssh->kex->kex[KEX_KEM_ML_KEM_1024_SHA384] = kex_gen_client; #ifdef WITH_OPENSSL #ifdef OPENSSL_HAS_ECC diff --git a/ssh_api.c b/ssh_api.c index a6df19118953..9ddbccad2914 100644 --- a/ssh_api.c +++ b/ssh_api.c @@ -131,19 +131,25 @@ ssh_init(struct ssh **sshp, int is_server, struct kex_params *kex_params) ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_server; ///// OQS_TEMPLATE_FRAGMENT_POINT_TO_KEX_GEN_SERVER_START ssh->kex->kex[KEX_KEM_FRODOKEM_640_AES_SHA256] = kex_gen_server; + ssh->kex->kex[KEX_KEM_FRODOKEM_640_AES_X25519_SHA256] = kex_gen_server; ssh->kex->kex[KEX_KEM_FRODOKEM_976_AES_SHA384] = kex_gen_server; ssh->kex->kex[KEX_KEM_FRODOKEM_1344_AES_SHA512] = kex_gen_server; ssh->kex->kex[KEX_KEM_FRODOKEM_640_SHAKE_SHA256] = kex_gen_server; + ssh->kex->kex[KEX_KEM_FRODOKEM_640_SHAKE_X25519_SHA256] = kex_gen_server; ssh->kex->kex[KEX_KEM_FRODOKEM_976_SHAKE_SHA384] = kex_gen_server; ssh->kex->kex[KEX_KEM_FRODOKEM_1344_SHAKE_SHA512] = kex_gen_server; ssh->kex->kex[KEX_KEM_KYBER_512_SHA256] = kex_gen_server; + ssh->kex->kex[KEX_KEM_KYBER_512_X25519_SHA256] = kex_gen_server; ssh->kex->kex[KEX_KEM_KYBER_768_SHA384] = kex_gen_server; ssh->kex->kex[KEX_KEM_KYBER_1024_SHA512] = kex_gen_server; ssh->kex->kex[KEX_KEM_BIKE_L1_SHA512] = kex_gen_server; + ssh->kex->kex[KEX_KEM_BIKE_L1_X25519_SHA512] = kex_gen_server; ssh->kex->kex[KEX_KEM_BIKE_L3_SHA512] = kex_gen_server; ssh->kex->kex[KEX_KEM_BIKE_L5_SHA512] = kex_gen_server; ssh->kex->kex[KEX_KEM_CLASSIC_MCELIECE_348864_SHA256] = kex_gen_server; + ssh->kex->kex[KEX_KEM_CLASSIC_MCELIECE_348864_X25519_SHA256] = kex_gen_server; ssh->kex->kex[KEX_KEM_CLASSIC_MCELIECE_348864F_SHA256] = kex_gen_server; + ssh->kex->kex[KEX_KEM_CLASSIC_MCELIECE_348864F_X25519_SHA256] = kex_gen_server; ssh->kex->kex[KEX_KEM_CLASSIC_MCELIECE_460896_SHA512] = kex_gen_server; ssh->kex->kex[KEX_KEM_CLASSIC_MCELIECE_460896F_SHA512] = kex_gen_server; ssh->kex->kex[KEX_KEM_CLASSIC_MCELIECE_6688128_SHA512] = kex_gen_server; @@ -153,10 +159,13 @@ ssh_init(struct ssh **sshp, int is_server, struct kex_params *kex_params) ssh->kex->kex[KEX_KEM_CLASSIC_MCELIECE_8192128_SHA512] = kex_gen_server; ssh->kex->kex[KEX_KEM_CLASSIC_MCELIECE_8192128F_SHA512] = kex_gen_server; ssh->kex->kex[KEX_KEM_HQC_128_SHA256] = kex_gen_server; + ssh->kex->kex[KEX_KEM_HQC_128_X25519_SHA256] = kex_gen_server; ssh->kex->kex[KEX_KEM_HQC_192_SHA384] = kex_gen_server; ssh->kex->kex[KEX_KEM_HQC_256_SHA512] = kex_gen_server; ssh->kex->kex[KEX_KEM_ML_KEM_512_SHA256] = kex_gen_server; + ssh->kex->kex[KEX_KEM_ML_KEM_512_X25519_SHA256] = kex_gen_server; ssh->kex->kex[KEX_KEM_ML_KEM_768_SHA256] = kex_gen_server; + ssh->kex->kex[KEX_KEM_ML_KEM_768_X25519_SHA256] = kex_gen_server; ssh->kex->kex[KEX_KEM_ML_KEM_1024_SHA384] = kex_gen_server; #ifdef WITH_OPENSSL #ifdef OPENSSL_HAS_ECC @@ -211,19 +220,25 @@ ssh_init(struct ssh **sshp, int is_server, struct kex_params *kex_params) ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client; ///// OQS_TEMPLATE_FRAGMENT_POINT_TO_KEX_GEN_CLIENT_START ssh->kex->kex[KEX_KEM_FRODOKEM_640_AES_SHA256] = kex_gen_client; + ssh->kex->kex[KEX_KEM_FRODOKEM_640_AES_X25519_SHA256] = kex_gen_client; ssh->kex->kex[KEX_KEM_FRODOKEM_976_AES_SHA384] = kex_gen_client; ssh->kex->kex[KEX_KEM_FRODOKEM_1344_AES_SHA512] = kex_gen_client; ssh->kex->kex[KEX_KEM_FRODOKEM_640_SHAKE_SHA256] = kex_gen_client; + ssh->kex->kex[KEX_KEM_FRODOKEM_640_SHAKE_X25519_SHA256] = kex_gen_client; ssh->kex->kex[KEX_KEM_FRODOKEM_976_SHAKE_SHA384] = kex_gen_client; ssh->kex->kex[KEX_KEM_FRODOKEM_1344_SHAKE_SHA512] = kex_gen_client; ssh->kex->kex[KEX_KEM_KYBER_512_SHA256] = kex_gen_client; + ssh->kex->kex[KEX_KEM_KYBER_512_X25519_SHA256] = kex_gen_client; ssh->kex->kex[KEX_KEM_KYBER_768_SHA384] = kex_gen_client; ssh->kex->kex[KEX_KEM_KYBER_1024_SHA512] = kex_gen_client; ssh->kex->kex[KEX_KEM_BIKE_L1_SHA512] = kex_gen_client; + ssh->kex->kex[KEX_KEM_BIKE_L1_X25519_SHA512] = kex_gen_client; ssh->kex->kex[KEX_KEM_BIKE_L3_SHA512] = kex_gen_client; ssh->kex->kex[KEX_KEM_BIKE_L5_SHA512] = kex_gen_client; ssh->kex->kex[KEX_KEM_CLASSIC_MCELIECE_348864_SHA256] = kex_gen_client; + ssh->kex->kex[KEX_KEM_CLASSIC_MCELIECE_348864_X25519_SHA256] = kex_gen_client; ssh->kex->kex[KEX_KEM_CLASSIC_MCELIECE_348864F_SHA256] = kex_gen_client; + ssh->kex->kex[KEX_KEM_CLASSIC_MCELIECE_348864F_X25519_SHA256] = kex_gen_client; ssh->kex->kex[KEX_KEM_CLASSIC_MCELIECE_460896_SHA512] = kex_gen_client; ssh->kex->kex[KEX_KEM_CLASSIC_MCELIECE_460896F_SHA512] = kex_gen_client; ssh->kex->kex[KEX_KEM_CLASSIC_MCELIECE_6688128_SHA512] = kex_gen_client; @@ -233,10 +248,13 @@ ssh_init(struct ssh **sshp, int is_server, struct kex_params *kex_params) ssh->kex->kex[KEX_KEM_CLASSIC_MCELIECE_8192128_SHA512] = kex_gen_client; ssh->kex->kex[KEX_KEM_CLASSIC_MCELIECE_8192128F_SHA512] = kex_gen_client; ssh->kex->kex[KEX_KEM_HQC_128_SHA256] = kex_gen_client; + ssh->kex->kex[KEX_KEM_HQC_128_X25519_SHA256] = kex_gen_client; ssh->kex->kex[KEX_KEM_HQC_192_SHA384] = kex_gen_client; ssh->kex->kex[KEX_KEM_HQC_256_SHA512] = kex_gen_client; ssh->kex->kex[KEX_KEM_ML_KEM_512_SHA256] = kex_gen_client; + ssh->kex->kex[KEX_KEM_ML_KEM_512_X25519_SHA256] = kex_gen_client; ssh->kex->kex[KEX_KEM_ML_KEM_768_SHA256] = kex_gen_client; + ssh->kex->kex[KEX_KEM_ML_KEM_768_X25519_SHA256] = kex_gen_client; ssh->kex->kex[KEX_KEM_ML_KEM_1024_SHA384] = kex_gen_client; #ifdef WITH_OPENSSL #ifdef OPENSSL_HAS_ECC diff --git a/sshconnect2.c b/sshconnect2.c index 17a922c5afde..c67007466672 100644 --- a/sshconnect2.c +++ b/sshconnect2.c @@ -279,19 +279,25 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port, ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client; ///// OQS_TEMPLATE_FRAGMENT_POINT_TO_KEX_GEN_START ssh->kex->kex[KEX_KEM_FRODOKEM_640_AES_SHA256] = kex_gen_client; + ssh->kex->kex[KEX_KEM_FRODOKEM_640_AES_X25519_SHA256] = kex_gen_client; ssh->kex->kex[KEX_KEM_FRODOKEM_976_AES_SHA384] = kex_gen_client; ssh->kex->kex[KEX_KEM_FRODOKEM_1344_AES_SHA512] = kex_gen_client; ssh->kex->kex[KEX_KEM_FRODOKEM_640_SHAKE_SHA256] = kex_gen_client; + ssh->kex->kex[KEX_KEM_FRODOKEM_640_SHAKE_X25519_SHA256] = kex_gen_client; ssh->kex->kex[KEX_KEM_FRODOKEM_976_SHAKE_SHA384] = kex_gen_client; ssh->kex->kex[KEX_KEM_FRODOKEM_1344_SHAKE_SHA512] = kex_gen_client; ssh->kex->kex[KEX_KEM_KYBER_512_SHA256] = kex_gen_client; + ssh->kex->kex[KEX_KEM_KYBER_512_X25519_SHA256] = kex_gen_client; ssh->kex->kex[KEX_KEM_KYBER_768_SHA384] = kex_gen_client; ssh->kex->kex[KEX_KEM_KYBER_1024_SHA512] = kex_gen_client; ssh->kex->kex[KEX_KEM_BIKE_L1_SHA512] = kex_gen_client; + ssh->kex->kex[KEX_KEM_BIKE_L1_X25519_SHA512] = kex_gen_client; ssh->kex->kex[KEX_KEM_BIKE_L3_SHA512] = kex_gen_client; ssh->kex->kex[KEX_KEM_BIKE_L5_SHA512] = kex_gen_client; ssh->kex->kex[KEX_KEM_CLASSIC_MCELIECE_348864_SHA256] = kex_gen_client; + ssh->kex->kex[KEX_KEM_CLASSIC_MCELIECE_348864_X25519_SHA256] = kex_gen_client; ssh->kex->kex[KEX_KEM_CLASSIC_MCELIECE_348864F_SHA256] = kex_gen_client; + ssh->kex->kex[KEX_KEM_CLASSIC_MCELIECE_348864F_X25519_SHA256] = kex_gen_client; ssh->kex->kex[KEX_KEM_CLASSIC_MCELIECE_460896_SHA512] = kex_gen_client; ssh->kex->kex[KEX_KEM_CLASSIC_MCELIECE_460896F_SHA512] = kex_gen_client; ssh->kex->kex[KEX_KEM_CLASSIC_MCELIECE_6688128_SHA512] = kex_gen_client; @@ -301,10 +307,13 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port, ssh->kex->kex[KEX_KEM_CLASSIC_MCELIECE_8192128_SHA512] = kex_gen_client; ssh->kex->kex[KEX_KEM_CLASSIC_MCELIECE_8192128F_SHA512] = kex_gen_client; ssh->kex->kex[KEX_KEM_HQC_128_SHA256] = kex_gen_client; + ssh->kex->kex[KEX_KEM_HQC_128_X25519_SHA256] = kex_gen_client; ssh->kex->kex[KEX_KEM_HQC_192_SHA384] = kex_gen_client; ssh->kex->kex[KEX_KEM_HQC_256_SHA512] = kex_gen_client; ssh->kex->kex[KEX_KEM_ML_KEM_512_SHA256] = kex_gen_client; + ssh->kex->kex[KEX_KEM_ML_KEM_512_X25519_SHA256] = kex_gen_client; ssh->kex->kex[KEX_KEM_ML_KEM_768_SHA256] = kex_gen_client; + ssh->kex->kex[KEX_KEM_ML_KEM_768_X25519_SHA256] = kex_gen_client; ssh->kex->kex[KEX_KEM_ML_KEM_1024_SHA384] = kex_gen_client; #ifdef WITH_OPENSSL #ifdef OPENSSL_HAS_ECC diff --git a/sshd.c b/sshd.c index 5b3274c185c4..200b775d01fb 100644 --- a/sshd.c +++ b/sshd.c @@ -2432,19 +2432,25 @@ do_ssh2_kex(struct ssh *ssh) kex->kex[KEX_C25519_SHA256] = kex_gen_server; ///// OQS_TEMPLATE_FRAGMENT_POINT_TO_KEX_GEN_START kex->kex[KEX_KEM_FRODOKEM_640_AES_SHA256] = kex_gen_server; + kex->kex[KEX_KEM_FRODOKEM_640_AES_X25519_SHA256] = kex_gen_server; kex->kex[KEX_KEM_FRODOKEM_976_AES_SHA384] = kex_gen_server; kex->kex[KEX_KEM_FRODOKEM_1344_AES_SHA512] = kex_gen_server; kex->kex[KEX_KEM_FRODOKEM_640_SHAKE_SHA256] = kex_gen_server; + kex->kex[KEX_KEM_FRODOKEM_640_SHAKE_X25519_SHA256] = kex_gen_server; kex->kex[KEX_KEM_FRODOKEM_976_SHAKE_SHA384] = kex_gen_server; kex->kex[KEX_KEM_FRODOKEM_1344_SHAKE_SHA512] = kex_gen_server; kex->kex[KEX_KEM_KYBER_512_SHA256] = kex_gen_server; + kex->kex[KEX_KEM_KYBER_512_X25519_SHA256] = kex_gen_server; kex->kex[KEX_KEM_KYBER_768_SHA384] = kex_gen_server; kex->kex[KEX_KEM_KYBER_1024_SHA512] = kex_gen_server; kex->kex[KEX_KEM_BIKE_L1_SHA512] = kex_gen_server; + kex->kex[KEX_KEM_BIKE_L1_X25519_SHA512] = kex_gen_server; kex->kex[KEX_KEM_BIKE_L3_SHA512] = kex_gen_server; kex->kex[KEX_KEM_BIKE_L5_SHA512] = kex_gen_server; kex->kex[KEX_KEM_CLASSIC_MCELIECE_348864_SHA256] = kex_gen_server; + kex->kex[KEX_KEM_CLASSIC_MCELIECE_348864_X25519_SHA256] = kex_gen_server; kex->kex[KEX_KEM_CLASSIC_MCELIECE_348864F_SHA256] = kex_gen_server; + kex->kex[KEX_KEM_CLASSIC_MCELIECE_348864F_X25519_SHA256] = kex_gen_server; kex->kex[KEX_KEM_CLASSIC_MCELIECE_460896_SHA512] = kex_gen_server; kex->kex[KEX_KEM_CLASSIC_MCELIECE_460896F_SHA512] = kex_gen_server; kex->kex[KEX_KEM_CLASSIC_MCELIECE_6688128_SHA512] = kex_gen_server; @@ -2454,10 +2460,13 @@ do_ssh2_kex(struct ssh *ssh) kex->kex[KEX_KEM_CLASSIC_MCELIECE_8192128_SHA512] = kex_gen_server; kex->kex[KEX_KEM_CLASSIC_MCELIECE_8192128F_SHA512] = kex_gen_server; kex->kex[KEX_KEM_HQC_128_SHA256] = kex_gen_server; + kex->kex[KEX_KEM_HQC_128_X25519_SHA256] = kex_gen_server; kex->kex[KEX_KEM_HQC_192_SHA384] = kex_gen_server; kex->kex[KEX_KEM_HQC_256_SHA512] = kex_gen_server; kex->kex[KEX_KEM_ML_KEM_512_SHA256] = kex_gen_server; + kex->kex[KEX_KEM_ML_KEM_512_X25519_SHA256] = kex_gen_server; kex->kex[KEX_KEM_ML_KEM_768_SHA256] = kex_gen_server; + kex->kex[KEX_KEM_ML_KEM_768_X25519_SHA256] = kex_gen_server; kex->kex[KEX_KEM_ML_KEM_1024_SHA384] = kex_gen_server; #ifdef WITH_OPENSSL #ifdef OPENSSL_HAS_ECC