summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2023-08-23 12:55:50 +0200
committerJustus Winter <justus@sequoia-pgp.org>2023-08-24 11:10:33 +0200
commit1817d2a71f80a33fd7345a5a15827acb90c2894f (patch)
tree72d92ce64f8843d45f1768034249ec524d19a4f4
parent367d9efcc6b79d04bc8dcec4303129d04215f350 (diff)
openpgp: Hand the plaintext length to decrypt_unwrap, if known.
- When using classical ECDH with the upcoming SEIPDv2, we cannot determine the expected plaintext length by looking at the cipher octet, because that is not included in the plaintext. Instead, we know it from the header of the SEIPDv2 packet, and hand the expected length to the low-level decryption functions.
-rw-r--r--openpgp/NEWS2
-rw-r--r--openpgp/src/crypto/backend/botan/asymmetric.rs5
-rw-r--r--openpgp/src/crypto/backend/botan/ecdh.rs8
-rw-r--r--openpgp/src/crypto/backend/cng/asymmetric.rs3
-rw-r--r--openpgp/src/crypto/backend/cng/ecdh.rs6
-rw-r--r--openpgp/src/crypto/backend/nettle/asymmetric.rs3
-rw-r--r--openpgp/src/crypto/backend/nettle/ecdh.rs8
-rw-r--r--openpgp/src/crypto/backend/openssl/asymmetric.rs6
-rw-r--r--openpgp/src/crypto/backend/openssl/ecdh.rs9
-rw-r--r--openpgp/src/crypto/backend/rust/asymmetric.rs5
-rw-r--r--openpgp/src/crypto/backend/rust/ecdh.rs8
-rw-r--r--openpgp/src/crypto/ecdh.rs33
-rw-r--r--openpgp/src/packet/key.rs2
13 files changed, 68 insertions, 30 deletions
diff --git a/openpgp/NEWS b/openpgp/NEWS
index ffb33b99..7cdbe82d 100644
--- a/openpgp/NEWS
+++ b/openpgp/NEWS
@@ -30,6 +30,7 @@
** New functionality
- The RustCrypto backend now supports DSA.
- crypto::SessionKey::as_protected
+ - crypto::ecdh::decrypt_unwrap2
- packet::Key::generate_dsa
- packet::Key::generate_elgamal
- parse::PacketParser::start_hashing
@@ -45,6 +46,7 @@
- types::KeyServerPreferences::as_bitfield
** Deprecated functionality
- cert::Preferences::preferred_aead_algorithms
+ - crypto::ecdh::decrypt_unwrap
- packet::signature::SignatureBuilder::set_preferred_aead_algorithms
- packet::signature::subpacket::SubpacketAreas::preferred_aead_algorithms
- packet::signature::subpacket::SubpacketTag::PreferredAEADAlgorithms
diff --git a/openpgp/src/crypto/backend/botan/asymmetric.rs b/openpgp/src/crypto/backend/botan/asymmetric.rs
index f3351570..5abd1c09 100644
--- a/openpgp/src/crypto/backend/botan/asymmetric.rs
+++ b/openpgp/src/crypto/backend/botan/asymmetric.rs
@@ -267,7 +267,7 @@ impl KeyPair {
impl KeyPair {
pub(crate) fn decrypt_backend(&self, secret: &mpi::SecretKeyMaterial, ciphertext: &mpi::Ciphertext,
- _plaintext_len: Option<usize>)
+ plaintext_len: Option<usize>)
-> Result<SessionKey>
{
fn bad(e: impl ToString) -> anyhow::Error {
@@ -307,7 +307,8 @@ impl KeyPair {
(PublicKey::ECDH{ .. },
mpi::SecretKeyMaterial::ECDH { .. },
mpi::Ciphertext::ECDH { .. }) =>
- crate::crypto::ecdh::decrypt(self.public(), secret, ciphertext)?,
+ crate::crypto::ecdh::decrypt(self.public(), secret, ciphertext,
+ plaintext_len)?,
(public, secret, ciphertext) =>
return Err(Error::InvalidOperation(format!(
diff --git a/openpgp/src/crypto/backend/botan/ecdh.rs b/openpgp/src/crypto/backend/botan/ecdh.rs
index 87eab757..41591421 100644
--- a/openpgp/src/crypto/backend/botan/ecdh.rs
+++ b/openpgp/src/crypto/backend/botan/ecdh.rs
@@ -10,7 +10,7 @@ use crate::{
Result,
};
use crate::crypto::SessionKey;
-use crate::crypto::ecdh::{encrypt_wrap, decrypt_unwrap};
+use crate::crypto::ecdh::{encrypt_wrap, decrypt_unwrap2};
use crate::crypto::mem::Protected;
use crate::crypto::mpi::{
MPI,
@@ -85,7 +85,8 @@ pub fn encrypt<R>(recipient: &Key<key::PublicParts, R>,
#[allow(non_snake_case)]
pub fn decrypt<R>(recipient: &Key<key::PublicParts, R>,
recipient_sec: &SecretKeyMaterial,
- ciphertext: &Ciphertext)
+ ciphertext: &Ciphertext,
+ plaintext_len: Option<usize>)
-> Result<SessionKey>
where R: key::KeyRole
{
@@ -138,7 +139,8 @@ pub fn decrypt<R>(recipient: &Key<key::PublicParts, R>,
},
};
- decrypt_unwrap(recipient, &S, ciphertext)
+ decrypt_unwrap2(recipient.role_as_unspecified(), &S, ciphertext,
+ plaintext_len)
}
_ =>
diff --git a/openpgp/src/crypto/backend/cng/asymmetric.rs b/openpgp/src/crypto/backend/cng/asymmetric.rs
index 5cd8f9f7..668ea7ac 100644
--- a/openpgp/src/crypto/backend/cng/asymmetric.rs
+++ b/openpgp/src/crypto/backend/cng/asymmetric.rs
@@ -449,7 +449,8 @@ impl KeyPair {
(mpi::PublicKey::ECDH{ .. },
mpi::SecretKeyMaterial::ECDH { .. },
mpi::Ciphertext::ECDH { .. }) =>
- crate::crypto::ecdh::decrypt(self.public(), secret, ciphertext)?,
+ crate::crypto::ecdh::decrypt(self.public(), secret, ciphertext,
+ plaintext_len)?,
(public, secret, ciphertext) =>
return Err(Error::InvalidOperation(format!(
diff --git a/openpgp/src/crypto/backend/cng/ecdh.rs b/openpgp/src/crypto/backend/cng/ecdh.rs
index ab687e24..afa688d1 100644
--- a/openpgp/src/crypto/backend/cng/ecdh.rs
+++ b/openpgp/src/crypto/backend/cng/ecdh.rs
@@ -7,7 +7,7 @@ use crate::packet::{key, Key};
use crate::types::Curve;
use crate::{Error, Result};
-use crate::crypto::ecdh::{encrypt_wrap, decrypt_unwrap};
+use crate::crypto::ecdh::{encrypt_wrap, decrypt_unwrap2};
use win_crypto_ng as cng;
use cng::asymmetric::{Ecdh, AsymmetricKey, Export};
@@ -153,6 +153,7 @@ pub fn decrypt<R>(
recipient: &Key<key::PublicParts, R>,
recipient_sec: &SecretKeyMaterial,
ciphertext: &Ciphertext,
+ plaintext_len: Option<usize>,
) -> Result<SessionKey>
where
R: key::KeyRole,
@@ -284,5 +285,6 @@ where
}
};
- decrypt_unwrap(recipient, &S, ciphertext)
+ decrypt_unwrap2(recipient.role_as_unspecified(), &S, ciphertext,
+ plaintext_len)
}
diff --git a/openpgp/src/crypto/backend/nettle/asymmetric.rs b/openpgp/src/crypto/backend/nettle/asymmetric.rs
index 220e8f11..405074a0 100644
--- a/openpgp/src/crypto/backend/nettle/asymmetric.rs
+++ b/openpgp/src/crypto/backend/nettle/asymmetric.rs
@@ -235,7 +235,8 @@ impl KeyPair {
(PublicKey::ECDH{ .. },
mpi::SecretKeyMaterial::ECDH { .. },
mpi::Ciphertext::ECDH { .. }) =>
- crate::crypto::ecdh::decrypt(self.public(), secret, ciphertext)?,
+ crate::crypto::ecdh::decrypt(self.public(), secret, ciphertext,
+ plaintext_len)?,
(public, secret, ciphertext) =>
return Err(Error::InvalidOperation(format!(
diff --git a/openpgp/src/crypto/backend/nettle/ecdh.rs b/openpgp/src/crypto/backend/nettle/ecdh.rs
index eea5661d..69cf4752 100644
--- a/openpgp/src/crypto/backend/nettle/ecdh.rs
+++ b/openpgp/src/crypto/backend/nettle/ecdh.rs
@@ -4,7 +4,7 @@ use nettle::{curve25519, ecc, ecdh, random::Yarrow};
use crate::{Error, Result};
use crate::crypto::SessionKey;
-use crate::crypto::ecdh::{encrypt_wrap, decrypt_unwrap};
+use crate::crypto::ecdh::{encrypt_wrap, decrypt_unwrap2};
use crate::crypto::mem::Protected;
use crate::crypto::mpi::{MPI, PublicKey, SecretKeyMaterial, Ciphertext};
use crate::packet::{key, Key};
@@ -119,7 +119,8 @@ pub fn encrypt<R>(recipient: &Key<key::PublicParts, R>,
#[allow(non_snake_case)]
pub fn decrypt<R>(recipient: &Key<key::PublicParts, R>,
recipient_sec: &SecretKeyMaterial,
- ciphertext: &Ciphertext)
+ ciphertext: &Ciphertext,
+ plaintext_len: Option<usize>)
-> Result<SessionKey>
where R: key::KeyRole
{
@@ -213,7 +214,8 @@ pub fn decrypt<R>(recipient: &Key<key::PublicParts, R>,
Err(Error::UnsupportedEllipticCurve(curve.clone()).into()),
};
- decrypt_unwrap(recipient, &S, ciphertext)
+ decrypt_unwrap2(recipient.role_as_unspecified(), &S, ciphertext,
+ plaintext_len)
}
_ =>
diff --git a/openpgp/src/crypto/backend/openssl/asymmetric.rs b/openpgp/src/crypto/backend/openssl/asymmetric.rs
index 38f97bfa..87d8623c 100644
--- a/openpgp/src/crypto/backend/openssl/asymmetric.rs
+++ b/openpgp/src/crypto/backend/openssl/asymmetric.rs
@@ -276,7 +276,7 @@ impl KeyPair {
&self,
secret: &mpi::SecretKeyMaterial,
ciphertext: &mpi::Ciphertext,
- _plaintext_len: Option<usize>,
+ plaintext_len: Option<usize>,
) -> Result<SessionKey> {
use crate::crypto::mpi::PublicKey;
@@ -305,7 +305,9 @@ impl KeyPair {
PublicKey::ECDH { .. },
mpi::SecretKeyMaterial::ECDH { .. },
mpi::Ciphertext::ECDH { .. },
- ) => crate::crypto::ecdh::decrypt(self.public(), secret, ciphertext)?,
+ ) => crate::crypto::ecdh::decrypt(self.public(), secret,
+ ciphertext,
+ plaintext_len)?,
(public, secret, ciphertext) => {
return Err(crate::Error::InvalidOperation(format!(
diff --git a/openpgp/src/crypto/backend/openssl/ecdh.rs b/openpgp/src/crypto/backend/openssl/ecdh.rs
index 662cc596..bf6237c2 100644
--- a/openpgp/src/crypto/backend/openssl/ecdh.rs
+++ b/openpgp/src/crypto/backend/openssl/ecdh.rs
@@ -1,7 +1,7 @@
//! Elliptic Curve Diffie-Hellman.
use std::convert::{TryFrom, TryInto};
-use crate::crypto::ecdh::{decrypt_unwrap, encrypt_wrap};
+use crate::crypto::ecdh::{decrypt_unwrap2, encrypt_wrap};
use crate::crypto::mpi;
use crate::crypto::mpi::{Ciphertext, SecretKeyMaterial};
use crate::crypto::SessionKey;
@@ -71,6 +71,7 @@ pub fn decrypt<R>(
recipient: &Key<key::PublicParts, R>,
recipient_sec: &SecretKeyMaterial,
ciphertext: &Ciphertext,
+ plaintext_len: Option<usize>,
) -> Result<SessionKey>
where
R: key::KeyRole,
@@ -99,7 +100,8 @@ where
deriver.set_peer(&public_key)?;
let secret = deriver.derive_to_vec()?.into();
- return decrypt_unwrap(recipient, &secret, ciphertext);
+ return decrypt_unwrap2(recipient.role_as_unspecified(), &secret,
+ ciphertext, plaintext_len);
}
let nid = curve.try_into()?;
@@ -119,5 +121,6 @@ where
deriver.set_peer(&recipient_key)?;
let secret = deriver.derive_to_vec()?.into();
- decrypt_unwrap(recipient, &secret, ciphertext)
+ decrypt_unwrap2(recipient.role_as_unspecified(), &secret, ciphertext,
+ plaintext_len)
}
diff --git a/openpgp/src/crypto/backend/rust/asymmetric.rs b/openpgp/src/crypto/backend/rust/asymmetric.rs
index 700741f7..764f6803 100644
--- a/openpgp/src/crypto/backend/rust/asymmetric.rs
+++ b/openpgp/src/crypto/backend/rust/asymmetric.rs
@@ -319,7 +319,7 @@ impl KeyPair {
impl KeyPair {
pub(crate) fn decrypt_backend(&self, secret: &mpi::SecretKeyMaterial, ciphertext: &mpi::Ciphertext,
- _plaintext_len: Option<usize>)
+ plaintext_len: Option<usize>)
-> Result<SessionKey>
{
use crate::PublicKeyAlgorithm::*;
@@ -340,7 +340,8 @@ impl KeyPair {
(mpi::PublicKey::ECDH { .. },
mpi::SecretKeyMaterial::ECDH { .. },
mpi::Ciphertext::ECDH { .. }) =>
- crate::crypto::ecdh::decrypt(self.public(), secret, ciphertext),
+ crate::crypto::ecdh::decrypt(self.public(), secret, ciphertext,
+ plaintext_len),
(public, secret, ciphertext) =>
Err(Error::InvalidOperation(format!(
diff --git a/openpgp/src/crypto/backend/rust/ecdh.rs b/openpgp/src/crypto/backend/rust/ecdh.rs
index fdec57f0..c7d4c4e1 100644
--- a/openpgp/src/crypto/backend/rust/ecdh.rs
+++ b/openpgp/src/crypto/backend/rust/ecdh.rs
@@ -7,7 +7,7 @@ use x25519_dalek_ng as x25519_dalek;
use crate::{Error, Result};
use crate::crypto::SessionKey;
use crate::crypto::mem::Protected;
-use crate::crypto::ecdh::{encrypt_wrap, decrypt_unwrap};
+use crate::crypto::ecdh::{encrypt_wrap, decrypt_unwrap2};
use crate::crypto::mpi::{self, Ciphertext, SecretKeyMaterial, MPI};
use crate::packet::{key, Key};
use crate::types::Curve;
@@ -89,7 +89,8 @@ pub fn encrypt<R>(recipient: &Key<key::PublicParts, R>,
#[allow(non_snake_case)]
pub fn decrypt<R>(recipient: &Key<key::PublicParts, R>,
recipient_sec: &SecretKeyMaterial,
- ciphertext: &Ciphertext)
+ ciphertext: &Ciphertext,
+ plaintext_len: Option<usize>)
-> Result<SessionKey>
where R: key::KeyRole
{
@@ -144,5 +145,6 @@ pub fn decrypt<R>(recipient: &Key<key::PublicParts, R>,
},
};
- decrypt_unwrap(recipient, &S, ciphertext)
+ decrypt_unwrap2(recipient.role_as_unspecified(), &S, ciphertext,
+ plaintext_len)
}
diff --git a/openpgp/src/crypto/ecdh.rs b/openpgp/src/crypto/ecdh.rs
index 2092ad07..3f47e0a6 100644
--- a/openpgp/src/crypto/ecdh.rs
+++ b/openpgp/src/crypto/ecdh.rs
@@ -116,11 +116,12 @@ pub(crate) fn encrypt_wrap<R>(recipient: &Key<key::PublicParts, R>,
/// `recipient` is the message receiver's public key, `S` is the
/// shared Diffie-Hellman secret used to encrypt `ciphertext`.
#[allow(non_snake_case)]
-pub fn decrypt_unwrap<R>(recipient: &Key<key::PublicParts, R>,
- S: &Protected,
- ciphertext: &mpi::Ciphertext)
- -> Result<SessionKey>
- where R: key::KeyRole
+pub fn decrypt_unwrap2(recipient: &Key<key::PublicParts,
+ key::UnspecifiedRole>,
+ S: &Protected,
+ ciphertext: &mpi::Ciphertext,
+ plaintext_len: Option<usize>)
+ -> Result<SessionKey>
{
match (recipient.mpis(), ciphertext) {
(mpi::PublicKey::ECDH { ref curve, ref hash, ref sym, ..},
@@ -135,8 +136,14 @@ pub fn decrypt_unwrap<R>(recipient: &Key<key::PublicParts, R>,
// Compute m = AESKeyUnwrap( Z, C ) as per [RFC3394]
let m = aes_key_unwrap(*sym, &Z, key)?;
- let cipher = SymmetricAlgorithm::from(m[0]);
- let m = pkcs5_unpad(m, 1 + cipher.key_size()? + 2)?;
+ let plaintext_len =
+ plaintext_len.ok_or_else(|| Error::InvalidOperation(
+ "Need the plaintext length to decrypt this PKESK".into()))
+ .or_else(|_| -> Result<usize> {
+ let cipher = SymmetricAlgorithm::from(m[0]);
+ Ok(1 + cipher.key_size()? + 2)
+ })?;
+ let m = pkcs5_unpad(m, plaintext_len)?;
Ok(m.into())
},
@@ -147,6 +154,18 @@ pub fn decrypt_unwrap<R>(recipient: &Key<key::PublicParts, R>,
}
}
+/// Unwraps a session key.
+#[allow(non_snake_case)]
+#[deprecated(note = "Use decrypt_unwrap2")]
+pub fn decrypt_unwrap<R>(recipient: &Key<key::PublicParts, R>,
+ S: &Protected,
+ ciphertext: &mpi::Ciphertext)
+ -> Result<SessionKey>
+ where R: key::KeyRole
+{
+ decrypt_unwrap2(recipient.role_as_unspecified(), S, ciphertext, None)
+}
+
/// Derives a secret key for session key wrapping.
///
/// See [Section 7 of RFC 6637].
diff --git a/openpgp/src/packet/key.rs b/openpgp/src/packet/key.rs
index c8c9621e..d0e62a5a 100644
--- a/openpgp/src/packet/key.rs
+++ b/openpgp/src/packet/key.rs
@@ -2269,7 +2269,7 @@ mod tests {
let key = key.parts_into_public();
let got_dek = match key.optional_secret() {
Some(SecretKeyMaterial::Unencrypted(ref u)) => u.map(|mpis| {
- ecdh::decrypt(&key, mpis, &ciphertext)
+ ecdh::decrypt(&key, mpis, &ciphertext, None)
.unwrap()
}),
_ => unreachable!(),