Trait sequoia_openpgp::parse::stream::DecryptionHelper
source · pub trait DecryptionHelper {
// Required method
fn decrypt<D>(
&mut self,
pkesks: &[PKESK],
skesks: &[SKESK],
sym_algo: Option<SymmetricAlgorithm>,
decrypt: D,
) -> Result<Option<Fingerprint>>
where D: FnMut(SymmetricAlgorithm, &SessionKey) -> bool;
}
Expand description
Helper for decrypting messages.
This trait abstracts over session key decryption. It allows us to
provide the Decryptor
without imposing any policy on how the
session key is decrypted.
Required Methods§
sourcefn decrypt<D>(
&mut self,
pkesks: &[PKESK],
skesks: &[SKESK],
sym_algo: Option<SymmetricAlgorithm>,
decrypt: D,
) -> Result<Option<Fingerprint>>
fn decrypt<D>( &mut self, pkesks: &[PKESK], skesks: &[SKESK], sym_algo: Option<SymmetricAlgorithm>, decrypt: D, ) -> Result<Option<Fingerprint>>
Decrypts the message.
This function is called with every PKESK
and SKESK
packet found in the message. The implementation must decrypt
the symmetric algorithm and session key from one of the
PKESK
packets, the SKESK
packets, or retrieve it from
a cache, and then call decrypt
with the symmetric algorithm
and session key. decrypt
returns true
if the decryption
was successful.
If a symmetric algorithm is given, it should be passed on to
PKESK::decrypt
.
If the message is decrypted using a PKESK
packet, then the
fingerprint of the certificate containing the encryption
subkey should be returned. This is used in conjunction with
the intended recipient subpacket (see Section 5.2.3.29 of RFC
4880bis) to prevent Surreptitious Forwarding.
This method will be called once per encryption layer.
§Examples
This example demonstrates how to decrypt a message using local keys (i.e. excluding remote keys like smart cards) while maximizing convenience for the user.
use sequoia_openpgp as openpgp;
use openpgp::{Fingerprint, Cert, Result};
use openpgp::crypto::SessionKey;
use openpgp::types::SymmetricAlgorithm;
use openpgp::packet::{PKESK, SKESK};
use openpgp::parse::stream::*;
struct Helper { /* ... */ };
impl DecryptionHelper for Helper {
fn decrypt<D>(&mut self, pkesks: &[PKESK], skesks: &[SKESK],
sym_algo: Option<SymmetricAlgorithm>,
mut decrypt: D) -> Result<Option<Fingerprint>>
where D: FnMut(SymmetricAlgorithm, &SessionKey) -> bool
{
// Try to decrypt, from the most convenient method to the
// least convenient one.
// First, see if it is in the cache.
if let Some((fp, algo, sk)) = lookup_cache(pkesks, skesks) {
if decrypt(algo, &sk) {
return Ok(fp);
}
}
// Second, we try those keys that we can use without
// prompting for a password.
for pkesk in pkesks {
if let Some((fp, key)) = lookup_key(pkesk.recipient()) {
if ! key.secret().is_encrypted() {
let mut keypair = key.clone().into_keypair()?;
if pkesk.decrypt(&mut keypair, sym_algo)
.map(|(algo, sk)| decrypt(algo, &sk))
.unwrap_or(false)
{
return Ok(Some(fp));
}
}
}
}
// Third, we try to decrypt PKESK packets with
// wildcard recipients using those keys that we can
// use without prompting for a password.
for pkesk in pkesks.iter().filter(|p| p.recipient().is_wildcard()) {
for (fp, key) in all_keys() {
if ! key.secret().is_encrypted() {
let mut keypair = key.clone().into_keypair()?;
if pkesk.decrypt(&mut keypair, sym_algo)
.map(|(algo, sk)| decrypt(algo, &sk))
.unwrap_or(false)
{
return Ok(Some(fp));
}
}
}
}
// Fourth, we try to decrypt all PKESK packets that we
// need encrypted keys for.
// [...]
// Fifth, we try to decrypt all PKESK packets with
// wildcard recipients using encrypted keys.
// [...]
// At this point, we have exhausted our options at
// decrypting the PKESK packets.
if skesks.is_empty() {
return
Err(anyhow::anyhow!("No key to decrypt message"));
}
// Finally, try to decrypt using the SKESKs.
loop {
let password = // Prompt for a password.
for skesk in skesks {
if skesk.decrypt(&password)
.map(|(algo, sk)| decrypt(algo, &sk))
.unwrap_or(false)
{
return Ok(None);
}
}
eprintln!("Bad password.");
}
}
}