summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2023-05-24 14:52:27 +0200
committerJustus Winter <justus@sequoia-pgp.org>2024-03-13 10:59:50 +0100
commita112ebb5058b443961a37d8273affade2164d720 (patch)
treea6f5b10934752e5fa1fc550bae902f628176cbfa
parentdda8bc17260ba0b1d067ba41277f18ab3353dd0f (diff)
openpgp: Implement X448 and Ed448 in the backends.
-rw-r--r--openpgp/src/crypto/backend/nettle/asymmetric.rs85
-rw-r--r--openpgp/src/crypto/backend/openssl/asymmetric.rs55
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<Protected> {
+ 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<bool> {
+ 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<Protected> {
+ 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<bool> {
+ 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)>
{