Initial ML-KEM documentation

Reviewed-by: Viktor Dukhovni <viktor@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/26037)
This commit is contained in:
Michael Baentsch 2024-12-05 11:27:49 +01:00 committed by Tomas Mraz
parent 42436eb53e
commit 78df1c1f61
8 changed files with 330 additions and 3 deletions

View file

@ -4619,6 +4619,10 @@ DEPEND[html/man7/EVP_KEM-EC.html]=man7/EVP_KEM-EC.pod
GENERATE[html/man7/EVP_KEM-EC.html]=man7/EVP_KEM-EC.pod
DEPEND[man/man7/EVP_KEM-EC.7]=man7/EVP_KEM-EC.pod
GENERATE[man/man7/EVP_KEM-EC.7]=man7/EVP_KEM-EC.pod
DEPEND[html/man7/EVP_KEM-ML-KEM.html]=man7/EVP_KEM-ML-KEM.pod
GENERATE[html/man7/EVP_KEM-ML-KEM.html]=man7/EVP_KEM-ML-KEM.pod
DEPEND[man/man7/EVP_KEM-ML-KEM.7]=man7/EVP_KEM-ML-KEM.pod
GENERATE[man/man7/EVP_KEM-ML-KEM.7]=man7/EVP_KEM-ML-KEM.pod
DEPEND[html/man7/EVP_KEM-RSA.html]=man7/EVP_KEM-RSA.pod
GENERATE[html/man7/EVP_KEM-RSA.html]=man7/EVP_KEM-RSA.pod
DEPEND[man/man7/EVP_KEM-RSA.7]=man7/EVP_KEM-RSA.pod
@ -4755,6 +4759,10 @@ DEPEND[html/man7/EVP_PKEY-ML-DSA.html]=man7/EVP_PKEY-ML-DSA.pod
GENERATE[html/man7/EVP_PKEY-ML-DSA.html]=man7/EVP_PKEY-ML-DSA.pod
DEPEND[man/man7/EVP_PKEY-ML-DSA.7]=man7/EVP_PKEY-ML-DSA.pod
GENERATE[man/man7/EVP_PKEY-ML-DSA.7]=man7/EVP_PKEY-ML-DSA.pod
DEPEND[html/man7/EVP_PKEY-ML-KEM.html]=man7/EVP_PKEY-ML-KEM.pod
GENERATE[html/man7/EVP_PKEY-ML-KEM.html]=man7/EVP_PKEY-ML-KEM.pod
DEPEND[man/man7/EVP_PKEY-ML-KEM.7]=man7/EVP_PKEY-ML-KEM.pod
GENERATE[man/man7/EVP_PKEY-ML-KEM.7]=man7/EVP_PKEY-ML-KEM.pod
DEPEND[html/man7/EVP_PKEY-RSA.html]=man7/EVP_PKEY-RSA.pod
GENERATE[html/man7/EVP_PKEY-RSA.html]=man7/EVP_PKEY-RSA.pod
DEPEND[man/man7/EVP_PKEY-RSA.7]=man7/EVP_PKEY-RSA.pod
@ -5121,6 +5129,7 @@ html/man7/EVP_KDF-X942-ASN1.html \
html/man7/EVP_KDF-X942-CONCAT.html \
html/man7/EVP_KDF-X963.html \
html/man7/EVP_KEM-EC.html \
html/man7/EVP_KEM-ML-KEM.html \
html/man7/EVP_KEM-RSA.html \
html/man7/EVP_KEM-X25519.html \
html/man7/EVP_KEYEXCH-DH.html \
@ -5155,6 +5164,7 @@ html/man7/EVP_PKEY-EC.html \
html/man7/EVP_PKEY-FFC.html \
html/man7/EVP_PKEY-HMAC.html \
html/man7/EVP_PKEY-ML-DSA.html \
html/man7/EVP_PKEY-ML-KEM.html \
html/man7/EVP_PKEY-RSA.html \
html/man7/EVP_PKEY-SM2.html \
html/man7/EVP_PKEY-X25519.html \
@ -5270,6 +5280,7 @@ man/man7/EVP_KDF-X942-ASN1.7 \
man/man7/EVP_KDF-X942-CONCAT.7 \
man/man7/EVP_KDF-X963.7 \
man/man7/EVP_KEM-EC.7 \
man/man7/EVP_KEM-ML-KEM.7 \
man/man7/EVP_KEM-RSA.7 \
man/man7/EVP_KEM-X25519.7 \
man/man7/EVP_KEYEXCH-DH.7 \
@ -5304,6 +5315,7 @@ man/man7/EVP_PKEY-EC.7 \
man/man7/EVP_PKEY-FFC.7 \
man/man7/EVP_PKEY-HMAC.7 \
man/man7/EVP_PKEY-ML-DSA.7 \
man/man7/EVP_PKEY-ML-KEM.7 \
man/man7/EVP_PKEY-RSA.7 \
man/man7/EVP_PKEY-SM2.7 \
man/man7/EVP_PKEY-X25519.7 \

122
doc/designs/ML-KEM.md Normal file
View file

@ -0,0 +1,122 @@
ML-KEM Design
=============
This document covers OpenSSL specific ML-KEM implementation details.
[FIPS 203](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.203.pdf)
clearly states most of the requirements of ML-KEM and has comprehensive
pseudo code for all its algorithms.
ML-KEM Parameters & Functions
-----------------------------
There are 3 different parameter sets in FIPS 203 (see Section 8).
There are constants related to these, as well as there being a group of
functions associated with each set.
To support these variants, OpenSSL will have 3 different key managers and 3
corresponding KEM function sets. The names used are of the form "ML-KEM-768".
The key problem implementing the different variants lies in the significant
differences in (dimensions of) vectors and matrics required. For this reason,
[boringssl](https://boringssl.googlesource.com/boringssl/+/HEAD/crypto/mlkem)
chose to use C++ templates to represent the different parameter sets.
As C++ cannot be used in OpenSSL, (object) code duplication by way of use
of macros to minimize source code duplication is used. Note that C++ templates are also specialised at compile time to the specific types at which they are instantiated, so there's not in fact much difference in the resulting code size. Templates are in this regard just a cleaner, more expressive "macro" system.
ML-KEM makes extensive use of SHA3 primitives, SHA3-256, SHA3-512, SHAKE256 and SHAKE128.
To improve ML-KEM execution performance the EVP handles for these are pre-fetched during ML-KEM
key initialisation and stored in an ossl_ml_kem_ctx object.
These are then used in key generation, encapsulation and decapsulation.
The context is also duplicated (EVP_MD handles uprefed) when the ML-KEM key is duplicated.
This ossl_ml_kem_ctx is then passed to all functions.
As already noted, it is presently allocated on a per-key basis in the providers'
ML-KEM key context, but if there's some way to do this just once during provider
initialisation, or once per thread, ... performance might noticeably improve.
ML-KEM keys
-----------
As expected, ML-KEM has both public and private keys.
Since the public key is exchanged between the two parties as part of key
agreement, the encoding (wire-form) of the public key is clearly defined and
there are unambiguous choices for its encoding and decoding functions.
It may be noted that the wire-form public key is "compressed".
Instead of the bulky "A" ("m" in the code) matrix, which represents the majority
of the storage required for ML-KEM public and private keys, the wire-form public
key, holds a 32-byte seed from which one can regenerate the matrix.
The full matrix is in memory in the internal form (needed for computations) of
the public key (which in our implementation is simply a reference into the internal
form of the private key when both are known).
It is possible to save space and compute the matrix elements just-in-time, as-needed,
which would not have a performance impact on the encapsulation step (typically server)
where each matrix element is used exactly once!
However, the same matrix is used both during key generation and decapsulation and
computing it twice would have a noticeable performance impact (typically on the client).
If we wanted to do just-in-time matrix computation for decapsulation, we'd need to have
a different memory layout for public keys when only the public key is known, and to change
the algorithm code to generate matrix elements on demand during encapsulation. This can
be considered later, if it is determined that the space savings (9*512 bytes in memory for
ML-KEM-768, for the full matrix, instead of 512 bytes for a just-in-time element) this could
be considered later, but the server will generally destroy the client public key soon after the
shared secret is computed, so these don't stay in memory long, so briefly saving ~2KB may
not to be of much benefit).
The private key format is somewhat ad hoc, though (to be able to fully describe the algorithms)
FIPS 203 documents a format that is commonly referred to as the "extended"
format and also exportable/importable via encoding functions in well-defined
sizes. The IETF voices interest in using the "seed-based" format (the (d,z) seed
pair from which the key is generated and can be recovered). This is supported by the
FIPS 203 internal deterministic key generation functions, which are "testing only".
We naturally use this for running the Known Answer Tests, but our private key encoding
format is the full expanded key, not the 64 byte (d,z) seed pair.
The design therefore caters to both options: The default key generation and
KEM encapsulation/decapsulation functions operate on/with "extended keys".
It is also possible to use the "seed-based" format by way of providing
specific OSSL_PARAMs made available for that purpose -- but again, as per
NIST guidance, only for testing. If the seed version is retrieved from a
normal key generation operation, it shall be subject to the same level of
protection given to private key material.
Key generation API
------------------
Keys can therefore be generated as "usual" by way of the EVP functions
EVP_PKEY_generate() and EVP_PKEY_Q_keygen().
An explicit seed can be specified by setting the OSSL_PARAM value
"OSSL_PKEY_PARAM_ML_KEM_SEED" to a 64-byte octet-string before key generation.
The octet-string value must be the concatenation of the B<d> and B<z> strings in that
order.
KEM API
-------
ML-KEM is meant to be a simple replacement for existing KEM algorithms.
Therefore, simple use should be
EVP_PKEY_encapsulate_init(), EVP_PKEY_encapsulate(),
EVP_PKEY_decapsulate_init(), EVP_PKEY_decapsulate().
For the encapsulation operation, a test-only option exists to avoid the
otherwise mandatory use of a random number generator for passing in a
known "entropy" by way of the OSSL_PARAM "OSSL_KEM_PARAM_IKME".
Buffers
-------
There are many functions passing buffers of sizes dependent on algorithm
(version). It therefore is required to properly check/allocate buffers of
suitable sizes as defined in the core "mlkem.h" header file. These size
checks are performed within the provider logic. The core crypto APIs for
any ML-KEM algorithm are not to be exposed and called by external users.
Constant Time Considerations
----------------------------
The usual constant time methods are used in the implementation. All possible
error conditions that can be detected are passed up the call stack to provide
the usual OK/NOK status for all required functions.

View file

@ -93,7 +93,8 @@ Decapsulate data using RSA:
L<EVP_PKEY_CTX_new_from_pkey(3)>,
L<EVP_PKEY_encapsulate(3)>,
L<EVP_KEM-RSA(7)>, L<EVP_KEM-X25519(7)>, L<EVP_KEM-EC(7)>
L<EVP_KEM-RSA(7)>, L<EVP_KEM-X25519(7)>, L<EVP_KEM-EC(7)>,
L<EVP_KEM-ML-KEM-512(7)>, L<EVP_KEM-ML-KEM-768(7)>, L<EVP_KEM-ML-KEM-1024(7)>
=head1 HISTORY

View file

@ -102,7 +102,8 @@ Encapsulate an RSASVE key (for RSA keys).
L<EVP_PKEY_CTX_new_from_pkey(3)>,
L<EVP_PKEY_decapsulate(3)>,
L<EVP_KEM-RSA(7)>, L<EVP_KEM-X25519(7)>, L<EVP_KEM-EC(7)>
L<EVP_KEM-RSA(7)>, L<EVP_KEM-X25519(7)>, L<EVP_KEM-EC(7)>,
L<EVP_KEM-ML-KEM-512(7)>, L<EVP_KEM-ML-KEM-768(7)>, L<EVP_KEM-ML-KEM-1024(7)>
=head1 HISTORY

View file

@ -0,0 +1,65 @@
=pod
=head1 NAME
EVP_KEM-ML-KEM-512,EVP_KEM-ML-KEM-768,EVP_KEM-ML-KEM-1024,EVP_KEM-ML-KEM
- EVP_KEM ML-KEM keytype and algorithm support
=head1 DESCRIPTION
The B<ML-KEM> keytypes and parameters are described in L<EVP_PKEY-ML-KEM(7)>.
See L<EVP_PKEY_encapsulate(3)> and L<EVP_PKEY_decapsulate(3)> for more info
regarding the basic KEM operations.
=head2 ML-KEM KEM parameters
=over 4
=item "ikme" (B<OSSL_KEM_PARAM_IKME>)<UTF8 string>
The OpenSSL ML-KEM encapsulation mechanism can only be modified by
setting randomness during encapsulation facilitating testing as per
FIPS 203, section 6.2, algorithm 17.
This parameter is not to be set for other purposes than testing.
This parameter is disabled for use in the FIPS provider (TODO(ML-KEM)).
When this parameter is not set, encapsulation proceeds as per FIPS 203,
section 7.2
This parameter is only settable.
=back
This can be set when using EVP_PKEY_encapsulate_init().
=head1 CONFORMING TO
=over 4
=item FIPS203
=back
=head1 SEE ALSO
L<EVP_PKEY_encapsulate(3)>,
L<EVP_PKEY_decapsulate(3)>
L<EVP_KEYMGMT(3)>,
L<EVP_PKEY(3)>,
L<provider-keymgmt(7)>
=head1 HISTORY
This functionality was added in OpenSSL 3.5.
=head1 COPYRIGHT
Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
Licensed under the Apache License 2.0 (the "License"). You may not use
this file except in compliance with the License. You can obtain a copy
in the file LICENSE in the source distribution or at
L<https://www.openssl.org/source/license.html>.
=cut

View file

@ -0,0 +1,113 @@
=pod
=head1 NAME
EVP_PKEY-ML-KEM-512,
EVP_PKEY-ML-KEM-768,
EVP_PKEY-ML-KEM-1024,
EVP_KEYMGMT-ML-KEM-512,
EVP_KEYMGMT-ML-KEM-768,
EVP_KEYMGMT-ML-KEM-1024,
EVP_PKEY-ML-KEM
- ML-KEM keytype and algorithm support
=head1 DESCRIPTION
The B<ML-KEM-512>, B<ML-KEM-768>, and B<ML-KEM-1024> keytypes are implemented in
OpenSSL's default provider.
=for comment (TODO(ML-KEM): Add FIPS support).
=head2 Keygen Parameters
By default, no parameters are required for generating a key pair.
=over 4
=item "seed" (B<OSSL_PKEY_PARAM_ML_KEM_SEED>) <octet string>
ML-KEM internally requires the generation of a keypair using a random value (seed).
This optional parameter can be used to set the value prior to key pair generation.
According to FIPS 203, section 3.3, this parameter should only be used for
test purposes and be treated with the same care as private key material.
The length of the seed is 64 bytes.
This parameter is only settable.
See L<provider-keymgmt(7)/Common Information Parameters> for further information.
=back
Use EVP_PKEY_CTX_set_params() after calling EVP_PKEY_keygen_init().
=head2 Common parameters
In addition to the common parameters that all keytypes should support (see
L<provider-keymgmt(7)/Common parameters>), the implementation of these keytypes
support the following.
=over 4
=item "pub" (B<OSSL_PKEY_PARAM_PUB_KEY>) <octet string>
The public key value.
This parameter is used when importing or exporting the public key value with the
EVP_PKEY_fromdata() and EVP_PKEY_todata() functions.
=item "priv" (B<OSSL_PKEY_PARAM_PRIV_KEY>) <octet string>
The private key value.
This parameter is used when importing or exporting the public key value with the
EVP_PKEY_fromdata() and EVP_PKEY_todata() functions.
=item "encoded-pub-key" (B<OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY>) <octet string>
Used for getting and setting the encoding of a public key. Public keys are
expected be encoded in a format as defined by FIPS 203.
This parameter is gettable and settable.
=back
=head1 CONFORMING TO
=over 4
=item FIPS 203
=back
=head1 EXAMPLES
An B<EVP_PKEY> context can be obtained by calling:
EVP_PKEY_CTX *pctx =
EVP_PKEY_CTX_new_from_name(NULL, "ML-KEM-768", NULL);
An B<ML-KEM-768> key can be generated like this:
pkey = EVP_PKEY_Q_keygen(NULL, NULL, "ML-KEM-768");
Equivalent calls are possible for B<ML-KEM-512> and B<ML-KEM-1024>.
=head1 SEE ALSO
L<EVP_KEYMGMT(3)>, L<EVP_PKEY(3)>, L<provider-keymgmt(7)>,
L<EVP_KEM-ML-KEM(7)>
=head1 HISTORY
This functionality was added in OpenSSL 3.5.
=head1 COPYRIGHT
Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
Licensed under the Apache License 2.0 (the "License"). You may not use
this file except in compliance with the License. You can obtain a copy
in the file LICENSE in the source distribution or at
L<https://www.openssl.org/source/license.html>.
=cut

View file

@ -229,6 +229,12 @@ The OpenSSL default provider supports these operations and algorithms:
=item EC, see L<EVP_KEM-EC(7)>
=item ML-KEM-512, see L<EVP_KEM-ML-KEM-512(7)>
=item ML-KEM-768, see L<EVP_KEM-ML-KEM-768(7)>
=item ML-KEM-1024, see L<EVP_KEM-ML-KEM-1024(7)>
=back
=head2 Asymmetric Key Management
@ -277,6 +283,12 @@ The OpenSSL default provider supports these operations and algorithms:
=item ML-DSA-87, see L<EVP_KEYMGMT-ML-DSA(7)>
=item ML-KEM-512, see L<EVP_KEYMGMT-ML-KEM-512(7)>
=item ML-KEM-768, see L<EVP_KEYMGMT-ML-KEM-768(7)>
=item ML-KEM-1024, see L<EVP_KEYMGMT-ML-KEM-1024(7)>
=back
=head2 Random Number Generation

View file

@ -502,7 +502,8 @@ L<EVP_PKEY_get_security_bits(3)>,
L<provider(7)>,
L<EVP_PKEY-X25519(7)>, L<EVP_PKEY-X448(7)>, L<EVP_PKEY-ED25519(7)>,
L<EVP_PKEY-ED448(7)>, L<EVP_PKEY-EC(7)>, L<EVP_PKEY-RSA(7)>,
L<EVP_PKEY-DSA(7)>, L<EVP_PKEY-DH(7)>, L<EVP_PKEY-ML-DSA(7)>
L<EVP_PKEY-DSA(7)>, L<EVP_PKEY-DH(7)>, L<EVP_PKEY-ML-DSA(7)>,
L<EVP_PKEY-ML-KEM(7)>.
=head1 HISTORY