1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
|
/// Decrypts asymmetrically-encrypted OpenPGP messages using the
/// openpgp crate, Sequoia's low-level API.
use std::sync::Arc;
use std::collections::HashMap;
use std::env;
use std::io;
use anyhow::Context;
use sequoia_openpgp as openpgp;
use openpgp::*;
use openpgp::crypto::{KeyPair, SessionKey};
use openpgp::types::SymmetricAlgorithm;
use openpgp::parse::{
Parse,
stream::{
DecryptionHelper,
DecryptorBuilder,
VerificationHelper,
GoodChecksum,
MessageStructure,
MessageLayer,
},
};
use openpgp::policy::Policy;
use openpgp::policy::StandardPolicy as P;
pub fn main() -> openpgp::Result<()> {
let p = &P::new();
let args: Vec<String> = env::args().collect();
if args.len() < 2 {
return Err(anyhow::anyhow!("A simple decryption filter.\n\n\
Usage: {} <keyfile> [<keyfile>...] <input >output\n", args[0]));
}
// Read the transferable secret keys from the given files.
let certs =
args[1..].iter().map(|f| {
openpgp::Cert::from_file(f)
}).collect::<openpgp::Result<Vec<_>>>()
.context("Failed to read key")?;
// Now, create a decryptor with a helper using the given Certs.
let mut decryptor =
DecryptorBuilder::from_reader(io::stdin())?
.with_policy(p, None, Helper::new(p, certs))?;
// Finally, stream the decrypted data to stdout.
io::copy(&mut decryptor, &mut io::stdout())
.context("Decryption failed")?;
Ok(())
}
/// This helper provides secrets for the decryption, fetches public
/// keys for the signature verification and implements the
/// verification policy.
struct Helper {
keys: HashMap<KeyID, (Arc<Cert>, KeyPair)>,
}
impl Helper {
/// Creates a Helper for the given Certs with appropriate secrets.
fn new(p: &dyn Policy, certs: Vec<openpgp::Cert>) -> Self {
// Map (sub)KeyIDs to certs and secrets.
let mut keys = HashMap::new();
for cert in certs {
let cert = Arc::new(cert);
for ka in cert.keys().unencrypted_secret().with_policy(p, None)
.supported()
.for_storage_encryption().for_transport_encryption()
{
keys.insert(ka.key().keyid(),
(cert.clone(),
ka.key().clone().into_keypair().unwrap()));
}
}
Helper {
keys,
}
}
}
impl DecryptionHelper for Helper {
fn decrypt(&mut self,
pkesks: &[openpgp::packet::PKESK],
_skesks: &[openpgp::packet::SKESK],
sym_algo: Option<SymmetricAlgorithm>,
decrypt: &mut dyn FnMut(Option<SymmetricAlgorithm>, &SessionKey) -> bool)
-> openpgp::Result<Option<Cert>>
{
// Try each PKESK until we succeed.
let mut recipient = None;
for pkesk in pkesks {
if let Some((cert, pair)) = self.keys.get_mut(&KeyID::from(pkesk.recipient())) {
if pkesk.decrypt(pair, sym_algo)
.map(|(algo, session_key)| decrypt(algo, &session_key))
.unwrap_or(false)
{
recipient = Some(cert.as_ref().clone());
break;
}
}
}
Ok(recipient)
}
}
impl VerificationHelper for Helper {
fn get_certs(&mut self, _ids: &[openpgp::KeyHandle])
-> openpgp::Result<Vec<openpgp::Cert>> {
Ok(Vec::new()) // Feed the Certs to the verifier here.
}
fn check(&mut self, structure: MessageStructure)
-> openpgp::Result<()> {
for layer in structure.iter() {
match layer {
MessageLayer::Compression { algo } =>
eprintln!("Compressed using {}", algo),
MessageLayer::Encryption { sym_algo, aead_algo } =>
if let Some(aead_algo) = aead_algo {
eprintln!("Encrypted and protected using {}/{}",
sym_algo, aead_algo);
} else {
eprintln!("Encrypted using {}", sym_algo);
},
MessageLayer::SignatureGroup { ref results } =>
for result in results {
match result {
Ok(GoodChecksum { ka, .. }) => {
eprintln!("Good signature from {}", ka.cert());
},
Err(e) =>
eprintln!("Error: {:?}", e),
}
}
}
}
Ok(()) // Implement your verification policy here.
}
}
|