Skip to content

Commit

Permalink
implement X25519MLKEM768
Browse files Browse the repository at this point in the history
  • Loading branch information
kazuho committed Nov 20, 2024
1 parent e7d65c7 commit a12530a
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 0 deletions.
2 changes: 2 additions & 0 deletions include/picotls.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,8 @@ extern "C" {
#define PTLS_GROUP_NAME_X25519 "x25519"
#define PTLS_GROUP_X448 30
#define PTLS_GROUP_NAME_X448 "x448"
#define PTLS_GROUP_X25519MLKEM768 4588
#define PTLS_GROUP_NAME_X25519MLKEM768 "X25519MLKEM768"

/* signature algorithms */
#define PTLS_SIGNATURE_RSA_PKCS1_SHA1 0x0201
Expand Down
6 changes: 6 additions & 0 deletions include/picotls/openssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@ extern ptls_key_exchange_algorithm_t ptls_openssl_x25519;
#define PTLS_OPENSSL_HAVE_X25519 0
#define PTLS_OPENSSL_HAS_X25519 0 /* deprecated; use HAVE_ */
#endif
#ifdef OPENSSL_IS_BORINGSSL
#define PTLS_OPENSSL_HAVE_MLKEM768 1
extern ptls_key_exchange_algorithm_t ptls_openssl_x25519mlkem768;
#else
#define PTLS_OPENSSL_HAVE_MLKEM768 0
#endif

/* when boringssl is used, existence of libdecrepit is assumed */
#if !defined(OPENSSL_NO_BF) || defined(OPENSSL_IS_BORINGSSL)
Expand Down
138 changes: 138 additions & 0 deletions lib/openssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@
#ifdef OPENSSL_IS_BORINGSSL
#include "./chacha20poly1305.h"
#endif
#if PTLS_OPENSSL_HAVE_MLKEM768
#include <openssl/mlkem.h>
#endif
#ifdef PTLS_HAVE_AEGIS
#include "./libaegis.h"
#endif
Expand Down Expand Up @@ -706,6 +709,135 @@ static int evp_keyex_exchange(ptls_key_exchange_algorithm_t *algo, ptls_iovec_t

#endif

#if PTLS_OPENSSL_HAVE_MLKEM768

struct st_x25519mlkem768_context_t {
ptls_key_exchange_context_t super;
uint8_t pubkey[MLKEM768_PUBLIC_KEY_BYTES + X25519_PUBLIC_VALUE_LEN];
struct {
uint8_t x25519[X25519_PRIVATE_KEY_LEN];
struct MLKEM768_private_key mlkem;
} privkey;
};

static int x25519mlkem768_on_exchange(ptls_key_exchange_context_t **_ctx, int release, ptls_iovec_t *secret,
ptls_iovec_t ciphertext)
{
struct st_x25519mlkem768_context_t *ctx = (void *)*_ctx;
int ret;

if (secret == NULL) {
ret = 0;
goto Exit;
}

*secret = ptls_iovec_init(NULL, 0);

/* validate length */
if (ciphertext.len != MLKEM768_CIPHERTEXT_BYTES + X25519_PUBLIC_VALUE_LEN) {
ret = PTLS_ALERT_DECRYPT_ERROR;
goto Exit;
}

/* appsocate memory */
secret->len = MLKEM_SHARED_SECRET_BYTES + X25519_SHARED_KEY_LEN;
if ((secret->base = malloc(secret->len)) == NULL) {
ret = PTLS_ERROR_NO_MEMORY;
goto Exit;
}

/* run key exchange */
if (!MLKEM768_decap(secret->base, ciphertext.base, MLKEM768_CIPHERTEXT_BYTES, &ctx->privkey.mlkem) ||
!X25519(secret->base + MLKEM_SHARED_SECRET_BYTES, ctx->privkey.x25519, ciphertext.base + MLKEM768_CIPHERTEXT_BYTES)) {
ret = PTLS_ALERT_ILLEGAL_PARAMETER;
goto Exit;
}
ret = 0;

Exit:
if (secret != NULL && ret != 0) {
free(secret->base);
*secret = ptls_iovec_init(NULL, 0);
}
if (release) {
ptls_clear_memory(&ctx->privkey, sizeof(ctx->privkey));
free(ctx);
*_ctx = NULL;
}
return ret;
}

static int x25519mlkem768_create(ptls_key_exchange_algorithm_t *algo, ptls_key_exchange_context_t **_ctx)
{
struct st_x25519mlkem768_context_t *ctx = NULL;

if ((ctx = malloc(sizeof(*ctx))) == NULL)
return PTLS_ERROR_NO_MEMORY;

ctx->super = (ptls_key_exchange_context_t){algo, ptls_iovec_init(ctx->pubkey, sizeof(ctx->pubkey)), x25519mlkem768_on_exchange};
MLKEM768_generate_key(ctx->pubkey, NULL, &ctx->privkey.mlkem);
X25519_keypair(ctx->pubkey + MLKEM768_PUBLIC_KEY_BYTES, ctx->privkey.x25519);

*_ctx = &ctx->super;
return 0;
}

static int x25519mlkem768_exchange(ptls_key_exchange_algorithm_t *algo, ptls_iovec_t *ciphertext, ptls_iovec_t *secret,
ptls_iovec_t peerkey)
{
struct {
CBS cbs;
struct MLKEM768_public_key key;
} mlkem_peer;
uint8_t x25519_privkey[X25519_PRIVATE_KEY_LEN];
int ret;

*ciphertext = ptls_iovec_init(NULL, 0);
*secret = ptls_iovec_init(NULL, 0);

/* validate input length */
if (peerkey.len != MLKEM768_PUBLIC_KEY_BYTES + X25519_PUBLIC_VALUE_LEN) {
ret = PTLS_ALERT_DECODE_ERROR;
goto Exit;
}

/* allocate memory */
ciphertext->len = MLKEM768_CIPHERTEXT_BYTES + X25519_PUBLIC_VALUE_LEN;
if ((ciphertext->base = malloc(ciphertext->len)) == NULL) {
ret = PTLS_ERROR_NO_MEMORY;
goto Exit;
}
secret->len = MLKEM_SHARED_SECRET_BYTES + X25519_SHARED_KEY_LEN;
if ((secret->base = malloc(secret->len)) == NULL) {
ret = PTLS_ERROR_NO_MEMORY;
goto Exit;
}

/* run key exchange */
CBS_init(&mlkem_peer.cbs, peerkey.base, MLKEM768_PUBLIC_KEY_BYTES);
X25519_keypair(ciphertext->base + MLKEM768_CIPHERTEXT_BYTES, x25519_privkey);
if (!MLKEM768_parse_public_key(&mlkem_peer.key, &mlkem_peer.cbs) ||
!X25519(secret->base + MLKEM_SHARED_SECRET_BYTES, x25519_privkey, peerkey.base + MLKEM768_PUBLIC_KEY_BYTES)) {
ret = PTLS_ALERT_ILLEGAL_PARAMETER;
goto Exit;
}
MLKEM768_encap(ciphertext->base, secret->base, &mlkem_peer.key);

ret = 0;

Exit:
if (ret != 0) {
free(ciphertext->base);
*ciphertext = ptls_iovec_init(NULL, 0);
free(secret->base);
*secret = ptls_iovec_init(NULL, 0);
}
ptls_clear_memory(&x25519_privkey, sizeof(x25519_privkey));
return ret;
}

#endif

int ptls_openssl_create_key_exchange(ptls_key_exchange_context_t **ctx, EVP_PKEY *pkey)
{
int ret, id;
Expand Down Expand Up @@ -2063,6 +2195,12 @@ ptls_key_exchange_algorithm_t ptls_openssl_x25519 = {.id = PTLS_GROUP_X25519,
.exchange = evp_keyex_exchange,
.data = NID_X25519};
#endif
#if PTLS_OPENSSL_HAVE_MLKEM768
ptls_key_exchange_algorithm_t ptls_openssl_x25519mlkem768 = {.id = PTLS_GROUP_X25519MLKEM768,
.name = PTLS_GROUP_NAME_X25519MLKEM768,
.create = x25519mlkem768_create,
.exchange = x25519mlkem768_exchange};
#endif
ptls_key_exchange_algorithm_t *ptls_openssl_key_exchanges[] = {&ptls_openssl_secp256r1, NULL};
ptls_cipher_algorithm_t ptls_openssl_aes128ecb = {
"AES128-ECB", PTLS_AES128_KEY_SIZE, PTLS_AES_BLOCK_SIZE, 0 /* iv size */, sizeof(struct cipher_context_t),
Expand Down
6 changes: 6 additions & 0 deletions t/cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,9 @@ static void usage(const char *cmd)
#endif
#if PTLS_OPENSSL_HAVE_X25519
", X25519"
#endif
#if PTLS_OPENSSL_HAVE_MLKEM768
", X5519MLKEM768"
#endif
"\n"
"Supported signature algorithms: rsa, secp256r1"
Expand Down Expand Up @@ -559,6 +562,9 @@ int main(int argc, char **argv)
#if PTLS_OPENSSL_HAVE_X25519
MATCH(x25519);
#endif
#if PTLS_OPENSSL_HAVE_MLKEM768
MATCH(x25519mlkem768);
#endif
#undef MATCH
if (algo == NULL) {
fprintf(stderr, "could not find key exchange: %s\n", optarg);
Expand Down
4 changes: 4 additions & 0 deletions t/openssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,10 @@ static void test_key_exchanges(void)
subtest("x25519-to-minicrypto", test_key_exchange, &ptls_openssl_x25519, &ptls_minicrypto_x25519);
subtest("x25519-from-minicrypto", test_key_exchange, &ptls_minicrypto_x25519, &ptls_openssl_x25519);
#endif

#if PTLS_OPENSSL_HAVE_MLKEM768
subtest("x25519mlkem768", test_key_exchange, &ptls_openssl_x25519mlkem768, &ptls_openssl_x25519mlkem768);
#endif
}

static void test_sign_verify(EVP_PKEY *key, const ptls_openssl_signature_scheme_t *schemes)
Expand Down

0 comments on commit a12530a

Please sign in to comment.