summaryrefslogtreecommitdiffstats
path: root/openpgp
diff options
context:
space:
mode:
Diffstat (limited to 'openpgp')
-rw-r--r--openpgp/NEWS5
-rw-r--r--openpgp/src/cert.rs65
-rw-r--r--openpgp/src/cert/amalgamation.rs21
-rw-r--r--openpgp/src/crypto/asymmetric.rs31
-rw-r--r--openpgp/src/crypto/backend/botan/ecdh.rs36
-rw-r--r--openpgp/src/crypto/backend/cng/asymmetric.rs15
-rw-r--r--openpgp/src/crypto/backend/cng/ecdh.rs69
-rw-r--r--openpgp/src/crypto/backend/nettle/ecdh.rs51
-rw-r--r--openpgp/src/crypto/backend/openssl/ecdh.rs29
-rw-r--r--openpgp/src/crypto/backend/rust/ecdh.rs45
-rw-r--r--openpgp/src/packet/key.rs45
-rw-r--r--openpgp/src/packet/signature.rs24
-rw-r--r--openpgp/src/packet/signature/cache.rs634
13 files changed, 829 insertions, 241 deletions
diff --git a/openpgp/NEWS b/openpgp/NEWS
index 0e50791d..c30b350d 100644
--- a/openpgp/NEWS
+++ b/openpgp/NEWS
@@ -42,6 +42,11 @@
- ComponentBundle::other_revocations
- ComponentBundle::self_revocations
- ComponentBundle::self_signatures
+ - Add a signature verification cache, which is automatically
+ consulted by the low-level signature verification functions, like
+ `Signature::verify_digest`.
+ - openpgp::packet::signature::cache::SignatureVerificationCache
+ - openpgp::packet::signature::cache::Entry
* Changes in 1.20.0
** New functionality
- S2K::Implicit
diff --git a/openpgp/src/cert.rs b/openpgp/src/cert.rs
index ebc9c8fd..105a69c0 100644
--- a/openpgp/src/cert.rs
+++ b/openpgp/src/cert.rs
@@ -1530,10 +1530,11 @@ impl Cert {
$sig_type_pat:pat, // pattern to test signature types against
$($hash_args:expr),* // additional arguments to pass to hash_method
) => ({
- t!("check!({}, {}, {:?}, {}, ...)",
- $desc, stringify!($binding), $binding.$sigs,
+ let sigs = $binding.$sigs.take();
+ t!("check!({}, {}, {} ({:?}), {}, ...)",
+ $desc, stringify!($binding), sigs.len(), sigs,
stringify!($hash_method));
- for sig in $binding.$sigs.take().into_iter() {
+ for sig in sigs.into_iter() {
// Use hash prefix as heuristic.
let key = self.primary.key();
match sig.hash_algo().context().and_then(|mut ctx| {
@@ -1592,10 +1593,11 @@ impl Cert {
$sig_type_pat:pat, // pattern to test signature types against
$($verify_args:expr),* // additional arguments to pass to the above
) => ({
- t!("check_3rd_party!({}, {}, {:?}, {}, {}, ...)",
- $desc, stringify!($binding), $binding.$sigs,
+ let sigs = mem::take(&mut $binding.$sigs);
+ t!("check_3rd_party!({}, {}, {} ({:?}_, {}, {}, ...)",
+ $desc, stringify!($binding), sigs.len(), sigs,
stringify!($verify_method), stringify!($hash_method));
- for sig in mem::take(&mut $binding.$sigs) {
+ for sig in sigs {
// Use hash prefix as heuristic.
let key = self.primary.key();
match sig.hash_algo().context().and_then(|mut ctx| {
@@ -1678,6 +1680,10 @@ impl Cert {
verify_primary_key_revocation, hash_direct_key,
KeyRevocation);
+ // Attestations are never associated with a primary key. If
+ // there are any, they need to be reordered.
+ self.bad.append(&mut self.primary.attestations.take());
+
for ua in self.userids.iter_mut() {
check!(format!("userid \"{}\"",
String::from_utf8_lossy(ua.userid().value())),
@@ -1762,6 +1768,10 @@ impl Cert {
verify_subkey_revocation, hash_subkey_binding,
SubkeyRevocation,
binding.key());
+
+ // Attestations are never associated with a subkey. If
+ // there are any, they need to be reordered.
+ self.bad.append(&mut binding.attestations.take());
}
// See if the signatures that didn't validate are just out of
@@ -1773,6 +1783,7 @@ impl Cert {
(None, sig)
})
.collect();
+ t!("Attempting to reorder {} signatures", bad_sigs.len());
// Do the same for signatures on unknown components, but
// remember where we took them from.
@@ -1815,9 +1826,9 @@ impl Cert {
$($verify_args:expr),* // additional arguments for the above
) => ({
if is_selfsig {
- t!("check_one!({}, {:?}, {:?}, {}, ...)",
- $desc, $sigs, $sig,
- stringify!($hash_method));
+ t!("check_one!({}, {:?}, {:?}/{}, {}, ...)",
+ $desc, $sigs, $sig, $sig.typ(),
+ stringify!($hash_method));
// Use hash prefix as heuristic.
let key = self.primary.key();
if let Ok(hash) = $sig.hash_algo().context()
@@ -7351,6 +7362,42 @@ Pu1xwz57O4zo1VYf6TqHJzVC3OMvMUM2hhdecMUe5x6GorNaj6g=
Ok(())
}
+ /// Makes sure that attested key signatures are correctly reordered.
+ #[test]
+ fn attested_key_signature_out_of_order() -> Result<()> {
+ let p = &crate::policy::StandardPolicy::new();
+
+ let (alice, _) = CertBuilder::general_purpose(
+ None, Some("alice@example.org")).generate().unwrap();
+ assert!(alice.keys().subkeys().count() > 0);
+ let mut alice_signer =
+ alice.primary_key().key().clone().parts_into_secret()?
+ .into_keypair()?;
+
+ // Now, create new attestation signatures.
+ let mut attestation_signatures = Vec::new();
+ for uid in alice.userids() {
+ attestation_signatures.append(&mut uid.attest_certifications(
+ p,
+ &mut alice_signer,
+ uid.certifications(),
+ )?);
+ }
+
+ // Add the new signatures. This appends the attestation
+ // signature so that it is considered part of last component,
+ // a subkey.
+ let alice2 = alice.insert_packets(attestation_signatures)?;
+
+ // Now we make sure the attestation signature was correctly reordered.
+ assert_eq!(alice2.bad_signatures().count(), 0);
+ assert!(alice2.keys().all(|ka| ka.attestations().count() == 0));
+ let ua = alice2.userids().next().unwrap();
+ assert_eq!(ua.attestations().count(), 1);
+
+ Ok(())
+ }
+
/// Makes sure that marker packets are ignored when parsing certs.
#[test]
fn marker_packets() -> Result<()> {
diff --git a/openpgp/src/cert/amalgamation.rs b/openpgp/src/cert/amalgamation.rs
index f65c588c..f4c024e4 100644
--- a/openpgp/src/cert/amalgamation.rs
+++ b/openpgp/src/cert/amalgamation.rs
@@ -1405,14 +1405,13 @@ impl<'a> UserIDAmalgamation<'a> {
/// This feature is [experimental](crate#experimental-features).
///
/// Allows the certificate owner to attest to third party
- /// certifications. See [Section 5.2.3.30 of RFC 4880bis] for
- /// details. This can be used to address certificate flooding
- /// concerns.
+ /// certifications. See [draft-dkg-openpgp-1pa3pc] for details.
+ /// This can be used to address certificate flooding concerns.
///
/// A policy is needed, because the expiration is updated by
/// updating the current binding signatures.
///
- /// [Section 5.2.3.30 of RFC 4880bis]: https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-10.html#section-5.2.3.30
+ /// [draft-dkg-openpgp-1pa3pc]: https://www.ietf.org/archive/id/draft-dkg-openpgp-1pa3pc-00.html
///
/// # Examples
///
@@ -1583,8 +1582,18 @@ where C: IntoIterator<Item = S>,
// Backdate the signature a little so that we can immediately
// override it.
use crate::packet::signature::SIG_BACKDATE_BY;
- let creation_time =
- crate::now() - time::Duration::new(SIG_BACKDATE_BY, 0);
+
+ let now = crate::now();
+ let mut creation_time =
+ now - time::Duration::new(SIG_BACKDATE_BY, 0);
+
+ // ... but don't backdate it further than the key's creation
+ // time, which would make it invalid.
+ let key_creation_time = primary_signer.public().creation_time();
+ if creation_time < key_creation_time {
+ // ... unless that would make it is later than now.
+ creation_time = key_creation_time.min(now);
+ }
let template = SignatureBuilder::new(SignatureType::AttestationKey)
.set_signature_creation_time(creation_time)?;
diff --git a/openpgp/src/crypto/asymmetric.rs b/openpgp/src/crypto/asymmetric.rs
index 6420048d..b83ce0ba 100644
--- a/openpgp/src/crypto/asymmetric.rs
+++ b/openpgp/src/crypto/asymmetric.rs
@@ -257,9 +257,40 @@ impl Decryptor for KeyPair {
plaintext_len: Option<usize>)
-> Result<SessionKey>
{
+ use crate::crypto::backend::{Backend, interface::Asymmetric};
+
self.secret().map(|secret| {
+ #[allow(non_snake_case)]
#[allow(clippy::match_single_binding)]
match (self.public().mpis(), secret, ciphertext) {
+ (mpi::PublicKey::ECDH { curve: Curve::Cv25519, .. },
+ mpi::SecretKeyMaterial::ECDH { scalar, },
+ mpi::Ciphertext::ECDH { e, .. }) =>
+ {
+ // Get the public part V of the ephemeral key.
+ let V = e.decode_point(&Curve::Cv25519)?.0;
+
+ // X25519 expects the private key to be exactly 32
+ // bytes long but OpenPGP allows leading zeros to
+ // be stripped. Padding has to be unconditional;
+ // otherwise we have a secret-dependent branch.
+ let mut r = scalar.value_padded(32);
+
+ // Reverse the scalar. See
+ // https://lists.gnupg.org/pipermail/gnupg-devel/2018-February/033437.html
+ r.reverse();
+
+ // Compute the shared point S = rV = rvG, where
+ // (r, R) is the recipient's key pair.
+ dbg!(r.as_ref());
+ dbg!(&V);
+ let S = dbg!(Backend::x25519_shared_point(&r, &V.try_into()?))?;
+
+ crate::crypto::ecdh::decrypt_unwrap2(
+ self.public(), &S, ciphertext, plaintext_len)
+
+ },
+
(_public, secret, _ciphertext) =>
self.decrypt_backend(secret, ciphertext, plaintext_len),
}
diff --git a/openpgp/src/crypto/backend/botan/ecdh.rs b/openpgp/src/crypto/backend/botan/ecdh.rs
index 41591421..6e5da2bb 100644
--- a/openpgp/src/crypto/backend/botan/ecdh.rs
+++ b/openpgp/src/crypto/backend/botan/ecdh.rs
@@ -31,21 +31,8 @@ pub fn encrypt<R>(recipient: &Key<key::PublicParts, R>,
ref curve, ref q,..
} = recipient.mpis() {
match curve {
- Curve::Cv25519 => {
- // Obtain the recipient public key R
- let R = &q.decode_point(curve)?.0;
-
- // Generate an ephemeral key pair {v, V=vG}
- let v = Privkey::create("Curve25519", "", &mut rng)?;
- let V = v.pubkey()?.get_x25519_key()?;
-
- // Compute the shared point S = vR;
- let S: Protected = v.agree(&R, 32, b"", "Raw")?.into();
-
- encrypt_wrap(recipient, session_key,
- MPI::new_compressed_point(&V),
- &S)
- },
+ Curve::Cv25519 =>
+ Err(Error::InvalidArgument("implemented elsewhere".into()).into()),
// N/A
Curve::Unknown(_) if ! curve.is_brainpoolp384() =>
@@ -96,23 +83,8 @@ pub fn decrypt<R>(recipient: &Key<key::PublicParts, R>,
Ciphertext::ECDH { ref e, .. }) =>
{
let S: Protected = match curve {
- Curve::Cv25519 => {
- // Get the public part V of the ephemeral key.
- let V = e.decode_point(curve)?.0;
-
- // Get our secret key.
- let mut r = scalar.value_padded(32);
-
- // Reverse the scalar. See
- // https://lists.gnupg.org/pipermail/gnupg-devel/2018-February/033437.html.
- r.reverse();
- let r = Privkey::load_x25519(&r)?;
-
- // Compute the shared point S = rV = rvG, where (r, R)
- // is the recipient's key pair.
- r.agree(&V, 32, b"", "Raw")?.into()
- },
-
+ Curve::Cv25519 => return
+ Err(Error::InvalidArgument("implemented elsewhere".into()).into()),
// N/A
Curve::Unknown(_) if ! curve.is_brainpoolp384() => return
diff --git a/openpgp/src/crypto/backend/cng/asymmetric.rs b/openpgp/src/crypto/backend/cng/asymmetric.rs
index 4bd8fa70..b7c17a49 100644
--- a/openpgp/src/crypto/backend/cng/asymmetric.rs
+++ b/openpgp/src/crypto/backend/cng/asymmetric.rs
@@ -68,7 +68,10 @@ impl Asymmetric for super::Backend {
let mut public = [0u8; 32];
public.copy_from_slice(pair.x());
- Ok((pair.d().into(), public))
+ let mut clamped_secret = pair.d().into();
+ Self::x25519_clamp_secret(&mut clamped_secret);
+
+ Ok((clamped_secret, public))
}
fn x25519_derive_public(secret: &Protected) -> Result<[u8; 32]> {
@@ -79,9 +82,12 @@ impl Asymmetric for super::Backend {
let provider = AsymmetricAlgorithm::open(
AsymmetricAlgorithmId::Ecdh(NamedCurve::Curve25519)
)?;
+
+ let mut clamped_secret = secret.clone();
+ Self::x25519_clamp_secret(&mut clamped_secret);
let key = AsymmetricKey::<Ecdh<Curve25519>, Private>::import_from_parts(
&provider,
- secret,
+ &clamped_secret,
)?;
Ok(<[u8; 32]>::try_from(&key.export()?.x()[..])?)
}
@@ -101,10 +107,13 @@ impl Asymmetric for super::Backend {
&provider,
public,
)?;
+
+ let mut clamped_secret = secret.clone();
+ Self::x25519_clamp_secret(&mut clamped_secret);
let secret =
AsymmetricKey::<Ecdh<Curve25519>, Private>::import_from_parts(
&provider,
- secret,
+ &clamped_secret,
)?;
let shared = secret_agreement(&secret, &public)?;
diff --git a/openpgp/src/crypto/backend/cng/ecdh.rs b/openpgp/src/crypto/backend/cng/ecdh.rs
index afa688d1..285a408c 100644
--- a/openpgp/src/crypto/backend/cng/ecdh.rs
+++ b/openpgp/src/crypto/backend/cng/ecdh.rs
@@ -32,34 +32,9 @@ where
};
match curve {
- Curve::Cv25519 => {
- // Obtain the authenticated recipient public key R
- let R = q.decode_point(curve)?.0;
- let provider = AsymmetricAlgorithm::open(AsymmetricAlgorithmId::Ecdh(NamedCurve::Curve25519))?;
- let recipient_key = AsymmetricKey::<Ecdh<Curve25519>, Public>::import_from_parts(
- &provider,
- R,
- )?;
+ Curve::Cv25519 => return
+ Err(Error::InvalidArgument("implemented elsewhere".into()).into()),
- // Generate an ephemeral key pair {v, V=vG}
- let ephemeral = AsymmetricKey::builder(Ecdh(Curve25519)).build().unwrap();
-
- // Compute the public key. We need to add an encoding
- // octet in front of the key.
- let blob = ephemeral.export().unwrap();
- let mut VB = [0; 33];
- VB[0] = 0x40;
- VB[1..].copy_from_slice(blob.x());
- let VB = MPI::new(&VB);
-
- // Compute the shared point S = vR;
- let secret = cng::asymmetric::agreement::secret_agreement(&ephemeral, &recipient_key)?;
- let mut S = Protected::from(secret.derive_raw()?);
- // Returned secret is little-endian, flip it to big-endian
- S.reverse();
-
- encrypt_wrap(recipient, session_key, VB, &S)
- }
Curve::NistP256 | Curve::NistP384 | Curve::NistP521 => {
let (Rx, Ry) = q.decode_point(curve)?;
@@ -166,44 +141,8 @@ where
};
let S: Protected = match curve {
- Curve::Cv25519 => {
- // Get the public part V of the ephemeral key.
- let V = e.decode_point(curve)?.0;
-
- let provider = AsymmetricAlgorithm::open(AsymmetricAlgorithmId::Ecdh(NamedCurve::Curve25519))?;
- let V = AsymmetricKey::<Ecdh<Curve25519>, Public>::import_from_parts(
- &provider,
- V,
- )?;
-
- let mut scalar = scalar.value_padded(32);
- // Reverse the scalar. See
- // https://lists.gnupg.org/pipermail/gnupg-devel/2018-February/033437.html.
- scalar.reverse();
-
- // Some bits must be clamped. Usually, this is done
- // during key creation. However, if that is not done, we
- // should do that before handing it to CNG. See
- // Curve25519 Paper, Sec. 3:
- //
- // > A user can, for example, generate 32 uniform random
- // > bytes, clear bits 0, 1, 2 of the first byte, clear bit
- // > 7 of the last byte, and set bit 6 of the last byte.
- scalar[0] &= 0b1111_1000;
- scalar[CURVE25519_SIZE - 1] &= !0b1000_0000;
- scalar[CURVE25519_SIZE - 1] |= 0b0100_0000;
-
- let r = AsymmetricKey::<Ecdh<Curve25519>, Private>::import_from_parts(
- &provider,
- &scalar,
- )?;
-
- let secret = cng::asymmetric::agreement::secret_agreement(&r, &V)?;
- // Returned secret is little-endian, flip it to big-endian
- let mut secret = secret.derive_raw()?;
- secret.reverse();
- secret.into()
- }
+ Curve::Cv25519 => return
+ Err(Error::InvalidArgument("implemented elsewhere".into()).into()),
Curve::NistP256 | Curve::NistP384 | Curve::NistP521 => {
// Get the public part V of the ephemeral key and
diff --git a/openpgp/src/crypto/backend/nettle/ecdh.rs b/openpgp/src/crypto/backend/nettle/ecdh.rs
index 69cf4752..a3fa9775 100644
--- a/openpgp/src/crypto/backend/nettle/ecdh.rs
+++ b/openpgp/src/crypto/backend/nettle/ecdh.rs
@@ -1,6 +1,6 @@
//! Elliptic Curve Diffie-Hellman.
-use nettle::{curve25519, ecc, ecdh, random::Yarrow};
+use nettle::{ecc, ecdh, random::Yarrow};
use crate::{Error, Result};
use crate::crypto::SessionKey;
@@ -23,28 +23,9 @@ pub fn encrypt<R>(recipient: &Key<key::PublicParts, R>,
ref curve, ref q,..
} = recipient.mpis() {
match curve {
- Curve::Cv25519 => {
- // Obtain the authenticated recipient public key R
- let R = q.decode_point(curve)?.0;
+ Curve::Cv25519 =>
+ Err(Error::InvalidArgument("implemented elsewhere".into()).into()),
- // Generate an ephemeral key pair {v, V=vG}
- let v: Protected =
- curve25519::private_key(&mut rng).into();
-
- // Compute the public key.
- let mut VB = [0; curve25519::CURVE25519_SIZE];
- curve25519::mul_g(&mut VB, &v)
- .expect("buffers are of the wrong size");
- let VB = MPI::new_compressed_point(&VB);
-
- // Compute the shared point S = vR;
- let mut S: Protected =
- vec![0; curve25519::CURVE25519_SIZE].into();
- curve25519::mul(&mut S, &v, R)
- .expect("buffers are of the wrong size");
-
- encrypt_wrap(recipient, session_key, VB, &S)
- }
Curve::NistP256 | Curve::NistP384 | Curve::NistP521 => {
// Obtain the authenticated recipient public key R and
// generate an ephemeral private key v.
@@ -130,30 +111,8 @@ pub fn decrypt<R>(recipient: &Key<key::PublicParts, R>,
Ciphertext::ECDH { ref e, .. }) =>
{
let S: Protected = match curve {
- Curve::Cv25519 => {
- // Get the public part V of the ephemeral key.
- let V = e.decode_point(curve)?.0;
-
- // Nettle expects the private key to be exactly
- // CURVE25519_SIZE bytes long but OpenPGP allows leading
- // zeros to be stripped.
- // Padding has to be unconditional; otherwise we have a
- // secret-dependent branch.
- let mut r =
- scalar.value_padded(curve25519::CURVE25519_SIZE);
-
- // Reverse the scalar. See
- // https://lists.gnupg.org/pipermail/gnupg-devel/2018-February/033437.html.
- r.reverse();
-
- // Compute the shared point S = rV = rvG, where (r, R)
- // is the recipient's key pair.
- let mut S: Protected =
- vec![0; curve25519::CURVE25519_SIZE].into();
- curve25519::mul(&mut S, &r[..], V)
- .expect("buffers are of the wrong size");
- S
- }
+ Curve::Cv25519 => return
+ Err(Error::InvalidArgument("implemented elsewhere".into()).into()),
Curve::NistP256 | Curve::NistP384 | Curve::NistP521 => {
// Get the public part V of the ephemeral key and
diff --git a/openpgp/src/crypto/backend/openssl/ecdh.rs b/openpgp/src/crypto/backend/openssl/ecdh.rs
index 04a87c23..41e6e67c 100644
--- a/openpgp/src/crypto/backend/openssl/ecdh.rs
+++ b/openpgp/src/crypto/backend/openssl/ecdh.rs
@@ -27,19 +27,7 @@ where
_ => return Err(Error::InvalidArgument("Expected an ECDHPublicKey".into()).into()),
};
if curve == &Curve::Cv25519 {
- let public = q.decode_point(curve)?.0;
-
- let public_key = PKey::public_key_from_raw_bytes(public, openssl::pkey::Id::X25519)?;
-
- let key = PKey::generate_x25519()?;
- let mut deriver = Deriver::new(&key)?;
- deriver.set_peer(&public_key)?;
-
- let secret = deriver.derive_to_vec()?.into();
-
- let q = mpi::MPI::new_compressed_point(&key.raw_public_key()?);
-
- return encrypt_wrap(recipient, session_key, q, &secret);
+ return Err(Error::InvalidArgument("implemented elsewhere".into()).into());
}
let nid = curve.try_into()?;
@@ -88,20 +76,7 @@ where
};
if curve == &Curve::Cv25519 {
- let mut scalar = scalar.value_padded(32);
- scalar.reverse();
-
- let key = PKey::private_key_from_raw_bytes(&scalar[..], openssl::pkey::Id::X25519)?;
-
- let public = e.decode_point(curve)?.0;
- let public_key = PKey::public_key_from_raw_bytes(public, openssl::pkey::Id::X25519)?;
-
- let mut deriver = Deriver::new(&key)?;
- deriver.set_peer(&public_key)?;
- let secret = deriver.derive_to_vec()?.into();
-
- return decrypt_unwrap2(recipient.role_as_unspecified(), &secret,
- ciphertext, plaintext_len);
+ return Err(Error::InvalidArgument("implemented elsewhere".into()).into());
}
let nid = curve.try_into()?;
diff --git a/openpgp/src/crypto/backend/rust/ecdh.rs b/openpgp/src/crypto/backend/rust/ecdh.rs
index 77fd7d23..f3b3d84f 100644
--- a/openpgp/src/crypto/backend/rust/ecdh.rs
+++ b/openpgp/src/crypto/backend/rust/ecdh.rs
@@ -32,34 +32,9 @@ pub fn encrypt<R>(recipient: &Key<key::PublicParts, R>,
};
let (VB, shared) = match curve {
- Curve::Cv25519 => {
- // x25519_dalek v1.1 doesn't reexport OsRng. It
- // depends on rand 0.8.
- use rand::rngs::OsRng;
- use x25519_dalek::{EphemeralSecret, PublicKey};
+ Curve::Cv25519 => return
+ Err(Error::InvalidArgument("implemented elsewhere".into()).into()),
- // Decode the recipient's public key.
- let R: [u8; CURVE25519_SIZE] = q.decode_point(curve)?.0.try_into()?;
- let recipient_key = PublicKey::from(R);
-
- // Generate a keypair and perform Diffie-Hellman.
- let secret = EphemeralSecret::random_from_rng(OsRng);
- let public = PublicKey::from(&secret);
- let shared = secret.diffie_hellman(&recipient_key);
-
- // Encode our public key. We need to add an encoding
- // octet in front of the key.
- let mut VB = [0; 1 + CURVE25519_SIZE];
- VB[0] = 0x40;
- VB[1..].copy_from_slice(public.as_bytes());
- let VB = MPI::new(&VB);
-
- // Encode the shared secret.
- let shared: &[u8] = shared.as_bytes();
- let shared = Protected::from(shared);
-
- (VB, shared)
- },
Curve::NistP256 => {
use p256::{EncodedPoint, PublicKey, ecdh::EphemeralSecret};
@@ -150,21 +125,9 @@ pub fn decrypt<R>(recipient: &Key<key::PublicParts, R>,
};
let S: Protected = match curve {
- Curve::Cv25519 => {
- use x25519_dalek::{PublicKey, StaticSecret};
+ Curve::Cv25519 => return
+ Err(Error::InvalidArgument("implemented elsewhere".into()).into()),
- // Get the public part V of the ephemeral key.
- let V: [u8; CURVE25519_SIZE] = e.decode_point(curve)?.0.try_into()?;
- let V = PublicKey::from(V);
-
- let mut scalar: [u8; CURVE25519_SIZE] =
- scalar.value_padded(CURVE25519_SIZE).as_ref().try_into()?;
- scalar.reverse();
- let r = StaticSecret::from(scalar);
-
- let secret = r.diffie_hellman(&V);
- Vec::from(secret.to_bytes()).into()
- },
Curve::NistP256 => {
use p256::{SecretKey, PublicKey};
const NISTP256_SIZE: usize = 32;
diff --git a/openpgp/src/packet/key.rs b/openpgp/src/packet/key.rs
index a6d7c660..38bcf7cd 100644
--- a/openpgp/src/packet/key.rs
+++ b/openpgp/src/packet/key.rs
@@ -742,6 +742,8 @@ impl<P, R> Key<P, R>
{
/// Encrypts the given data with this key.
pub fn encrypt(&self, data: &SessionKey) -> Result<mpi::Ciphertext> {
+ use crate::crypto::backend::{Backend, interface::Asymmetric};
+ use crate::crypto::mpi::PublicKey;
use PublicKeyAlgorithm::*;
#[allow(deprecated, non_snake_case)]
@@ -751,6 +753,29 @@ impl<P, R> Key<P, R>
format!("{} is not an encryption algorithm", self.pk_algo())
).into()),
+ ECDH if matches!(self.mpis(),
+ PublicKey::ECDH { curve: Curve::Cv25519, ..}) =>
+ {
+ let q = match self.mpis() {
+ PublicKey::ECDH { q, .. } => q,
+ _ => unreachable!(),
+ };
+
+ // Obtain the authenticated recipient public key R
+ let R = q.decode_point(&C