mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-02-12 11:10:28 +09:00
Native ML-KEM768 implementation
for cryptographic backends that do not have support for ML-KEM (old OpenSSL and Gcrypt; MbedTLS). Based on the libcrux implementation used in OpenSSH, taken from this revision: https://github.com/openssh/openssh-portable/blob/6aba700/libcrux_mlkem768_sha3.h But refactored to separate C and header file to support testing and removed unused functions (to make compiler happy). Signed-off-by: Jakub Jelen <jjelen@redhat.com> Reviewed-by: Andreas Schneider <asn@cryptomilk.org> Reviewed-by: Pavol Žáčik <pzacik@redhat.com>
This commit is contained in:
@@ -105,6 +105,7 @@ set(libssh_SRCS
|
||||
error.c
|
||||
getpass.c
|
||||
gzip.c
|
||||
hybrid_mlkem.c
|
||||
init.c
|
||||
kdf.c
|
||||
kex.c
|
||||
@@ -115,6 +116,7 @@ set(libssh_SRCS
|
||||
match.c
|
||||
messages.c
|
||||
misc.c
|
||||
mlkem.c
|
||||
options.c
|
||||
packet.c
|
||||
packet_cb.c
|
||||
@@ -196,12 +198,12 @@ if (WITH_GCRYPT)
|
||||
)
|
||||
endif(HAVE_GCRYPT_CURVE25519)
|
||||
|
||||
if (HAVE_MLKEM)
|
||||
if (HAVE_GCRYPT_MLKEM)
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
mlkem_gcrypt.c
|
||||
)
|
||||
endif (HAVE_MLKEM)
|
||||
endif (HAVE_GCRYPT_MLKEM)
|
||||
elseif (WITH_MBEDTLS)
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
@@ -255,12 +257,12 @@ else (WITH_GCRYPT)
|
||||
chachapoly.c
|
||||
)
|
||||
endif (NOT HAVE_OPENSSL_EVP_CHACHA20)
|
||||
if (HAVE_MLKEM)
|
||||
if (HAVE_OPENSSL_MLKEM)
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
mlkem_crypto.c
|
||||
)
|
||||
endif (HAVE_MLKEM)
|
||||
endif (HAVE_OPENSSL_MLKEM)
|
||||
endif (WITH_GCRYPT)
|
||||
|
||||
if (WITH_SFTP)
|
||||
@@ -313,13 +315,18 @@ if (NOT WITH_NACL)
|
||||
endif()
|
||||
endif (NOT WITH_NACL)
|
||||
|
||||
if (HAVE_MLKEM)
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
hybrid_mlkem.c
|
||||
mlkem.c
|
||||
)
|
||||
endif (HAVE_MLKEM)
|
||||
if (NOT HAVE_MLKEM1024)
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
mlkem_native.c
|
||||
external/libcrux_mlkem768_sha3.c
|
||||
)
|
||||
if (WITH_WERROR_DECLARATION_AFTER_STATEMENT_FLAG)
|
||||
set_source_files_properties(external/libcrux_mlkem768_sha3.c
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS -Wno-error=declaration-after-statement)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (WITH_FIDO2)
|
||||
set(libssh_SRCS
|
||||
|
||||
@@ -47,9 +47,7 @@
|
||||
#include "libssh/misc.h"
|
||||
#include "libssh/pki.h"
|
||||
#include "libssh/kex.h"
|
||||
#ifdef HAVE_MLKEM
|
||||
#include "libssh/hybrid_mlkem.h"
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
#ifdef HAVE_PTHREAD
|
||||
@@ -308,13 +306,13 @@ int dh_handshake(ssh_session session)
|
||||
rc = ssh_client_sntrup761x25519_init(session);
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_MLKEM
|
||||
case SSH_KEX_MLKEM768X25519_SHA256:
|
||||
case SSH_KEX_MLKEM768NISTP256_SHA256:
|
||||
#ifdef HAVE_MLKEM1024
|
||||
case SSH_KEX_MLKEM1024NISTP384_SHA384:
|
||||
#endif
|
||||
rc = ssh_client_hybrid_mlkem_init(session);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
rc = SSH_ERROR;
|
||||
}
|
||||
|
||||
@@ -53,13 +53,11 @@ static const char *ecdh_kex_type_to_curve(enum ssh_key_exchange_e kex_type) {
|
||||
#endif /* OPENSSL_VERSION_NUMBER */
|
||||
switch (kex_type) {
|
||||
case SSH_KEX_ECDH_SHA2_NISTP256:
|
||||
#ifdef HAVE_MLKEM
|
||||
case SSH_KEX_MLKEM768NISTP256_SHA256:
|
||||
#endif
|
||||
case SSH_GSS_KEX_ECDH_NISTP256_SHA256:
|
||||
return NISTP256;
|
||||
case SSH_KEX_ECDH_SHA2_NISTP384:
|
||||
#ifdef HAVE_MLKEM
|
||||
#if HAVE_MLKEM1024
|
||||
case SSH_KEX_MLKEM1024NISTP384_SHA384:
|
||||
#endif
|
||||
return NISTP384;
|
||||
|
||||
@@ -41,12 +41,10 @@ static const char *ecdh_kex_type_to_curve(enum ssh_key_exchange_e kex_type)
|
||||
switch (kex_type) {
|
||||
case SSH_KEX_ECDH_SHA2_NISTP256:
|
||||
case SSH_GSS_KEX_ECDH_NISTP256_SHA256:
|
||||
#ifdef HAVE_MLKEM
|
||||
case SSH_KEX_MLKEM768NISTP256_SHA256:
|
||||
#endif
|
||||
return "NIST P-256";
|
||||
case SSH_KEX_ECDH_SHA2_NISTP384:
|
||||
#ifdef HAVE_MLKEM
|
||||
#if HAVE_MLKEM1024
|
||||
case SSH_KEX_MLKEM1024NISTP384_SHA384:
|
||||
#endif
|
||||
return "NIST P-384";
|
||||
|
||||
@@ -38,16 +38,21 @@
|
||||
|
||||
#ifdef HAVE_ECDH
|
||||
|
||||
static mbedtls_ecp_group_id ecdh_kex_type_to_curve(enum ssh_key_exchange_e kex_type) {
|
||||
if (kex_type == SSH_KEX_ECDH_SHA2_NISTP256 ||
|
||||
kex_type == SSH_GSS_KEX_ECDH_NISTP256_SHA256) {
|
||||
static mbedtls_ecp_group_id
|
||||
ecdh_kex_type_to_curve(enum ssh_key_exchange_e kex_type)
|
||||
{
|
||||
switch (kex_type) {
|
||||
case SSH_KEX_ECDH_SHA2_NISTP256:
|
||||
case SSH_KEX_MLKEM768NISTP256_SHA256:
|
||||
case SSH_GSS_KEX_ECDH_NISTP256_SHA256:
|
||||
return MBEDTLS_ECP_DP_SECP256R1;
|
||||
} else if (kex_type == SSH_KEX_ECDH_SHA2_NISTP384) {
|
||||
case SSH_KEX_ECDH_SHA2_NISTP384:
|
||||
return MBEDTLS_ECP_DP_SECP384R1;
|
||||
} else if (kex_type == SSH_KEX_ECDH_SHA2_NISTP521) {
|
||||
case SSH_KEX_ECDH_SHA2_NISTP521:
|
||||
return MBEDTLS_ECP_DP_SECP521R1;
|
||||
default:
|
||||
return MBEDTLS_ECP_DP_NONE;
|
||||
}
|
||||
|
||||
return MBEDTLS_ECP_DP_NONE;
|
||||
}
|
||||
|
||||
|
||||
8896
src/external/libcrux_mlkem768_sha3.c
vendored
Normal file
8896
src/external/libcrux_mlkem768_sha3.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -102,9 +102,11 @@ static ssh_string derive_ecdh_secret(ssh_session session)
|
||||
case SSH_KEX_MLKEM768NISTP256_SHA256:
|
||||
secret = derive_nist_curve_secret(session, NISTP256_SHARED_SECRET_SIZE);
|
||||
break;
|
||||
#ifdef HAVE_MLKEM1024
|
||||
case SSH_KEX_MLKEM1024NISTP384_SHA384:
|
||||
secret = derive_nist_curve_secret(session, NISTP384_SHARED_SECRET_SIZE);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
ssh_set_error(session, SSH_FATAL, "Unsupported KEX type");
|
||||
return NULL;
|
||||
@@ -129,10 +131,12 @@ static int derive_hybrid_secret(ssh_session session,
|
||||
digest = sha256;
|
||||
digest_len = SHA256_DIGEST_LEN;
|
||||
break;
|
||||
#ifdef HAVE_MLKEM1024
|
||||
case SSH_KEX_MLKEM1024NISTP384_SHA384:
|
||||
digest = sha384;
|
||||
digest_len = SHA384_DIGEST_LEN;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
ssh_set_error(session, SSH_FATAL, "Unsupported KEX type");
|
||||
goto cleanup;
|
||||
@@ -244,7 +248,9 @@ int ssh_client_hybrid_mlkem_init(ssh_session session)
|
||||
crypto->curve25519_client_pubkey);
|
||||
break;
|
||||
case SSH_KEX_MLKEM768NISTP256_SHA256:
|
||||
#ifdef HAVE_MLKEM1024
|
||||
case SSH_KEX_MLKEM1024NISTP384_SHA384:
|
||||
#endif
|
||||
rc = ssh_ecdh_init(session);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error(session,
|
||||
@@ -435,7 +441,9 @@ static SSH_PACKET_CALLBACK(ssh_packet_client_hybrid_mlkem_reply)
|
||||
#endif
|
||||
break;
|
||||
case SSH_KEX_MLKEM768NISTP256_SHA256:
|
||||
#ifdef HAVE_MLKEM1024
|
||||
case SSH_KEX_MLKEM1024NISTP384_SHA384:
|
||||
#endif
|
||||
ecdh_server_pubkey_size = ssh_buffer_get_len(server_reply_buffer);
|
||||
ssh_string_free(crypto->ecdh_server_pubkey);
|
||||
crypto->ecdh_server_pubkey = ssh_string_new(ecdh_server_pubkey_size);
|
||||
@@ -585,7 +593,9 @@ static SSH_PACKET_CALLBACK(ssh_packet_server_hybrid_mlkem_init)
|
||||
#endif
|
||||
break;
|
||||
case SSH_KEX_MLKEM768NISTP256_SHA256:
|
||||
#ifdef HAVE_MLKEM1024
|
||||
case SSH_KEX_MLKEM1024NISTP384_SHA384:
|
||||
#endif
|
||||
rc = ssh_ecdh_init(session);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error(session,
|
||||
@@ -682,7 +692,9 @@ static SSH_PACKET_CALLBACK(ssh_packet_server_hybrid_mlkem_init)
|
||||
#endif
|
||||
break;
|
||||
case SSH_KEX_MLKEM768NISTP256_SHA256:
|
||||
#ifdef HAVE_MLKEM1024
|
||||
case SSH_KEX_MLKEM1024NISTP384_SHA384:
|
||||
#endif
|
||||
ecdh_client_pubkey_size = ssh_buffer_get_len(client_init_buffer);
|
||||
ssh_string_free(crypto->ecdh_client_pubkey);
|
||||
crypto->ecdh_client_pubkey = ssh_string_new(ecdh_client_pubkey_size);
|
||||
@@ -760,7 +772,9 @@ static SSH_PACKET_CALLBACK(ssh_packet_server_hybrid_mlkem_init)
|
||||
crypto->curve25519_server_pubkey);
|
||||
break;
|
||||
case SSH_KEX_MLKEM768NISTP256_SHA256:
|
||||
#ifdef HAVE_MLKEM1024
|
||||
case SSH_KEX_MLKEM1024NISTP384_SHA384:
|
||||
#endif
|
||||
rc = ssh_buffer_pack(server_reply_buffer,
|
||||
"PP",
|
||||
ssh_string_len(crypto->mlkem_ciphertext),
|
||||
|
||||
31
src/kex.c
31
src/kex.c
@@ -41,9 +41,7 @@
|
||||
#include "libssh/string.h"
|
||||
#include "libssh/curve25519.h"
|
||||
#include "libssh/sntrup761.h"
|
||||
#ifdef HAVE_MLKEM
|
||||
#include "libssh/hybrid_mlkem.h"
|
||||
#endif
|
||||
#include "libssh/kex-gss.h"
|
||||
#include "libssh/knownhosts.h"
|
||||
#include "libssh/misc.h"
|
||||
@@ -107,13 +105,14 @@
|
||||
#define SNTRUP761X25519 ""
|
||||
#endif /* HAVE_SNTRUP761 */
|
||||
|
||||
#ifdef HAVE_MLKEM
|
||||
#ifdef HAVE_MLKEM1024
|
||||
#define HYBRID_MLKEM "mlkem768x25519-sha256," \
|
||||
"mlkem768nistp256-sha256," \
|
||||
"mlkem1024nistp384-sha384,"
|
||||
#else
|
||||
#define HYBRID_MLKEM ""
|
||||
#endif /* HAVE_MLKEM */
|
||||
#define HYBRID_MLKEM "mlkem768x25519-sha256," \
|
||||
"mlkem768nistp256-sha256,"
|
||||
#endif /* HAVE_MLKEM1024 */
|
||||
|
||||
#ifdef HAVE_ECC
|
||||
#define ECDH "ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,"
|
||||
@@ -996,11 +995,11 @@ kex_select_kex_type(const char *kex)
|
||||
return SSH_KEX_SNTRUP761X25519_SHA512_OPENSSH_COM;
|
||||
} else if (strcmp(kex, "sntrup761x25519-sha512") == 0) {
|
||||
return SSH_KEX_SNTRUP761X25519_SHA512;
|
||||
#ifdef HAVE_MLKEM
|
||||
} else if (strcmp(kex, "mlkem768x25519-sha256") == 0) {
|
||||
return SSH_KEX_MLKEM768X25519_SHA256;
|
||||
} else if (strcmp(kex, "mlkem768nistp256-sha256") == 0) {
|
||||
return SSH_KEX_MLKEM768NISTP256_SHA256;
|
||||
#ifdef HAVE_MLKEM1024
|
||||
} else if (strcmp(kex, "mlkem1024nistp384-sha384") == 0) {
|
||||
return SSH_KEX_MLKEM1024NISTP384_SHA384;
|
||||
#endif
|
||||
@@ -1058,13 +1057,13 @@ static void revert_kex_callbacks(ssh_session session)
|
||||
ssh_client_sntrup761x25519_remove_callbacks(session);
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_MLKEM
|
||||
case SSH_KEX_MLKEM768X25519_SHA256:
|
||||
case SSH_KEX_MLKEM768NISTP256_SHA256:
|
||||
#ifdef HAVE_MLKEM1024
|
||||
case SSH_KEX_MLKEM1024NISTP384_SHA384:
|
||||
#endif
|
||||
ssh_client_hybrid_mlkem_remove_callbacks(session);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1664,10 +1663,11 @@ int ssh_make_sessionid(ssh_session session)
|
||||
}
|
||||
break;
|
||||
#endif /* HAVE_SNTRUP761 */
|
||||
#ifdef HAVE_MLKEM
|
||||
case SSH_KEX_MLKEM768X25519_SHA256:
|
||||
case SSH_KEX_MLKEM768NISTP256_SHA256:
|
||||
#ifdef HAVE_MLKEM1024
|
||||
case SSH_KEX_MLKEM1024NISTP384_SHA384:
|
||||
#endif
|
||||
rc = ssh_buffer_pack(buf,
|
||||
"SS",
|
||||
session->next_crypto->hybrid_client_init,
|
||||
@@ -1679,7 +1679,6 @@ int ssh_make_sessionid(ssh_session session)
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
#endif /* HAVE_MLKEM */
|
||||
default:
|
||||
/* Handle unsupported kex types - this should not happen in normal operation */
|
||||
rc = SSH_ERROR;
|
||||
@@ -1694,13 +1693,13 @@ int ssh_make_sessionid(ssh_session session)
|
||||
session->next_crypto->shared_secret,
|
||||
SHA512_DIGEST_LEN);
|
||||
break;
|
||||
#ifdef HAVE_MLKEM
|
||||
case SSH_KEX_MLKEM768X25519_SHA256:
|
||||
case SSH_KEX_MLKEM768NISTP256_SHA256:
|
||||
#ifdef HAVE_MLKEM1024
|
||||
case SSH_KEX_MLKEM1024NISTP384_SHA384:
|
||||
#endif
|
||||
rc = ssh_buffer_pack(buf, "S", session->next_crypto->hybrid_shared_secret);
|
||||
break;
|
||||
#endif /* HAVE_MLKEM */
|
||||
default:
|
||||
rc = ssh_buffer_pack(buf, "B", session->next_crypto->shared_secret);
|
||||
break;
|
||||
@@ -1737,10 +1736,8 @@ int ssh_make_sessionid(ssh_session session)
|
||||
case SSH_KEX_ECDH_SHA2_NISTP256:
|
||||
case SSH_KEX_CURVE25519_SHA256:
|
||||
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
|
||||
#ifdef HAVE_MLKEM
|
||||
case SSH_KEX_MLKEM768X25519_SHA256:
|
||||
case SSH_KEX_MLKEM768NISTP256_SHA256:
|
||||
#endif
|
||||
case SSH_GSS_KEX_ECDH_NISTP256_SHA256:
|
||||
case SSH_GSS_KEX_CURVE25519_SHA256:
|
||||
#ifdef WITH_GEX
|
||||
@@ -1757,7 +1754,7 @@ int ssh_make_sessionid(ssh_session session)
|
||||
session->next_crypto->secret_hash);
|
||||
break;
|
||||
case SSH_KEX_ECDH_SHA2_NISTP384:
|
||||
#ifdef HAVE_MLKEM
|
||||
#ifdef HAVE_MLKEM1024
|
||||
case SSH_KEX_MLKEM1024NISTP384_SHA384:
|
||||
#endif
|
||||
session->next_crypto->digest_len = SHA384_DIGEST_LENGTH;
|
||||
@@ -1925,13 +1922,13 @@ int ssh_generate_session_keys(ssh_session session)
|
||||
k_string = ssh_make_padded_bignum_string(crypto->shared_secret,
|
||||
crypto->digest_len);
|
||||
break;
|
||||
#ifdef HAVE_MLKEM
|
||||
case SSH_KEX_MLKEM768X25519_SHA256:
|
||||
case SSH_KEX_MLKEM768NISTP256_SHA256:
|
||||
#ifdef HAVE_MLKEM1024
|
||||
case SSH_KEX_MLKEM1024NISTP384_SHA384:
|
||||
#endif
|
||||
k_string = ssh_string_copy(crypto->hybrid_shared_secret);
|
||||
break;
|
||||
#endif /* HAVE_MLKEM */
|
||||
default:
|
||||
k_string = ssh_make_bignum_string(crypto->shared_secret);
|
||||
break;
|
||||
|
||||
@@ -30,8 +30,10 @@ const struct mlkem_type_info *kex_type_to_mlkem_info(enum ssh_key_exchange_e kex
|
||||
case SSH_KEX_MLKEM768X25519_SHA256:
|
||||
case SSH_KEX_MLKEM768NISTP256_SHA256:
|
||||
return &MLKEM768_INFO;
|
||||
#ifdef HAVE_MLKEM1024
|
||||
case SSH_KEX_MLKEM1024NISTP384_SHA384:
|
||||
return &MLKEM1024_INFO;
|
||||
#endif
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
202
src/mlkem_native.c
Normal file
202
src/mlkem_native.c
Normal file
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2025 by Red Hat, Inc.
|
||||
*
|
||||
* Author: Jakub Jelen <jjelen@redhat.com>
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 2.1 of the License.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "libssh/crypto.h"
|
||||
#include "libssh/mlkem.h"
|
||||
#include "libssh/mlkem_native.h"
|
||||
#include "libssh/session.h"
|
||||
|
||||
#define crypto_kem_mlkem768_PUBLICKEYBYTES 1184
|
||||
#define crypto_kem_mlkem768_SECRETKEYBYTES 2400
|
||||
#define crypto_kem_mlkem768_CIPHERTEXTBYTES 1088
|
||||
|
||||
const struct mlkem_type_info MLKEM768_INFO = {
|
||||
.pubkey_size = crypto_kem_mlkem768_PUBLICKEYBYTES,
|
||||
.privkey_size = crypto_kem_mlkem768_SECRETKEYBYTES,
|
||||
.ciphertext_size = crypto_kem_mlkem768_CIPHERTEXTBYTES,
|
||||
};
|
||||
|
||||
int ssh_mlkem_init(ssh_session session)
|
||||
{
|
||||
int ret = SSH_ERROR;
|
||||
struct ssh_crypto_struct *crypto = session->next_crypto;
|
||||
const struct mlkem_type_info *mlkem_info = NULL;
|
||||
unsigned char rnd[LIBCRUX_ML_KEM_KEY_PAIR_PRNG_LEN];
|
||||
struct libcrux_mlkem768_keypair keypair;
|
||||
int err;
|
||||
|
||||
mlkem_info = kex_type_to_mlkem_info(crypto->kex_type);
|
||||
if (mlkem_info == NULL) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "Unknown ML-KEM type");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
err = ssh_get_random(rnd, sizeof(rnd), 0);
|
||||
if (err != 1) {
|
||||
SSH_LOG(SSH_LOG_WARNING,
|
||||
"Failed to generate random data for ML-KEM keygen");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
keypair = libcrux_ml_kem_mlkem768_portable_generate_key_pair(rnd);
|
||||
|
||||
if (ssh_string_len(crypto->mlkem_client_pubkey) < mlkem_info->pubkey_size) {
|
||||
SSH_STRING_FREE(crypto->mlkem_client_pubkey);
|
||||
}
|
||||
if (crypto->mlkem_client_pubkey == NULL) {
|
||||
crypto->mlkem_client_pubkey = ssh_string_new(mlkem_info->pubkey_size);
|
||||
if (crypto->mlkem_client_pubkey == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
err = ssh_string_fill(crypto->mlkem_client_pubkey,
|
||||
keypair.pk.value,
|
||||
mlkem_info->pubkey_size);
|
||||
if (err) {
|
||||
SSH_LOG(SSH_LOG_WARNING,
|
||||
"Failed to fill the string with client pubkey");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (crypto->mlkem_privkey == NULL) {
|
||||
crypto->mlkem_privkey = malloc(mlkem_info->privkey_size);
|
||||
if (crypto->mlkem_privkey == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
memcpy(crypto->mlkem_privkey, keypair.sk.value, mlkem_info->privkey_size);
|
||||
crypto->mlkem_privkey_len = mlkem_info->privkey_size;
|
||||
|
||||
ret = SSH_OK;
|
||||
|
||||
cleanup:
|
||||
ssh_burn(&keypair, sizeof(keypair));
|
||||
ssh_burn(rnd, sizeof(rnd));
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ssh_mlkem_encapsulate(ssh_session session,
|
||||
ssh_mlkem_shared_secret shared_secret)
|
||||
{
|
||||
int ret = SSH_ERROR;
|
||||
const struct mlkem_type_info *mlkem_info = NULL;
|
||||
struct ssh_crypto_struct *crypto = session->next_crypto;
|
||||
const unsigned char *pubkey_data = NULL;
|
||||
ssh_string pubkey = crypto->mlkem_client_pubkey;
|
||||
struct libcrux_mlkem768_enc_result enc;
|
||||
struct libcrux_mlkem768_pk mlkem_pub = {0};
|
||||
unsigned char rnd[LIBCRUX_ML_KEM_ENC_PRNG_LEN];
|
||||
int err;
|
||||
|
||||
if (pubkey == NULL) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "Missing pubkey in session");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
mlkem_info = kex_type_to_mlkem_info(crypto->kex_type);
|
||||
if (mlkem_info == NULL) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "Unknown ML-KEM type");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
pubkey_data = ssh_string_data(pubkey);
|
||||
memcpy(mlkem_pub.value, pubkey_data, mlkem_info->pubkey_size);
|
||||
err = libcrux_ml_kem_mlkem768_portable_validate_public_key(&mlkem_pub);
|
||||
if (err == 0) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "Invalid public key");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
err = ssh_get_random(rnd, sizeof(rnd), 0);
|
||||
if (err != 1) {
|
||||
SSH_LOG(SSH_LOG_WARNING,
|
||||
"Failed to generate random data for ML-KEM keygen");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
enc = libcrux_ml_kem_mlkem768_portable_encapsulate(&mlkem_pub, rnd);
|
||||
|
||||
if (ssh_string_len(crypto->mlkem_ciphertext) < mlkem_info->ciphertext_size) {
|
||||
SSH_STRING_FREE(crypto->mlkem_ciphertext);
|
||||
}
|
||||
if (crypto->mlkem_ciphertext == NULL) {
|
||||
crypto->mlkem_ciphertext = ssh_string_new(mlkem_info->ciphertext_size);
|
||||
if (crypto->mlkem_ciphertext == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
err = ssh_string_fill(crypto->mlkem_ciphertext,
|
||||
enc.fst.value,
|
||||
sizeof(enc.fst.value));
|
||||
if (err != SSH_OK) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "Failed to fill the string with ciphertext");
|
||||
goto cleanup;
|
||||
}
|
||||
memcpy(shared_secret, enc.snd, sizeof(enc.snd));
|
||||
|
||||
ret = SSH_OK;
|
||||
|
||||
cleanup:
|
||||
ssh_burn(rnd, sizeof(rnd));
|
||||
ssh_burn(&enc, sizeof(enc));
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ssh_mlkem_decapsulate(const ssh_session session,
|
||||
ssh_mlkem_shared_secret shared_secret)
|
||||
{
|
||||
const struct mlkem_type_info *mlkem_info = NULL;
|
||||
struct ssh_crypto_struct *crypto = session->next_crypto;
|
||||
ssh_string ciphertext = NULL;
|
||||
unsigned char *ciphertext_data = NULL;
|
||||
struct libcrux_mlkem768_sk mlkem_priv = {0};
|
||||
struct libcrux_mlkem768_ciphertext mlkem_ciphertext = {0};
|
||||
|
||||
mlkem_info = kex_type_to_mlkem_info(crypto->kex_type);
|
||||
if (mlkem_info == NULL) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "Unknown ML-KEM type");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
ciphertext = crypto->mlkem_ciphertext;
|
||||
if (ciphertext == NULL) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "Missing ciphertext in session");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
ciphertext_data = ssh_string_data(ciphertext);
|
||||
memcpy(mlkem_ciphertext.value,
|
||||
ciphertext_data,
|
||||
sizeof(mlkem_ciphertext.value));
|
||||
|
||||
memcpy(mlkem_priv.value, crypto->mlkem_privkey, crypto->mlkem_privkey_len);
|
||||
|
||||
libcrux_ml_kem_mlkem768_portable_decapsulate(&mlkem_priv,
|
||||
&mlkem_ciphertext,
|
||||
shared_secret);
|
||||
return SSH_OK;
|
||||
}
|
||||
@@ -505,14 +505,14 @@ const char* ssh_get_kex_algo(ssh_session session) {
|
||||
return "sntrup761x25519-sha512@openssh.com";
|
||||
case SSH_KEX_SNTRUP761X25519_SHA512:
|
||||
return "sntrup761x25519-sha512";
|
||||
#ifdef HAVE_MLKEM
|
||||
case SSH_KEX_MLKEM768X25519_SHA256:
|
||||
return "mlkem768x25519-sha256";
|
||||
case SSH_KEX_MLKEM768NISTP256_SHA256:
|
||||
return "mlkem768nistp256-sha256";
|
||||
#ifdef HAVE_MLKEM1024
|
||||
case SSH_KEX_MLKEM1024NISTP384_SHA384:
|
||||
return "mlkem1024nistp384-sha384";
|
||||
#endif /* HAVE_MLKEM */
|
||||
#endif /* HAVE_MLKEM1024 */
|
||||
#ifdef WITH_GEX
|
||||
case SSH_KEX_DH_GEX_SHA1:
|
||||
return "diffie-hellman-group-exchange-sha1";
|
||||
|
||||
@@ -51,10 +51,8 @@
|
||||
#include "libssh/curve25519.h"
|
||||
#include "libssh/kex-gss.h"
|
||||
#include "libssh/ecdh.h"
|
||||
#include "libssh/sntrup761.h"
|
||||
#ifdef HAVE_MLKEM
|
||||
#include "libssh/hybrid_mlkem.h"
|
||||
#endif
|
||||
#include "libssh/sntrup761.h"
|
||||
|
||||
static struct ssh_hmac_struct ssh_hmac_tab[] = {
|
||||
{ "hmac-sha1", SSH_HMAC_SHA1, false },
|
||||
@@ -230,15 +228,14 @@ void crypto_free(struct ssh_crypto_struct *crypto)
|
||||
SAFE_FREE(crypto->kex_methods[i]);
|
||||
}
|
||||
|
||||
#ifdef HAVE_MLKEM
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
#ifdef HAVE_OPENSSL_MLKEM
|
||||
EVP_PKEY_free(crypto->mlkem_privkey);
|
||||
#else
|
||||
if (crypto->mlkem_privkey != NULL) {
|
||||
ssh_burn(crypto->mlkem_privkey, crypto->mlkem_privkey_len);
|
||||
SAFE_FREE(crypto->mlkem_privkey);
|
||||
crypto->mlkem_privkey_len = 0;
|
||||
}
|
||||
#else
|
||||
EVP_PKEY_free(crypto->mlkem_privkey);
|
||||
#endif
|
||||
ssh_string_burn(crypto->hybrid_shared_secret);
|
||||
ssh_string_free(crypto->mlkem_client_pubkey);
|
||||
@@ -246,7 +243,6 @@ void crypto_free(struct ssh_crypto_struct *crypto)
|
||||
ssh_string_free(crypto->hybrid_client_init);
|
||||
ssh_string_free(crypto->hybrid_server_reply);
|
||||
ssh_string_free(crypto->hybrid_shared_secret);
|
||||
#endif
|
||||
|
||||
ssh_burn(crypto, sizeof(struct ssh_crypto_struct));
|
||||
|
||||
@@ -629,13 +625,13 @@ int crypt_set_algorithms_server(ssh_session session){
|
||||
ssh_server_sntrup761x25519_init(session);
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_MLKEM
|
||||
case SSH_KEX_MLKEM768X25519_SHA256:
|
||||
case SSH_KEX_MLKEM768NISTP256_SHA256:
|
||||
#ifdef HAVE_MLKEM1024
|
||||
case SSH_KEX_MLKEM1024NISTP384_SHA384:
|
||||
#endif
|
||||
ssh_server_hybrid_mlkem_init(session);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
|
||||
Reference in New Issue
Block a user