use std::sync::Arc;
use std::collections::HashMap;
use std::env;
use std::io;
use anyhow::Context;
use sequoia_openpgp as openpgp;
use openpgp::{Cert, KeyID};
use openpgp::packet::prelude::*;
use openpgp::crypto::{KeyPair, SessionKey};
use openpgp::types::SymmetricAlgorithm;
use openpgp::parse::{Parse, stream::*};
use openpgp::serialize::{Serialize, stream::*};
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() < 3 {
return Err(anyhow::anyhow!("Reply-to-all without having all certs.\n\n\
Usage: {} <encrypted-msg> <keyfile> [<keyfile>...] \
<plaintext >ciphertext\n", args[0]));
}
let encrypted_message = &args[1];
let certs =
args[2..].iter().map(|f| {
openpgp::Cert::from_file(f)
}).collect::<openpgp::Result<Vec<_>>>()
.context("Failed to read key")?;
let mut decryptor =
DecryptorBuilder::from_file(encrypted_message)?
.with_policy(p, None, Helper::new(p, certs))?;
eprintln!("- Original message:");
io::copy(&mut decryptor, &mut io::stderr())
.context("Decryption failed")?;
let (algo, sk, pkesks) = decryptor.into_helper().recycling_bin.unwrap();
eprintln!("- Reusing ({:?}, {}) with {} PKESK packets",
algo, openpgp::fmt::hex::encode(&sk), pkesks.len());
let mut sink = io::stdout();
let message = Message::new(&mut sink);
let mut message = Armorer::new(message).build()?;
for p in pkesks {
openpgp::Packet::from(p).serialize(&mut message)?;
}
let message = Encryptor::with_session_key(message, algo.expect("XXX seipdv2"), sk)?
.build().context("Failed to create encryptor")?;
let mut message = LiteralWriter::new(message).build()
.context("Failed to create literal writer")?;
io::copy(&mut io::stdin(), &mut message)
.context("Failed to encrypt")?;
message.finalize()?;
Ok(())
}
struct Helper {
keys: HashMap<KeyID, (Arc<Cert>, KeyPair)>,
recycling_bin: Option<(Option<SymmetricAlgorithm>, SessionKey, Vec<PKESK>)>,
}
impl Helper {
fn new(p: &dyn Policy, certs: Vec<openpgp::Cert>) -> Self {
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,
recycling_bin: None,
}
}
}
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>>
{
let mut recipient = None;
let mut encryption_context = 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)| {
let success = decrypt(algo, &session_key);
if success {
encryption_context =
Some((
algo,
session_key.clone(),
pkesks.iter().cloned().collect(),
));
}
success
})
.unwrap_or(false)
{
recipient = Some(cert.as_ref().clone());
break;
}
}
}
self.recycling_bin = encryption_context;
Ok(recipient)
}
}
impl VerificationHelper for Helper {
fn get_certs(&mut self, _ids: &[openpgp::KeyHandle])
-> openpgp::Result<Vec<openpgp::Cert>> {
Ok(Vec::new()) }
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(()) }
}