From a112ebb5058b443961a37d8273affade2164d720 Mon Sep 17 00:00:00 2001 From: Justus Winter Date: Wed, 24 May 2023 14:52:27 +0200 Subject: openpgp: Implement X448 and Ed448 in the backends. --- openpgp/src/crypto/backend/nettle/asymmetric.rs | 85 +++++++++++++++++++++++- openpgp/src/crypto/backend/openssl/asymmetric.rs | 55 ++++++++++++++- 2 files changed, 137 insertions(+), 3 deletions(-) diff --git a/openpgp/src/crypto/backend/nettle/asymmetric.rs b/openpgp/src/crypto/backend/nettle/asymmetric.rs index 8108c4f9..034d246a 100644 --- a/openpgp/src/crypto/backend/nettle/asymmetric.rs +++ b/openpgp/src/crypto/backend/nettle/asymmetric.rs @@ -4,7 +4,18 @@ //! [`Decryptor`]: crate::crypto::Decryptor //! [`KeyPair`]: crate::crypto::KeyPair -use nettle::{curve25519, ecc, ecdh, ecdsa, ed25519, dsa, rsa, random::Yarrow}; +use nettle::{ + curve25519, + curve448, + dsa, + ecc, + ecdh, + ecdsa, + ed25519, + ed448, + rsa, + random::Yarrow, +}; use crate::{Error, Result}; @@ -26,7 +37,8 @@ impl Asymmetric for super::Backend { X25519 | Ed25519 | RSAEncryptSign | RSAEncrypt | RSASign | DSA | ECDH | ECDSA | EdDSA => true, - X448 | Ed448 | + X448 | Ed448 + => curve448::IS_SUPPORTED, ElGamalEncrypt | ElGamalEncryptSign | Private(_) | Unknown(_) => false, } @@ -66,6 +78,42 @@ impl Asymmetric for super::Backend { Ok(s) } + fn x448_generate_key() -> Result<(Protected, [u8; 56])> { + debug_assert_eq!(curve448::CURVE448_SIZE, 56); + if ! curve448::IS_SUPPORTED { + return Err(Error::UnsupportedPublicKeyAlgorithm( + PublicKeyAlgorithm::Ed448).into()); + } + let mut rng = Yarrow::default(); + let secret = curve448::private_key(&mut rng); + let mut public = [0; 56]; + curve448::mul_g(&mut public, &secret)?; + Ok((secret.into(), public)) + } + + fn x448_derive_public(secret: &Protected) -> Result<[u8; 56]> { + debug_assert_eq!(curve448::CURVE448_SIZE, 56); + if ! curve448::IS_SUPPORTED { + return Err(Error::UnsupportedPublicKeyAlgorithm( + PublicKeyAlgorithm::Ed448).into()); + } + let mut public = [0; 56]; + curve448::mul_g(&mut public, secret)?; + Ok(public) + } + + fn x448_shared_point(secret: &Protected, public: &[u8; 56]) + -> Result { + debug_assert_eq!(curve448::CURVE448_SIZE, 56); + if ! curve448::IS_SUPPORTED { + return Err(Error::UnsupportedPublicKeyAlgorithm( + PublicKeyAlgorithm::Ed448).into()); + } + let mut s: Protected = vec![0; 56].into(); + curve448::mul(&mut s, secret, public)?; + Ok(s) + } + fn ed25519_generate_key() -> Result<(Protected, [u8; 32])> { debug_assert_eq!(ed25519::ED25519_KEY_SIZE, 32); let mut rng = Yarrow::default(); @@ -99,6 +147,39 @@ impl Asymmetric for super::Backend { Ok(ed25519::verify(public, digest, signature)?) } + fn ed448_generate_key() -> Result<(Protected, [u8; 57])> { + debug_assert_eq!(ed448::ED448_KEY_SIZE, 57); + let mut rng = Yarrow::default(); + let mut public = [0; 57]; + let secret: Protected = + ed448::private_key(&mut rng).into(); + ed448::public_key(&mut public, &secret)?; + Ok((secret, public)) + } + + fn ed448_derive_public(secret: &Protected) -> Result<[u8; 57]> { + debug_assert_eq!(ed448::ED448_KEY_SIZE, 57); + let mut public = [0; 57]; + ed448::public_key(&mut public, secret)?; + Ok(public) + } + + fn ed448_sign(secret: &Protected, public: &[u8; 57], digest: &[u8]) + -> Result<[u8; 114]> { + debug_assert_eq!(ed448::ED448_KEY_SIZE, 57); + debug_assert_eq!(ed448::ED448_SIGNATURE_SIZE, 114); + let mut sig = [0u8; 114]; + ed448::sign(public, secret, digest, &mut sig)?; + Ok(sig) + } + + fn ed448_verify(public: &[u8; 57], digest: &[u8], signature: &[u8; 114]) + -> Result { + debug_assert_eq!(ed448::ED448_KEY_SIZE, 57); + debug_assert_eq!(ed448::ED448_SIGNATURE_SIZE, 114); + Ok(ed448::verify(public, digest, signature)?) + } + fn dsa_generate_key(p_bits: usize) -> Result<(MPI, MPI, MPI, MPI, ProtectedMPI)> { diff --git a/openpgp/src/crypto/backend/openssl/asymmetric.rs b/openpgp/src/crypto/backend/openssl/asymmetric.rs index 60768306..4caa5ed8 100644 --- a/openpgp/src/crypto/backend/openssl/asymmetric.rs +++ b/openpgp/src/crypto/backend/openssl/asymmetric.rs @@ -29,10 +29,10 @@ impl Asymmetric for super::Backend { #[allow(deprecated)] match algo { X25519 | Ed25519 | + X448 | Ed448 | RSAEncryptSign | RSAEncrypt | RSASign => true, DSA => true, ECDH | ECDSA | EdDSA => true, - X448 | Ed448 | ElGamalEncrypt | ElGamalEncryptSign | Private(_) | Unknown(_) => false, @@ -78,6 +78,30 @@ impl Asymmetric for super::Backend { Ok(deriver.derive_to_vec()?.into()) } + fn x448_generate_key() -> Result<(Protected, [u8; 56])> { + let pair = openssl::pkey::PKey::generate_x448()?; + Ok((pair.raw_private_key()?.into(), + pair.raw_public_key()?.as_slice().try_into()?)) + } + + fn x448_derive_public(secret: &Protected) -> Result<[u8; 56]> { + let key = PKey::private_key_from_raw_bytes( + secret, openssl::pkey::Id::X448)?; + Ok(key.raw_public_key()?.as_slice().try_into()?) + } + + fn x448_shared_point(secret: &Protected, public: &[u8; 56]) + -> Result { + let public = PKey::public_key_from_raw_bytes( + public, openssl::pkey::Id::X448)?; + let secret = PKey::private_key_from_raw_bytes( + secret, openssl::pkey::Id::X448)?; + + let mut deriver = Deriver::new(&secret)?; + deriver.set_peer(&public)?; + Ok(deriver.derive_to_vec()?.into()) + } + fn ed25519_generate_key() -> Result<(Protected, [u8; 32])> { let pair = openssl::pkey::PKey::generate_ed25519()?; Ok((pair.raw_private_key()?.into(), @@ -107,6 +131,35 @@ impl Asymmetric for super::Backend { Ok(verifier.verify_oneshot(signature, digest)?) } + fn ed448_generate_key() -> Result<(Protected, [u8; 57])> { + let pair = openssl::pkey::PKey::generate_ed448()?; + Ok((pair.raw_private_key()?.into(), + pair.raw_public_key()?.as_slice().try_into()?)) + } + + fn ed448_derive_public(secret: &Protected) -> Result<[u8; 57]> { + let key = PKey::private_key_from_raw_bytes( + secret, openssl::pkey::Id::ED448)?; + Ok(key.raw_public_key()?.as_slice().try_into()?) + } + + fn ed448_sign(secret: &Protected, _public: &[u8; 57], digest: &[u8]) + -> Result<[u8; 114]> { + let key = PKey::private_key_from_raw_bytes( + secret, openssl::pkey::Id::ED448)?; + + let mut signer = OpenSslSigner::new_without_digest(&key)?; + Ok(signer.sign_oneshot_to_vec(digest)?.as_slice().try_into()?) + } + + fn ed448_verify(public: &[u8; 57], digest: &[u8], signature: &[u8; 114]) + -> Result { + let key = PKey::public_key_from_raw_bytes( + public, openssl::pkey::Id::ED448)?; + let mut verifier = Verifier::new_without_digest(&key)?; + Ok(verifier.verify_oneshot(signature, digest)?) + } + fn dsa_generate_key(p_bits: usize) -> Result<(MPI, MPI, MPI, MPI, ProtectedMPI)> { -- cgit v1.2.3