diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2018-10-16 13:35:52 +0200 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2018-10-16 16:24:39 +0200 |
commit | 09664cf092f19648c8d2a14ff1b76d418ed0a42f (patch) | |
tree | 10e033490a44326f1b3eed6168ab0e92f16500dd /openpgp | |
parent | 28adb38e2b31dcb0f7dfc0101b14f058da2dff4b (diff) |
openpgp: Improve examples.
- Fixes #112.
Diffstat (limited to 'openpgp')
-rw-r--r-- | openpgp/examples/decrypt-with.rs | 189 | ||||
-rw-r--r-- | openpgp/examples/encrypt-for.rs | 10 | ||||
-rw-r--r-- | openpgp/examples/notarize.rs | 7 | ||||
-rw-r--r-- | openpgp/examples/sign-detached.rs | 4 | ||||
-rw-r--r-- | openpgp/examples/sign.rs | 6 | ||||
-rw-r--r-- | openpgp/examples/statistics.rs | 3 | ||||
-rw-r--r-- | openpgp/examples/wrap-literal.rs | 8 |
7 files changed, 110 insertions, 117 deletions
diff --git a/openpgp/examples/decrypt-with.rs b/openpgp/examples/decrypt-with.rs index aa528c75..5c3f1a28 100644 --- a/openpgp/examples/decrypt-with.rs +++ b/openpgp/examples/decrypt-with.rs @@ -1,18 +1,16 @@ -/// This program demonstrates how to decrypt a stream of data. +/// Decrypts asymmetrically-encrypted OpenPGP messages using the +/// openpgp crate, Sequoia's low-level API. +use std::collections::HashMap; use std::env; use std::io; -use std::collections::HashMap; +extern crate failure; extern crate openpgp; -use openpgp::{ - Packet, - KeyID, - packet::Key, - TPK, - SecretKey, + +use openpgp::parse::stream::{ + Decryptor, DecryptionHelper, Secret, VerificationHelper, VerificationResult, }; -use openpgp::parse::PacketParserResult; pub fn main() { let args: Vec<String> = env::args().collect(); @@ -22,106 +20,95 @@ pub fn main() { } // Read the transferable secret keys from the given files. - let mut keys: HashMap<KeyID, Key> = HashMap::new(); - for f in args[1..].iter() { - let tsk = TPK::from_reader( - // Use an openpgp::Reader so that we accept both armored - // and plain PGP data. - openpgp::Reader::from_file(f) - .expect("Failed to open file")) - .expect("Failed to read key"); - for (sig, key) in tsk.keys() { - if ! sig.map(|s| s.key_flags().can_encrypt_at_rest() - || s.key_flags().can_encrypt_for_transport()) - .unwrap_or(false) - { - continue; - } + let tpks = + args[1..].iter().map(|f| { + openpgp::TPK::from_reader( + // Use an openpgp::Reader so that we accept both armored + // and plain PGP data. + openpgp::Reader::from_file(f) + .expect("Failed to open file")) + .expect("Failed to read key") + }).collect(); - keys.insert(key.fingerprint().to_keyid(), key.clone()); - } - } - - #[derive(PartialEq)] - enum State { - Start(Vec<openpgp::packet::PKESK>, Vec<openpgp::packet::SKESK>), - Deciphered, - Done, - } - let mut state = State::Start(vec![], vec![]); - let mut input = io::stdin(); - let mut ppr - = openpgp::parse::PacketParser::from_reader( - openpgp::Reader::from_reader(&mut input) - .expect("Failed to build reader")) - .expect("Failed to build parser"); + // First, use an openpgp::Reader so that we accept both armored + // and plain PGP data. + let reader = openpgp::Reader::from_reader(io::stdin()) + .expect("Failed to open file"); - while let PacketParserResult::Some(mut pp) = ppr { - state = match state { - // Look for an PKESK or SKESK packet. - State::Start(mut pkesks, mut skesks) => - match pp.packet { - Packet::SEIP(_) => { - let mut state = None; - for pkesk in pkesks.iter() { - if let Some(tsk) = keys.get(&pkesk.recipient()) { - if let Some(SecretKey::Unencrypted{ref mpis}) = - tsk.secret() - { - if let Ok((algo, key)) = pkesk.decrypt(tsk, mpis) { - let r = pp.decrypt(algo, &key); - if r.is_ok() { - state = Some(State::Deciphered); - break; - } - } - } - } - } - state.unwrap_or(State::Start(pkesks, skesks)) - }, - _ => State::Start(pkesks, skesks), - }, + // Now, create a decryptor with a helper using the given TPKs. + let mut decryptor = + Decryptor::from_reader(reader, Helper::new(tpks)).unwrap(); - // Look for the literal data packet. - State::Deciphered => - if let Packet::Literal(_) = pp.packet { - io::copy(&mut pp, &mut io::stdout()) - .expect("Failed to copy data"); - State::Done - } else { - State::Deciphered - }, + // Finally, stream the decrypted data to stdout. + io::copy(&mut decryptor, &mut io::stdout()) + .expect("Decryption failed"); +} - // We continue to parse, useful for dumping - // encrypted packets. - State::Done => State::Done, - }; +/// This helper provides secrets for the decryption, fetches public +/// keys for the signature verification and implements the +/// verification policy. +struct Helper { + keys: HashMap<openpgp::KeyID, Secret>, + i: usize, +} - let (packet, ppr_tmp) = pp.recurse().expect("Failed to recurse"); - ppr = ppr_tmp; +impl Helper { + /// Creates a Helper for the given TPKs with appropriate secrets. + fn new(tpks: Vec<openpgp::TPK>) -> Self { + // Map (sub)KeyIDs to secrets. + let mut keys = HashMap::new(); + for tpk in tpks { + for (sig, key) in tpk.keys() { + if sig.map(|s| (s.key_flags().can_encrypt_at_rest() + || s.key_flags().can_encrypt_for_transport())) + .unwrap_or(false) + { + // Only handle unencrypted secret keys. + if let Some(openpgp::SecretKey::Unencrypted { ref mpis }) = + key.secret() + { + keys.insert(key.fingerprint().to_keyid(), + Secret::Asymmetric { + identity: tpk.fingerprint(), + key: key.clone(), + secret: mpis.clone(), + }); + } + } + } + } - state = match state { - // Look for an PKESK or SKESK packet. - State::Start(mut pkesks, mut skesks) => - match packet { - Packet::PKESK(pkesk) => { - pkesks.push(pkesk); - State::Start(pkesks, skesks) - }, - Packet::SKESK(skesk) => { - skesks.push(skesk); - State::Start(pkesks, skesks) - }, - _ => State::Start(pkesks, skesks), - }, + Helper { + keys: keys, + i: 0, + } + } +} - // Do nothing in all other states. - s => s, - }; +impl DecryptionHelper for Helper { + fn get_secret(&mut self, + pkesks: &[&openpgp::packet::PKESK], + _: &[&openpgp::packet::SKESK]) + -> failure::Fallible<Option<Secret>> { + let r = pkesks + .iter() + .nth(self.i) + .and_then(|pkesk| { + self.keys.get(pkesk.recipient()) + .map(|s| (*s).clone()) + }); + self.i += 1; + Ok(r) } +} - if state != State::Done { - panic!("decryption failed"); +impl VerificationHelper for Helper { + fn get_public_keys(&mut self, _ids: &[openpgp::KeyID]) + -> failure::Fallible<Vec<openpgp::TPK>> { + Ok(Vec::new()) // Feed the TPKs to the verifier here. + } + fn check(&mut self, _sigs: Vec<Vec<VerificationResult>>) + -> failure::Fallible<()> { + Ok(()) // Implement your verification policy here. } } diff --git a/openpgp/examples/encrypt-for.rs b/openpgp/examples/encrypt-for.rs index de4cad9b..a5d7150a 100644 --- a/openpgp/examples/encrypt-for.rs +++ b/openpgp/examples/encrypt-for.rs @@ -1,4 +1,5 @@ -/// This program demonstrates how to encrypt a stream of data. +/// Asymmetrically encrypts OpenPGP messages using the openpgp crate, +/// Sequoia's low-level API. use std::env; use std::io; @@ -14,7 +15,8 @@ fn main() { let args: Vec<String> = env::args().collect(); if args.len() < 3 { panic!("A simple encryption filter.\n\n\ - Usage: {} [at-rest|for-transport] <keyfile> [<keyfile>...] <input >output\n", args[0]); + Usage: {} [at-rest|for-transport] <keyfile> [<keyfile>...] \ + <input >output\n", args[0]); } let mode = match args[1].as_ref() { @@ -53,9 +55,11 @@ fn main() { None, None) .expect("Failed to create literal writer"); - // Finally, copy stdin to our writer stack to encrypt the data. + // Copy stdin to our writer stack to encrypt the data. io::copy(&mut io::stdin(), &mut literal_writer) .expect("Failed to encrypt"); + // Finally, finalize the OpenPGP message by tearing down the + // writer stack. literal_writer.finalize().unwrap(); } diff --git a/openpgp/examples/notarize.rs b/openpgp/examples/notarize.rs index a21ee69a..c26e79af 100644 --- a/openpgp/examples/notarize.rs +++ b/openpgp/examples/notarize.rs @@ -1,4 +1,5 @@ -/// This program demonstrates how to notarize an OpenPGP message. +/// Notarizes OpenPGP messages using the openpgp crate, Sequoia's +/// low-level API. use std::env; use std::io; @@ -67,7 +68,7 @@ fn main() { LiteralWriter::new(signer, DataFormat::Binary, None, None) .expect("Failed to create literal writer"); - // Finally, just copy all the data. + // Copy all the data. io::copy(&mut pp, &mut literal) .expect("Failed to sign data"); @@ -90,7 +91,7 @@ fn main() { unreachable!() } - // Teardown the stack to ensure all the data is written. + // Finally, teardown the stack to ensure all the data is written. signer.finalize() .expect("Failed to write data"); } diff --git a/openpgp/examples/sign-detached.rs b/openpgp/examples/sign-detached.rs index 64a1002f..fca195b0 100644 --- a/openpgp/examples/sign-detached.rs +++ b/openpgp/examples/sign-detached.rs @@ -36,11 +36,11 @@ fn main() { wrap(sink), &tsks.iter().collect::<Vec<&openpgp::TPK>>()) .expect("Failed to create signer"); - // Finally, just copy all the data. + // Copy all the data. io::copy(&mut io::stdin(), &mut signer) .expect("Failed to sign data"); - // Teardown the stack to ensure all the data is written. + // Finally, teardown the stack to ensure all the data is written. signer.finalize() .expect("Failed to write data"); } diff --git a/openpgp/examples/sign.rs b/openpgp/examples/sign.rs index 8a5ad0cc..03117ed5 100644 --- a/openpgp/examples/sign.rs +++ b/openpgp/examples/sign.rs @@ -1,4 +1,4 @@ -/// This program demonstrates how to sign data. +/// Signs data using the openpgp crate, Sequoia's low-level API. use std::env; use std::io; @@ -42,11 +42,11 @@ fn main() { let mut literal = LiteralWriter::new(signer, DataFormat::Binary, None, None) .expect("Failed to create literal writer"); - // Finally, just copy all the data. + // Copy all the data. io::copy(&mut io::stdin(), &mut literal) .expect("Failed to sign data"); - // Teardown the stack to ensure all the data is written. + // Finally, teardown the stack to ensure all the data is written. literal.finalize() .expect("Failed to write data"); } diff --git a/openpgp/examples/statistics.rs b/openpgp/examples/statistics.rs index 1e52bd6d..df1611de 100644 --- a/openpgp/examples/statistics.rs +++ b/openpgp/examples/statistics.rs @@ -1,4 +1,5 @@ -/// This program collects statistics about e.g. the SKS packet dump. +/// Collects statistics about the SKS packet dump using the openpgp +/// crate, Sequoia's low-level API. /// /// Note that to achieve reasonable performance, you need to compile /// Sequoia and this program with optimizations: diff --git a/openpgp/examples/wrap-literal.rs b/openpgp/examples/wrap-literal.rs index 5d57d118..b7cea74e 100644 --- a/openpgp/examples/wrap-literal.rs +++ b/openpgp/examples/wrap-literal.rs @@ -1,5 +1,5 @@ -/// This program demonstrates how to wrap a stream into a literal data -/// packet. +/// Wraps a stream of data into a literal data packet using the +/// openpgp crate, Sequoia's low-level API. /// /// It is also used to generate test vectors for the armor subsystem. @@ -30,11 +30,11 @@ fn main() { None, None) .expect("Failed to create literal writer"); - // Finally, just copy all the data. + // Copy all the data. io::copy(&mut io::stdin(), &mut literal) .expect("Failed to sign data"); - // Teardown the stack to ensure all the data is written. + // Finally, teardown the stack to ensure all the data is written. literal.finalize() .expect("Failed to write data"); } |