Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reverse TLS hybrid keyshares for x25519/x448-mlkem hybrids #524

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ALGORITHMS.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ As standardization for these algorithms within TLS is not done, all TLS code poi
| mlkem768 | 0x0768 | Yes | OQS_CODEPOINT_MLKEM768 |
| p384_mlkem768 | 0x2F4C | Yes | OQS_CODEPOINT_P384_MLKEM768 |
| x448_mlkem768 | 0x2FB7 | Yes | OQS_CODEPOINT_X448_MLKEM768 |
| x25519_mlkem768 | 0x2FB8 | Yes | OQS_CODEPOINT_X25519_MLKEM768 |
| x25519_mlkem768 | 0x11ec | Yes | OQS_CODEPOINT_X25519_MLKEM768 |
| p256_mlkem768 | 4587 | Yes | OQS_CODEPOINT_P256_MLKEM768 |
| mlkem1024 | 0x1024 | Yes | OQS_CODEPOINT_MLKEM1024 |
| p521_mlkem1024 | 0x2F4D | Yes | OQS_CODEPOINT_P521_MLKEM1024 |
Expand Down
6 changes: 4 additions & 2 deletions oqs-template/generate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ kems:
# KEM prefix 2.16.840.1.101.3.4.4.
-
family: 'ML-KEM'
fips_standard: 1
name_group: 'mlkem512'
# code point not standardized: Why? XXX
nid: '0x024A'
Expand All @@ -167,6 +168,7 @@ kems:
nid: '0x2FB6'
-
family: 'ML-KEM'
fips_standard: 1
name_group: 'mlkem768'
# https://www.ietf.org/archive/id/draft-connolly-tls-mlkem-key-agreement-01.html
nid: '0x0768'
Expand All @@ -180,14 +182,14 @@ kems:
- hybrid_group: "x448"
# code point not standardized: Why? XXX
nid: '0x2FB7'
# To change when hybrid order change implemented, see https://github.com/open-quantum-safe/oqs-provider/issues/503
- hybrid_group: "x25519"
nid: '0x2FB8'
nid: '0x11ec'
- hybrid_group: "p256"
# https://www.ietf.org/archive/id/draft-kwiatkowski-tls-ecdhe-mlkem-01.html#name-iana-considerations
nid: '4587'
-
family: 'ML-KEM'
fips_standard: 1
name_group: 'mlkem1024'
# https://www.ietf.org/archive/id/draft-connolly-tls-mlkem-key-agreement-01.html
nid: '0x1024'
Expand Down
2 changes: 1 addition & 1 deletion oqs-template/oqs-kem-info.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@
| ML-KEM | ML-KEM | mlkem512 | FIPS203 | 1 | 0x2F4B | secp256_r1 |
| ML-KEM | ML-KEM | mlkem512 | FIPS203 | 1 | 0x2FB6 | x25519 |
| ML-KEM | ML-KEM | mlkem768 | FIPS203 | 3 | 0x0768 | |
| ML-KEM | ML-KEM | mlkem768 | FIPS203 | 3 | 0x11ec | x25519 |
| ML-KEM | ML-KEM | mlkem768 | FIPS203 | 3 | 0x2F4C | secp384_r1 |
| ML-KEM | ML-KEM | mlkem768 | FIPS203 | 3 | 0x2FB7 | x448 |
| ML-KEM | ML-KEM | mlkem768 | FIPS203 | 3 | 0x2FB8 | x25519 |
| ML-KEM | ML-KEM | mlkem768 | FIPS203 | 3 | 4587 | p256 |
12 changes: 6 additions & 6 deletions oqs-template/oqsprov/oqs_kmgmt.c/keymgmt_constructors.fragment
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,37 @@
{%- set count.val = count.val + 1 %}
static void *{{variant['name']}}_new_key(void *provctx)
{
return oqsx_key_new(PROV_OQS_LIBCTX_OF(provctx), {{variant['oqs_meth']}}, "{{variant['name']}}", KEY_TYPE_SIG, NULL, {{variant['security']}}, {{ count.val }});
return oqsx_key_new(PROV_OQS_LIBCTX_OF(provctx), {{variant['oqs_meth']}}, "{{variant['name']}}", KEY_TYPE_SIG, NULL, {{variant['security']}}, {{ count.val }}, 0);
}

static void *{{variant['name']}}_gen_init(void *provctx, int selection)
{
return oqsx_gen_init(provctx, selection, {{variant['oqs_meth']}}, "{{variant['name']}}", 0, {{variant['security']}}, {{ count.val }});
return oqsx_gen_init(provctx, selection, {{variant['oqs_meth']}}, "{{variant['name']}}", 0, {{variant['security']}}, {{ count.val }}, 0);
}

{%- for classical_alg in variant['mix_with'] %}
{%- set count.val = count.val + 1 %}
static void *{{ classical_alg['name'] }}_{{variant['name']}}_new_key(void *provctx)
{
return oqsx_key_new(PROV_OQS_LIBCTX_OF(provctx), {{variant['oqs_meth']}}, "{{ classical_alg['name'] }}_{{variant['name']}}", KEY_TYPE_HYB_SIG, NULL, {{variant['security']}}, {{ count.val }});
return oqsx_key_new(PROV_OQS_LIBCTX_OF(provctx), {{variant['oqs_meth']}}, "{{ classical_alg['name'] }}_{{variant['name']}}", KEY_TYPE_HYB_SIG, NULL, {{variant['security']}}, {{ count.val }}, 0);
}

static void *{{ classical_alg['name'] }}_{{variant['name']}}_gen_init(void *provctx, int selection)
{
return oqsx_gen_init(provctx, selection, {{variant['oqs_meth']}}, "{{ classical_alg['name'] }}_{{variant['name']}}", KEY_TYPE_HYB_SIG, {{variant['security']}}, {{ count.val }});
return oqsx_gen_init(provctx, selection, {{variant['oqs_meth']}}, "{{ classical_alg['name'] }}_{{variant['name']}}", KEY_TYPE_HYB_SIG, {{variant['security']}}, {{ count.val }}, 0);
}

{%- endfor -%}
{%- for composite_alg in variant['composite'] %}
{%- set count.val = count.val + 1 %}
static void *{{ variant['name'] }}_{{ composite_alg['name'] }}_new_key(void *provctx)
{
return oqsx_key_new(PROV_OQS_LIBCTX_OF(provctx), {{variant['oqs_meth']}}, "{{ variant['name'] }}_{{ composite_alg['name'] }}", KEY_TYPE_CMP_SIG, NULL, {{composite_alg['security']}}, {{ count.val }});
return oqsx_key_new(PROV_OQS_LIBCTX_OF(provctx), {{variant['oqs_meth']}}, "{{ variant['name'] }}_{{ composite_alg['name'] }}", KEY_TYPE_CMP_SIG, NULL, {{composite_alg['security']}}, {{ count.val }}, 0);
}

static void *{{ variant['name'] }}_{{ composite_alg['name'] }}_gen_init(void *provctx, int selection)
{
return oqsx_gen_init(provctx, selection, {{variant['oqs_meth']}}, "{{ variant['name'] }}_{{ composite_alg['name'] }}", KEY_TYPE_CMP_SIG, {{composite_alg['security']}}, {{ count.val }});
return oqsx_gen_init(provctx, selection, {{variant['oqs_meth']}}, "{{ variant['name'] }}_{{ composite_alg['name'] }}", KEY_TYPE_CMP_SIG, {{composite_alg['security']}}, {{ count.val }}, 0);
}

{%- endfor -%}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ MAKE_KEM_KEYMGMT_FUNCTIONS({{kem['name_group']}}, {{kem['oqs_alg']}}, {{kem['bit
{% if hybrid['hybrid_group'].startswith('p') -%}
MAKE_KEM_ECP_KEYMGMT_FUNCTIONS({{hybrid['hybrid_group']}}_{{kem['name_group']}}, {{kem['oqs_alg']}}, {{hybrid['bit_security']}})
{%- else %}
MAKE_KEM_ECX_KEYMGMT_FUNCTIONS({{hybrid['hybrid_group']}}_{{kem['name_group']}}, {{kem['oqs_alg']}}, {{hybrid['bit_security']}})
MAKE_KEM_ECX_KEYMGMT_FUNCTIONS({{hybrid['hybrid_group']}}_{{kem['name_group']}}, {{kem['oqs_alg']}}, {{hybrid['bit_security']}}, {% if 'fips_standard' in kem %}{{kem['fips_standard']}}{% else %}0{% endif %})
{%- endif %}
{%- endfor %}
{%- endfor %}
Expand Down
105 changes: 68 additions & 37 deletions oqsprov/oqs_hyb_kem.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ static int oqs_evp_kem_encaps_keyslot(void *vpkemctx, unsigned char *ct,

// Free at err:
EVP_PKEY_CTX *ctx = NULL, *kgctx = NULL;
;

EVP_PKEY *pkey = NULL, *peerpk = NULL;
unsigned char *ctkex_encoded = NULL;

Expand Down Expand Up @@ -153,37 +153,53 @@ static int oqs_hyb_kem_encaps(void *vpkemctx, unsigned char *ct, size_t *ctlen,
unsigned char *secret, size_t *secretlen) {
int ret = OQS_SUCCESS;
const PROV_OQSKEM_CTX *pkemctx = (PROV_OQSKEM_CTX *)vpkemctx;
size_t secretLen0 = 0, secretLen1 = 0;
size_t ctLen0 = 0, ctLen1 = 0;
unsigned char *ct0, *ct1, *secret0, *secret1;

ret = oqs_evp_kem_encaps_keyslot(vpkemctx, NULL, &ctLen0, NULL, &secretLen0,
0);
const OQSX_KEY *oqsx_key = pkemctx->kem;
size_t secretLenClassical = 0, secretLenPQ = 0;
size_t ctLenClassical = 0, ctLenPQ = 0;
unsigned char *ctClassical, *ctPQ, *secretClassical, *secretPQ;

ret = oqs_evp_kem_encaps_keyslot(vpkemctx, NULL, &ctLenClassical, NULL,
&secretLenClassical,
oqsx_key->reverse_share ? 1 : 0);
ON_ERR_SET_GOTO(ret <= 0, ret, OQS_ERROR, err);
ret = oqs_qs_kem_encaps_keyslot(vpkemctx, NULL, &ctLen1, NULL, &secretLen1,
1);
ret =
oqs_qs_kem_encaps_keyslot(vpkemctx, NULL, &ctLenPQ, NULL, &secretLenPQ,
oqsx_key->reverse_share ? 0 : 1);
ON_ERR_SET_GOTO(ret <= 0, ret, OQS_ERROR, err);

*ctlen = ctLen0 + ctLen1;
*secretlen = secretLen0 + secretLen1;
*ctlen = ctLenClassical + ctLenPQ;
*secretlen = secretLenClassical + secretLenPQ;

if (ct == NULL || secret == NULL) {
OQS_KEM_PRINTF3("HYB KEM returning lengths %ld and %ld\n", *ctlen,
*secretlen);
return 1;
}

ct0 = ct;
ct1 = ct + ctLen0;
secret0 = secret;
secret1 = secret + secretLen0;
/* Rule: if the classical algorthm is not FIPS approved
but the PQ algorithm is: PQ share comes first
otherwise: classical share comes first
*/
if (oqsx_key->reverse_share) {
ctPQ = ct;
ctClassical = ct + ctLenPQ;
secretPQ = secret;
secretClassical = secret + secretLenPQ;
} else {
ctClassical = ct;
ctPQ = ct + ctLenClassical;
secretClassical = secret;
secretPQ = secret + secretLenClassical;
}

ret = oqs_evp_kem_encaps_keyslot(vpkemctx, ct0, &ctLen0, secret0,
&secretLen0, 0);
ret = oqs_evp_kem_encaps_keyslot(vpkemctx, ctClassical, &ctLenClassical,
secretClassical, &secretLenClassical,
oqsx_key->reverse_share ? 1 : 0);
ON_ERR_SET_GOTO(ret <= 0, ret, OQS_ERROR, err);

ret = oqs_qs_kem_encaps_keyslot(vpkemctx, ct1, &ctLen1, secret1,
&secretLen1, 1);
ret = oqs_qs_kem_encaps_keyslot(vpkemctx, ctPQ, &ctLenPQ, secretPQ,
&secretLenPQ,
oqsx_key->reverse_share ? 0 : 1);
ON_ERR_SET_GOTO(ret <= 0, ret, OQS_ERROR, err);

err:
Expand All @@ -195,39 +211,54 @@ static int oqs_hyb_kem_decaps(void *vpkemctx, unsigned char *secret,
size_t ctlen) {
int ret = OQS_SUCCESS;
const PROV_OQSKEM_CTX *pkemctx = (PROV_OQSKEM_CTX *)vpkemctx;
const OQSX_KEY *oqsx_key = pkemctx->kem;
const OQSX_EVP_CTX *evp_ctx = pkemctx->kem->oqsx_provider_ctx.oqsx_evp_ctx;
const OQS_KEM *qs_ctx = pkemctx->kem->oqsx_provider_ctx.oqsx_qs_ctx.kem;

size_t secretLen0 = 0, secretLen1 = 0;
size_t ctLen0 = 0, ctLen1 = 0;
const unsigned char *ct0, *ct1;
unsigned char *secret0, *secret1;
size_t secretLenClassical = 0, secretLenPQ = 0;
size_t ctLenClassical = 0, ctLenPQ = 0;
const unsigned char *ctClassical, *ctPQ;
unsigned char *secretClassical, *secretPQ;

ret = oqs_evp_kem_decaps_keyslot(vpkemctx, NULL, &secretLen0, NULL, 0, 0);
ret = oqs_evp_kem_decaps_keyslot(vpkemctx, NULL, &secretLenClassical, NULL,
0, oqsx_key->reverse_share ? 1 : 0);
ON_ERR_SET_GOTO(ret <= 0, ret, OQS_ERROR, err);
ret = oqs_qs_kem_decaps_keyslot(vpkemctx, NULL, &secretLen1, NULL, 0, 1);
ret = oqs_qs_kem_decaps_keyslot(vpkemctx, NULL, &secretLenPQ, NULL, 0,
oqsx_key->reverse_share ? 0 : 1);
ON_ERR_SET_GOTO(ret <= 0, ret, OQS_ERROR, err);

*secretlen = secretLen0 + secretLen1;
*secretlen = secretLenClassical + secretLenPQ;

if (secret == NULL)
return 1;

ctLen0 = evp_ctx->evp_info->length_public_key;
ctLen1 = qs_ctx->length_ciphertext;
ctLenClassical = evp_ctx->evp_info->length_public_key;
ctLenPQ = qs_ctx->length_ciphertext;

ON_ERR_SET_GOTO(ctLen0 + ctLen1 != ctlen, ret, OQS_ERROR, err);
ON_ERR_SET_GOTO(ctLenClassical + ctLenPQ != ctlen, ret, OQS_ERROR, err);

ct0 = ct;
ct1 = ct + ctLen0;
secret0 = secret;
secret1 = secret + secretLen0;
/* Rule: if the classical algorthm is not FIPS approved
but the PQ algorithm is: PQ share comes first
otherwise: classical share comes first
*/
if (oqsx_key->reverse_share) {
ctPQ = ct;
ctClassical = ct + ctLenPQ;
secretPQ = secret;
secretClassical = secret + secretLenPQ;
} else {
ctClassical = ct;
ctPQ = ct + ctLenClassical;
secretClassical = secret;
secretPQ = secret + secretLenClassical;
}

ret = oqs_evp_kem_decaps_keyslot(vpkemctx, secret0, &secretLen0, ct0,
ctLen0, 0);
ret = oqs_evp_kem_decaps_keyslot(
vpkemctx, secretClassical, &secretLenClassical, ctClassical,
ctLenClassical, oqsx_key->reverse_share ? 1 : 0);
ON_ERR_SET_GOTO(ret <= 0, ret, OQS_ERROR, err);
ret = oqs_qs_kem_decaps_keyslot(vpkemctx, secret1, &secretLen1, ct1, ctLen1,
1);
ret = oqs_qs_kem_decaps_keyslot(vpkemctx, secretPQ, &secretLenPQ, ctPQ,
ctLenPQ, oqsx_key->reverse_share ? 0 : 1);
ON_ERR_SET_GOTO(ret <= 0, ret, OQS_ERROR, err);

err:
Expand Down
Loading
Loading