-
Notifications
You must be signed in to change notification settings - Fork 1.7k
MLDSA65 support for AWS-LC #14404
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
MLDSA65 support for AWS-LC #14404
Changes from 28 commits
176e34b
65ab941
4fab32f
2450b41
ef4345f
2f6b313
4fe06c7
ed6d9de
b60d88b
39c9db3
db6d98d
c78a527
7bde7d5
a8083a4
f849147
7284fec
16bd0d3
b66fdca
67c5374
e457a27
8cb4c7e
a532164
c56210c
b2cd7dd
f492ca3
d517b35
530aa92
4b8430c
1f1303a
7a6f3a2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| # This file is dual licensed under the terms of the Apache License, Version | ||
| # 2.0, and the BSD License. See the LICENSE file in the root of this repository | ||
| # for complete details. | ||
|
|
||
| from cryptography.hazmat.primitives.asymmetric import mldsa | ||
| from cryptography.utils import Buffer | ||
|
|
||
| class MlDsa65PrivateKey: ... | ||
| class MlDsa65PublicKey: ... | ||
|
|
||
| def generate_key() -> mldsa.MlDsa65PrivateKey: ... | ||
| def from_public_bytes(data: bytes) -> mldsa.MlDsa65PublicKey: ... | ||
| def from_seed_bytes(data: Buffer) -> mldsa.MlDsa65PrivateKey: ... |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,155 @@ | ||
| # This file is dual licensed under the terms of the Apache License, Version | ||
| # 2.0, and the BSD License. See the LICENSE file in the root of this repository | ||
| # for complete details. | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import abc | ||
|
|
||
| from cryptography.exceptions import UnsupportedAlgorithm, _Reasons | ||
| from cryptography.hazmat.bindings._rust import openssl as rust_openssl | ||
| from cryptography.hazmat.primitives import _serialization | ||
| from cryptography.utils import Buffer | ||
|
|
||
|
|
||
| class MlDsa65PublicKey(metaclass=abc.ABCMeta): | ||
| @classmethod | ||
| def from_public_bytes(cls, data: bytes) -> MlDsa65PublicKey: | ||
| from cryptography.hazmat.backends.openssl.backend import backend | ||
|
|
||
| if not backend.mldsa_supported(): | ||
| raise UnsupportedAlgorithm( | ||
| "ML-DSA-65 is not supported by this backend.", | ||
| _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, | ||
| ) | ||
|
|
||
| return rust_openssl.mldsa.from_public_bytes(data) | ||
|
|
||
| @abc.abstractmethod | ||
| def public_bytes( | ||
| self, | ||
| encoding: _serialization.Encoding, | ||
| format: _serialization.PublicFormat, | ||
| ) -> bytes: | ||
| """ | ||
| The serialized bytes of the public key. | ||
| """ | ||
|
|
||
| @abc.abstractmethod | ||
| def public_bytes_raw(self) -> bytes: | ||
| """ | ||
| The raw bytes of the public key. | ||
| Equivalent to public_bytes(Raw, Raw). | ||
|
|
||
| The public key is 1,952 bytes for MLDSA-65. | ||
| """ | ||
|
|
||
| @abc.abstractmethod | ||
| def verify( | ||
| self, | ||
| signature: Buffer, | ||
| data: Buffer, | ||
| context: Buffer | None = None, | ||
| ) -> None: | ||
| """ | ||
alex marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| Verify the signature. | ||
| """ | ||
|
|
||
| @abc.abstractmethod | ||
| def __eq__(self, other: object) -> bool: | ||
| """ | ||
| Checks equality. | ||
| """ | ||
|
|
||
| @abc.abstractmethod | ||
| def __copy__(self) -> MlDsa65PublicKey: | ||
| """ | ||
| Returns a copy. | ||
| """ | ||
|
|
||
| @abc.abstractmethod | ||
| def __deepcopy__(self, memo: dict) -> MlDsa65PublicKey: | ||
| """ | ||
| Returns a deep copy. | ||
| """ | ||
|
|
||
|
|
||
| if hasattr(rust_openssl, "mldsa"): | ||
| MlDsa65PublicKey.register(rust_openssl.mldsa.MlDsa65PublicKey) | ||
|
|
||
|
|
||
| class MlDsa65PrivateKey(metaclass=abc.ABCMeta): | ||
| @classmethod | ||
| def generate(cls) -> MlDsa65PrivateKey: | ||
| from cryptography.hazmat.backends.openssl.backend import backend | ||
|
|
||
| if not backend.mldsa_supported(): | ||
| raise UnsupportedAlgorithm( | ||
| "ML-DSA-65 is not supported by this backend.", | ||
| _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, | ||
| ) | ||
|
|
||
| return rust_openssl.mldsa.generate_key() | ||
|
|
||
| @classmethod | ||
| def from_seed_bytes(cls, data: Buffer) -> MlDsa65PrivateKey: | ||
| from cryptography.hazmat.backends.openssl.backend import backend | ||
|
|
||
| if not backend.mldsa_supported(): | ||
| raise UnsupportedAlgorithm( | ||
| "ML-DSA-65 is not supported by this backend.", | ||
| _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, | ||
| ) | ||
|
|
||
| return rust_openssl.mldsa.from_seed_bytes(data) | ||
|
|
||
| @abc.abstractmethod | ||
| def public_key(self) -> MlDsa65PublicKey: | ||
| """ | ||
| The MlDsa65PublicKey derived from the private key. | ||
| """ | ||
|
|
||
| @abc.abstractmethod | ||
| def private_bytes( | ||
DarkaMaul marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| self, | ||
| encoding: _serialization.Encoding, | ||
| format: _serialization.PrivateFormat, | ||
| encryption_algorithm: _serialization.KeySerializationEncryption, | ||
| ) -> bytes: | ||
| """ | ||
| The serialized bytes of the private key. | ||
|
|
||
| This method only returns the serialization of the seed form of the | ||
| private key, never the expanded one. | ||
| """ | ||
|
|
||
| @abc.abstractmethod | ||
| def private_bytes_raw(self) -> bytes: | ||
| """ | ||
| The raw bytes of the private key. | ||
| Equivalent to private_bytes(Raw, Raw, NoEncryption()). | ||
alex marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| This method only returns the seed form of the private key (32 bytes). | ||
| """ | ||
|
|
||
| @abc.abstractmethod | ||
| def sign(self, data: Buffer, context: Buffer | None = None) -> bytes: | ||
| """ | ||
| Signs the data. | ||
| """ | ||
|
|
||
| @abc.abstractmethod | ||
| def __copy__(self) -> MlDsa65PrivateKey: | ||
| """ | ||
| Returns a copy. | ||
| """ | ||
|
|
||
| @abc.abstractmethod | ||
| def __deepcopy__(self, memo: dict) -> MlDsa65PrivateKey: | ||
| """ | ||
| Returns a deep copy. | ||
| """ | ||
|
|
||
|
|
||
| if hasattr(rust_openssl, "mldsa"): | ||
| MlDsa65PrivateKey.register(rust_openssl.mldsa.MlDsa65PrivateKey) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,6 +22,16 @@ pub struct PrivateKeyInfo<'a> { | |
| pub attributes: Option<Attributes<'a>>, | ||
| } | ||
|
|
||
| // RFC 9881 Section 6.5 | ||
| #[cfg(CRYPTOGRAPHY_IS_AWSLC)] | ||
| // NO-COVERAGE-START | ||
| #[derive(asn1::Asn1Read, asn1::Asn1Write)] | ||
| // NO-COVERAGE-END | ||
|
||
| pub enum MlDsaPrivateKey<'a> { | ||
| #[implicit(0)] | ||
| Seed(&'a [u8]), | ||
|
||
| } | ||
|
|
||
| pub fn parse_private_key( | ||
| data: &[u8], | ||
| ) -> KeyParsingResult<openssl::pkey::PKey<openssl::pkey::Private>> { | ||
|
|
@@ -108,6 +118,13 @@ pub fn parse_private_key( | |
| )?) | ||
| } | ||
|
|
||
| #[cfg(CRYPTOGRAPHY_IS_AWSLC)] | ||
| AlgorithmParameters::MlDsa65 => { | ||
| let MlDsaPrivateKey::Seed(seed) = | ||
| asn1::parse_single::<MlDsaPrivateKey<'_>>(k.private_key)?; | ||
| Ok(cryptography_openssl::mldsa::new_raw_private_key(seed)?) | ||
| } | ||
|
|
||
| _ => Err(KeyParsingError::UnsupportedKeyType( | ||
| k.algorithm.oid().clone(), | ||
| )), | ||
|
|
@@ -443,6 +460,12 @@ pub fn serialize_private_key( | |
|
|
||
| (params, private_key_der) | ||
| } | ||
| #[cfg(CRYPTOGRAPHY_IS_AWSLC)] | ||
| cryptography_openssl::mldsa::PKEY_ID => { | ||
| let seed = pkey.raw_private_key()?; | ||
alex marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| let private_key_der = asn1::write_single(&MlDsaPrivateKey::Seed(seed.as_slice()))?; | ||
| (AlgorithmParameters::MlDsa65, private_key_der) | ||
| } | ||
alex marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| _ => { | ||
| unimplemented!("Unknown key type"); | ||
| } | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.