Conversation
# Conflicts: # src/cryptography/hazmat/primitives/asymmetric/types.py # src/rust/cryptography-key-parsing/src/pkcs8.rs # src/rust/cryptography-key-parsing/src/spki.rs
| return rust_openssl.mlkem.from_mlkem768_public_bytes(data) | ||
|
|
||
| @abc.abstractmethod | ||
| def encapsulate(self) -> tuple[bytes, bytes]: |
| // ML-KEM returns the seed rather than a PKey because AWS-LC's | ||
| // kem_priv_encode writes the expanded key (2,400 bytes) into PKCS#8, | ||
| // not the seed. |
There was a problem hiding this comment.
I've updated it to clarify it.
I wanted to say that we can't use OpenSSL PKey construct here, so we need a second element in our ParsedPrivateKey enum.
| } | ||
|
|
||
| pub fn serialize_private_key(key: &ParsedPrivateKey) -> crate::KeySerializationResult<Vec<u8>> { | ||
| let ParsedPrivateKey::Pkey(pkey) = key; |
There was a problem hiding this comment.
Can you refactor this out into its own PR for readability
| } | ||
|
|
||
| extern "C" { | ||
| fn EVP_PKEY_kem_new_raw_public_key( |
There was a problem hiding this comment.
I don't think you need to declare these, they should just be available in ffi::
There was a problem hiding this comment.
Correct, only EVP_PKEY_keygen_deterministic is needed because it is still in experimental/ in aws-lc.
IIUC, this is Algorithm 16 in FIPS 203.
Using this function allows us to use the seed form of the private key.
src/rust/src/backend/mlkem.rs
Outdated
| format: crate::serialization::PrivateFormat, | ||
| encryption_algorithm: &pyo3::Bound<'p, pyo3::PyAny>, | ||
| ) -> CryptographyResult<pyo3::Bound<'p, pyo3::types::PyBytes>> { | ||
| if !encryption_algorithm.is_instance(&types::KEY_SERIALIZATION_ENCRYPTION.get(py)?)? { |
There was a problem hiding this comment.
Why did we end up needing to re-implement a ton of the utility function whereas that wasn't required for MLDSA?
There was a problem hiding this comment.
The problem here is that we can't represent the private key as an openssl PKey (AWS-LC's kem_priv_encode writes the expanded key into PKCS#8, not the seed), so we can't use pkey_private_bytes here.
There was a problem hiding this comment.
We have another solution by refactoring pkey_private_bytes to:
- accept the new enum ParsedPrivateKey as argument
// Replace this line with a match {}
let raw_bytes = pkey.raw_private_key()?;
return Ok(pyo3::types::PyBytes::new(py, &raw_bytes));- Revert
let parsed = cryptography_key_parsing::ParsedPrivateKey::Pkey(pkey.to_owned());- Gate before
if format == PrivateFormat::TraditionalOpenSSL {to ensure we're not reaching this for MLKem keys
The main downside is that the refactor modifies every caller of the function from &slf.borrow().pkey, to ParsedPrivateKey::Pkey(slf.borrow().pkey.to_owned())
That would avoid the deduplication here (and the need for extensive tests for each variant of the encryption part)
There was a problem hiding this comment.
If the aws-lc change to store the seed on the pkey lands, we'll need neither of these changes, right?
There was a problem hiding this comment.
Correct! Once we can represent MLKEM's key as PKey, all this complexity goes away
There was a problem hiding this comment.
Let's add a comment clearly indicating this (with a link to the issue/PR)
There was a problem hiding this comment.
Landed as aws/aws-lc#3149
In this case, I think it's better to wait for a new version of AWS-LC, so we remove this complexity?
There was a problem hiding this comment.
If we think that'll be in a release soon (<10 days), then waiting seems ok. If not, landing and then following up with the cleanup seems preferable.
There was a problem hiding this comment.
v1.72.0 has been released !
I'll updated my PR!
# Conflicts: # src/rust/cryptography-key-parsing/src/pkcs8.rs
# Conflicts: # src/cryptography/hazmat/primitives/asymmetric/types.py
| } | ||
|
|
||
| extern "C" { | ||
| fn EVP_PKEY_keygen_deterministic( |
There was a problem hiding this comment.
can you add a comment that this is needed because its in the expiremental header
There was a problem hiding this comment.
(The review comment got displaced by GitHub UI, but a comment was added Line 42 )
src/rust/src/backend/keys.rs
Outdated
| #[cfg(CRYPTOGRAPHY_IS_AWSLC)] | ||
| cryptography_key_parsing::ParsedPrivateKey::MlKem(variant, seed) => { | ||
| let pkey = cryptography_openssl::mlkem::new_from_seed(variant, &seed)?; | ||
| Ok( |
There was a problem hiding this comment.
should probably match on variant here?
src/rust/src/backend/keys.rs
Outdated
| let pub_len = pkey.raw_public_key()?.len(); | ||
| assert_eq!( |
There was a problem hiding this comment.
Can we do the match pattern here (like mldsa) so it's ready for other variants
src/rust/src/backend/mlkem.rs
Outdated
| format: crate::serialization::PrivateFormat, | ||
| encryption_algorithm: &pyo3::Bound<'p, pyo3::PyAny>, | ||
| ) -> CryptographyResult<pyo3::Bound<'p, pyo3::types::PyBytes>> { | ||
| if !encryption_algorithm.is_instance(&types::KEY_SERIALIZATION_ENCRYPTION.get(py)?)? { |
There was a problem hiding this comment.
Let's add a comment clearly indicating this (with a link to the issue/PR)
| ss_n = key.decapsulate(binascii.unhexlify(vector["ct_n"])) | ||
| assert ss_n == binascii.unhexlify(vector["ss_n"]) | ||
|
|
||
| @pytest.mark.parametrize( |
There was a problem hiding this comment.
I would like a test or two that load a specific key and asserts about the parsed results.
There was a problem hiding this comment.
I've added a test for the serialization, but I don't think we can test reliably the encryption part.
(Added as part of this PR, but it contains two new test vectors. If you agree with the approach, I'll move them in a separate PR)
| skip_message="Requires a backend with ML-KEM-768 support", | ||
| ) | ||
| @wycheproof_tests("mlkem_768_encaps_test.json") | ||
| def test_mlkem768_encaps(backend, wycheproof): |
There was a problem hiding this comment.
Do we have private key to decap and verify it round trips?
There was a problem hiding this comment.
I believe this is covered by the test_kat_vectors in tests/hazmat/primitives/test_mlkem.py.
We decapsulate there the ciphertext ct, and verify that the shared secret is correct .
But I think I'm not understanding your comment here.
| } | ||
|
|
||
| pub fn encapsulate( | ||
| variant: MlKemVariant, |
There was a problem hiding this comment.
Do we need to pass variant, or can we extract it from pkey? (I want to avoid them not being consistent with each other)
There was a problem hiding this comment.
Updated to not use the variant here.
Add the support for ML-KEM using AWS-LC as the backend.
The PR is massive (sorry), about 1000 lines, but I could not reduce it more.
It follows closely the pattern of MLDSA, with the latest changes (class cases, variant enum)
A following PR with the documentation will be opened once this one get merged.
(Note: until aws/aws-lc#3140 is fixed, we have to store the ML-KEM seed on our side)