summaryrefslogtreecommitdiffstats
path: root/openpgp/src
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2024-04-16 15:29:43 +0200
committerJustus Winter <justus@sequoia-pgp.org>2024-04-16 15:29:43 +0200
commit83860faa021ad1bdc3ebb1a8b0deec651c0b5e46 (patch)
tree51e00803a2ade8de9a524695261d843f60f2e999 /openpgp/src
parentf650e183e645d22873247939fedf522736863f16 (diff)
openpgp: Support NistP521 using the RustCrypto backend.
Diffstat (limited to 'openpgp/src')
-rw-r--r--openpgp/src/crypto/backend/rust/asymmetric.rs93
-rw-r--r--openpgp/src/crypto/backend/rust/ecdh.rs38
2 files changed, 128 insertions, 3 deletions
diff --git a/openpgp/src/crypto/backend/rust/asymmetric.rs b/openpgp/src/crypto/backend/rust/asymmetric.rs
index d8adf44f..a5a434f8 100644
--- a/openpgp/src/crypto/backend/rust/asymmetric.rs
+++ b/openpgp/src/crypto/backend/rust/asymmetric.rs
@@ -67,10 +67,8 @@ impl Asymmetric for super::Backend {
fn supports_curve(curve: &Curve) -> bool {
use self::Curve::*;
match curve {
- NistP256 | NistP384
+ NistP256 | NistP384 | NistP521
=> true,
- NistP521
- => false,
Ed25519 | Cv25519
=> true,
BrainpoolP256 | BrainpoolP512 | Unknown(_)
@@ -323,6 +321,31 @@ impl KeyPair {
})
},
+ Curve::NistP521 => {
+ use p521::Scalar;
+ const LEN: usize = 66;
+
+ let key = scalar.value_padded(LEN);
+ let key = Scalar::reduce_bytes(GA::try_from_slice(&key)?);
+ let dig = pad_truncating(digest, LEN);
+ let dig = GA::try_from_slice(&dig)?;
+
+ let sig = loop {
+ let mut k: Protected = vec![0; LEN].into();
+ crate::crypto::random(&mut k);
+ let k = Scalar::reduce_bytes(
+ GA::try_from_slice(&k)?);
+ if let Ok(s) = key.try_sign_prehashed(k, &dig) {
+ break s.0;
+ }
+ };
+
+ Ok(mpi::Signature::ECDSA {
+ r: MPI::new(&sig.r().to_bytes()),
+ s: MPI::new(&sig.s().to_bytes()),
+ })
+ },
+
_ => Err(Error::UnsupportedEllipticCurve(curve.clone()).into()),
},
@@ -504,6 +527,30 @@ impl<P: key::KeyParts, R: key::KeyRole> Key<P, R> {
key.verify_prehashed(&dig, &sig).map_err(bad)
},
+ Curve::NistP521 => {
+ use p521::{AffinePoint, ecdsa::Signature};
+ const LEN: usize = 66;
+
+ let key = AffinePoint::from_encoded_point(
+ &EncodedPoint::<p521::NistP521>::from_bytes(q.value())?);
+ let key = if key.is_some().into() {
+ key.unwrap()
+ } else {
+ return Err(Error::InvalidKey(
+ "Point is not on the curve".into()).into());
+ };
+
+ let sig = Signature::from_scalars(
+ GA::try_clone_from_slice(
+ &r.value_padded(LEN).map_err(bad)?)?,
+ GA::try_clone_from_slice(
+ &s.value_padded(LEN).map_err(bad)?)?)
+ .map_err(bad)?;
+ let dig = pad_truncating(digest, LEN);
+ let dig = GA::try_from_slice(&dig)?;
+ key.verify_prehashed(&dig, &sig).map_err(bad)
+ },
+
_ => Err(Error::UnsupportedEllipticCurve(curve.clone()).into()),
},
_ => Err(Error::MalformedPacket(format!(
@@ -688,6 +735,46 @@ impl<R> Key4<SecretParts, R>
Ok((PublicKeyAlgorithm::ECDH, public_mpis, private_mpis))
},
+ (Curve::NistP521, true) => {
+ use p521::{EncodedPoint, SecretKey};
+
+ let secret = SecretKey::random(
+ &mut p521::elliptic_curve::rand_core::OsRng);
+ let public = EncodedPoint::from(secret.public_key());
+
+ let public_mpis = mpi::PublicKey::ECDSA {
+ curve,
+ q: MPI::new(public.as_bytes()),
+ };
+ let private_mpis = mpi::SecretKeyMaterial::ECDSA {
+ scalar: Vec::from(secret.to_bytes().as_slice()).into(),
+ };
+
+ Ok((PublicKeyAlgorithm::ECDSA, public_mpis, private_mpis))
+ },
+
+ (Curve::NistP521, false) => {
+ use p521::{EncodedPoint, SecretKey};
+
+ let secret = SecretKey::random(
+ &mut p521::elliptic_curve::rand_core::OsRng);
+ let public = EncodedPoint::from(secret.public_key());
+
+ let public_mpis = mpi::PublicKey::ECDH {
+ q: MPI::new(public.as_bytes()),
+ hash:
+ crate::crypto::ecdh::default_ecdh_kdf_hash(&curve),
+ sym:
+ crate::crypto::ecdh::default_ecdh_kek_cipher(&curve),
+ curve,
+ };
+ let private_mpis = mpi::SecretKeyMaterial::ECDH {
+ scalar: Vec::from(secret.to_bytes().as_slice()).into(),
+ };
+
+ Ok((PublicKeyAlgorithm::ECDH, public_mpis, private_mpis))
+ },
+
_ => Err(Error::UnsupportedEllipticCurve(curve).into()),
}
}
diff --git a/openpgp/src/crypto/backend/rust/ecdh.rs b/openpgp/src/crypto/backend/rust/ecdh.rs
index eed2f827..77fd7d23 100644
--- a/openpgp/src/crypto/backend/rust/ecdh.rs
+++ b/openpgp/src/crypto/backend/rust/ecdh.rs
@@ -104,6 +104,28 @@ pub fn encrypt<R>(recipient: &Key<key::PublicParts, R>,
(VB, shared)
},
+ Curve::NistP521 => {
+ use p521::{EncodedPoint, PublicKey, ecdh::EphemeralSecret};
+
+ // Decode the recipient's public key.
+ let recipient_key = PublicKey::from_sec1_bytes(q.value())?;
+
+ // Generate a keypair and perform Diffie-Hellman.
+ let secret = EphemeralSecret::random(
+ &mut p521::elliptic_curve::rand_core::OsRng);
+ let public = EncodedPoint::from(PublicKey::from(&secret));
+ let shared = secret.diffie_hellman(&recipient_key);
+
+ // Encode our public key.
+ let VB = MPI::new(public.as_bytes());
+
+ // Encode the shared secret.
+ let shared: &[u8] = shared.raw_secret_bytes();
+ let shared = Protected::from(shared);
+
+ (VB, shared)
+ },
+
_ =>
return Err(Error::UnsupportedEllipticCurve(curve.clone()).into()),
};
@@ -175,6 +197,22 @@ pub fn decrypt<R>(recipient: &Key<key::PublicParts, R>,
Vec::from(secret.raw_secret_bytes().as_slice()).into()
},
+ Curve::NistP521 => {
+ use p521::{SecretKey, PublicKey};
+ const NISTP521_SIZE: usize = 66;
+
+ // Get the public part V of the ephemeral key.
+ let V = PublicKey::from_sec1_bytes(e.value())?;
+
+ let scalar: [u8; NISTP521_SIZE] =
+ scalar.value_padded(NISTP521_SIZE).as_ref().try_into()?;
+ let scalar = GA::try_from_slice(&scalar)?;
+ let r = SecretKey::from_bytes(&scalar)?;
+
+ let secret = diffie_hellman(r.to_nonzero_scalar(), V.as_affine());
+ Vec::from(secret.raw_secret_bytes().as_slice()).into()
+ },
+
_ => {
return Err(Error::UnsupportedEllipticCurve(curve.clone()).into());
},