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§

source

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.");
        }
    }
}

Object Safety§

This trait is not object safe.

Implementors§