summaryrefslogtreecommitdiffstats
path: root/openpgp
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2018-10-16 13:35:52 +0200
committerJustus Winter <justus@sequoia-pgp.org>2018-10-16 16:24:39 +0200
commit09664cf092f19648c8d2a14ff1b76d418ed0a42f (patch)
tree10e033490a44326f1b3eed6168ab0e92f16500dd /openpgp
parent28adb38e2b31dcb0f7dfc0101b14f058da2dff4b (diff)
openpgp: Improve examples.
- Fixes #112.
Diffstat (limited to 'openpgp')
-rw-r--r--openpgp/examples/decrypt-with.rs189
-rw-r--r--openpgp/examples/encrypt-for.rs10
-rw-r--r--openpgp/examples/notarize.rs7
-rw-r--r--openpgp/examples/sign-detached.rs4
-rw-r--r--openpgp/examples/sign.rs6
-rw-r--r--openpgp/examples/statistics.rs3
-rw-r--r--openpgp/examples/wrap-literal.rs8
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");
}