diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2019-09-06 13:47:50 +0200 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2019-09-06 16:42:12 +0200 |
commit | 38a4d2b4ff4fc4512b31a4ff4e4ddd8a6b3c7503 (patch) | |
tree | 469d667b6bab8333df02c7a2402b9edabbe08419 | |
parent | 4d642187f1df0c9a4c60dc2355c797ebac6fcd4f (diff) |
openpgp: Rework streaming encryptor.
- Instead of giving a set of TPKs to the encryptor, hand in a set of
recipients, which are (keyid, key)-tuples, conveniently created
from key queries over TPKs. This simplifies the encryptor, and
makes the key selection explicit.
- Drop the EncryptionMode type.
- As a nice side effect, we can now generate encrypted messages with
wildcard recipient addresses.
-rw-r--r-- | ffi/lang/python/sequoia/sequoia_build.py | 1 | ||||
-rw-r--r-- | guide/src/chapter_02.md | 48 | ||||
-rw-r--r-- | ipc/tests/gpg-agent.rs | 10 | ||||
-rw-r--r-- | openpgp-ffi/examples/encrypt-for.c | 13 | ||||
-rw-r--r-- | openpgp-ffi/include/sequoia/openpgp.h | 4 | ||||
-rw-r--r-- | openpgp-ffi/include/sequoia/openpgp/serialize.h | 40 | ||||
-rw-r--r-- | openpgp-ffi/include/sequoia/openpgp/types.h | 24 | ||||
-rw-r--r-- | openpgp-ffi/src/serialize.rs | 104 | ||||
-rw-r--r-- | openpgp-ffi/src/tpk.rs | 1 | ||||
-rw-r--r-- | openpgp/examples/encrypt-for.rs | 17 | ||||
-rw-r--r-- | openpgp/examples/generate-encrypt-decrypt.rs | 13 | ||||
-rw-r--r-- | openpgp/examples/pad.rs | 18 | ||||
-rw-r--r-- | openpgp/src/autocrypt.rs | 3 | ||||
-rw-r--r-- | openpgp/src/serialize/stream.rs | 156 | ||||
-rw-r--r-- | tool/src/commands/mod.rs | 23 | ||||
-rw-r--r-- | tool/src/sq-usage.rs | 4 | ||||
-rw-r--r-- | tool/src/sq.rs | 12 | ||||
-rw-r--r-- | tool/src/sq_cli.rs | 10 |
18 files changed, 335 insertions, 166 deletions
diff --git a/ffi/lang/python/sequoia/sequoia_build.py b/ffi/lang/python/sequoia/sequoia_build.py index 5243e489..a3ce2786 100644 --- a/ffi/lang/python/sequoia/sequoia_build.py +++ b/ffi/lang/python/sequoia/sequoia_build.py @@ -11,6 +11,7 @@ defs = "".join(l open(join(pgp_inc, "openpgp/types.h")).readlines(), open(join(pgp_inc, "openpgp/crypto.h")).readlines(), open(join(pgp_inc, "openpgp/packet.h")).readlines(), + open(join(pgp_inc, "openpgp/serialize.h")).readlines(), open(join(pgp_inc, "openpgp.h")).readlines(), open(join(sq_inc, "core.h")).readlines(), open(join(sq_inc, "net.h")).readlines(), diff --git a/guide/src/chapter_02.md b/guide/src/chapter_02.md index 7c564ff0..e29f412c 100644 --- a/guide/src/chapter_02.md +++ b/guide/src/chapter_02.md @@ -50,14 +50,22 @@ fn main() { # /// Encrypts the given message. # fn encrypt(sink: &mut Write, plaintext: &str, recipient: &openpgp::TPK) # -> openpgp::Result<()> { +# // Build a vector of recipients to hand to Encryptor. +# let recipients = +# recipient.keys_valid() +# .key_flags(KeyFlags::default() +# .set_encrypt_at_rest(true) +# .set_encrypt_for_transport(true)) +# .map(|(_, _, key)| key.into()) +# .collect::<Vec<_>>(); +# # // Start streaming an OpenPGP message. # let message = Message::new(sink); # # // We want to encrypt a literal data packet. # let encryptor = Encryptor::new(message, # &[], // No symmetric encryption. -# &[recipient], -# EncryptionMode::ForTransport, +# &recipients, # None, None)?; # # // Emit a literal data packet. @@ -186,14 +194,22 @@ fn generate() -> openpgp::Result<openpgp::TPK> { # /// Encrypts the given message. # fn encrypt(sink: &mut Write, plaintext: &str, recipient: &openpgp::TPK) # -> openpgp::Result<()> { +# // Build a vector of recipients to hand to Encryptor. +# let recipients = +# recipient.keys_valid() +# .key_flags(KeyFlags::default() +# .set_encrypt_at_rest(true) +# .set_encrypt_for_transport(true)) +# .map(|(_, _, key)| key.into()) +# .collect::<Vec<_>>(); +# # // Start streaming an OpenPGP message. # let message = Message::new(sink); # # // We want to encrypt a literal data packet. # let encryptor = Encryptor::new(message, # &[], // No symmetric encryption. -# &[recipient], -# EncryptionMode::ForTransport, +# &recipients, # None, None)?; # # // Emit a literal data packet. @@ -322,14 +338,22 @@ implements [`io::Write`], and we simply write the plaintext to it. /// Encrypts the given message. fn encrypt(sink: &mut Write, plaintext: &str, recipient: &openpgp::TPK) -> openpgp::Result<()> { + // Build a vector of recipients to hand to Encryptor. + let recipients = + recipient.keys_valid() + .key_flags(KeyFlags::default() + .set_encrypt_at_rest(true) + .set_encrypt_for_transport(true)) + .map(|(_, _, key)| key.into()) + .collect::<Vec<_>>(); + // Start streaming an OpenPGP message. let message = Message::new(sink); // We want to encrypt a literal data packet. let encryptor = Encryptor::new(message, &[], // No symmetric encryption. - &[recipient], - EncryptionMode::ForTransport, + &recipients, None, None)?; // Emit a literal data packet. @@ -472,14 +496,22 @@ Decrypted data can be read from this using [`io::Read`]. # /// Encrypts the given message. # fn encrypt(sink: &mut Write, plaintext: &str, recipient: &openpgp::TPK) # -> openpgp::Result<()> { +# // Build a vector of recipients to hand to Encryptor. +# let recipients = +# recipient.keys_valid() +# .key_flags(KeyFlags::default() +# .set_encrypt_at_rest(true) +# .set_encrypt_for_transport(true)) +# .map(|(_, _, key)| key.into()) +# .collect::<Vec<_>>(); +# # // Start streaming an OpenPGP message. # let message = Message::new(sink); # # // We want to encrypt a literal data packet. # let encryptor = Encryptor::new(message, # &[], // No symmetric encryption. -# &[recipient], -# EncryptionMode::ForTransport, +# &recipients, # None, None)?; # # // Emit a literal data packet. diff --git a/ipc/tests/gpg-agent.rs b/ipc/tests/gpg-agent.rs index ea07a4e1..707f2bb6 100644 --- a/ipc/tests/gpg-agent.rs +++ b/ipc/tests/gpg-agent.rs @@ -200,14 +200,20 @@ fn decrypt() { let mut message = Vec::new(); { + // Build a vector of recipients to hand to Encryptor. + let recipients = + tpk.keys_valid().key_flags( + KeyFlags::default().set_encrypt_for_transport(true)) + .map(|(_, _, key)| key.into()) + .collect::<Vec<Recipient>>(); + // Start streaming an OpenPGP message. let message = Message::new(&mut message); // We want to encrypt a literal data packet. let encryptor = Encryptor::new(message, &[], // No symmetric encryption. - &[&tpk], - EncryptionMode::ForTransport, + recipients, None, None).unwrap(); // Emit a literal data packet. diff --git a/openpgp-ffi/examples/encrypt-for.c b/openpgp-ffi/examples/encrypt-for.c index 31b643e3..49bf025e 100644 --- a/openpgp-ffi/examples/encrypt-for.c +++ b/openpgp-ffi/examples/encrypt-for.c @@ -36,6 +36,13 @@ main (int argc, char **argv) if (tpk == NULL) error (1, 0, "pgp_tpk_from_file: %s", pgp_error_to_string (err)); + pgp_tpk_key_iter_t iter = pgp_tpk_key_iter_valid (tpk); + pgp_tpk_key_iter_encrypting_capable_at_rest (iter); + pgp_tpk_key_iter_encrypting_capable_for_transport (iter); + size_t recipients_len; + pgp_recipient_t *recipients = + pgp_recipients_from_key_iter (iter, &recipients_len); + sink = pgp_writer_from_fd (STDOUT_FILENO); if (use_armor) @@ -46,8 +53,7 @@ main (int argc, char **argv) writer = pgp_encryptor_new (&err, writer, NULL, 0, /* no passwords */ - &tpk, 1, - PGP_ENCRYPTION_MODE_FOR_TRANSPORT, + recipients, recipients_len, 9 /* AES256 */, 0 /* No AEAD */); if (writer == NULL) @@ -79,6 +85,9 @@ main (int argc, char **argv) if (rc) error (1, 0, "pgp_writer_stack_write: %s", pgp_error_to_string (err)); + for (size_t i = 0; i < recipients_len; i++) + pgp_recipient_free (recipients[i]); + free (recipients); pgp_tpk_free (tpk); return 0; } diff --git a/openpgp-ffi/include/sequoia/openpgp.h b/openpgp-ffi/include/sequoia/openpgp.h index a440abd1..8662fef1 100644 --- a/openpgp-ffi/include/sequoia/openpgp.h +++ b/openpgp-ffi/include/sequoia/openpgp.h @@ -12,6 +12,7 @@ #include <sequoia/openpgp/error.h> #include <sequoia/openpgp/crypto.h> #include <sequoia/openpgp/packet.h> +#include <sequoia/openpgp/serialize.h> /* sequoia::openpgp::KeyID. */ @@ -1622,9 +1623,8 @@ pgp_writer_stack_t pgp_encryptor_new (pgp_error_t *errp, pgp_writer_stack_t inner, char **passwords, size_t passwords_len, - pgp_tpk_t *recipients, + pgp_recipient_t *recipients, size_t recipients_len, - pgp_encryption_mode_t mode, uint8_t cipher_algo, uint8_t aead_algo); diff --git a/openpgp-ffi/include/sequoia/openpgp/serialize.h b/openpgp-ffi/include/sequoia/openpgp/serialize.h new file mode 100644 index 00000000..7d41d9b0 --- /dev/null +++ b/openpgp-ffi/include/sequoia/openpgp/serialize.h @@ -0,0 +1,40 @@ +#ifndef SEQUOIA_OPENPGP_SERIALIZE_H +#define SEQUOIA_OPENPGP_SERIALIZE_H + +/*/ +/// Creates a new recipient with an explicit recipient keyid. +/// +/// Consumes `keyid`, references `key`. +/*/ +pgp_recipient_t pgp_recipient_new (pgp_keyid_t keyid, pgp_key_t key); + +/*/ +/// Frees this object. +/*/ +void pgp_recipient_free (pgp_recipient_t); + +/*/ +/// Returns a human readable description of this object suitable for +/// debugging. +/*/ +char *pgp_recipient_debug (const pgp_recipient_t); + +/*/ +/// Gets the KeyID. +/*/ +pgp_keyid_t pgp_recipient_keyid (const pgp_recipient_t); + +/*/ +/// Sets the KeyID. +/*/ +void pgp_recipient_set_keyid (pgp_recipient_t, pgp_keyid_t); + +/*/ +/// Collects recipients from a `pgp_tpk_key_iter_t`. +/// +/// Consumes the iterator. The returned buffer must be freed using +/// libc's allocator. +/*/ +pgp_recipient_t *pgp_recipients_from_key_iter (pgp_tpk_key_iter_t, size_t *); + +#endif diff --git a/openpgp-ffi/include/sequoia/openpgp/types.h b/openpgp-ffi/include/sequoia/openpgp/types.h index b6003b1d..d1612a73 100644 --- a/openpgp-ffi/include/sequoia/openpgp/types.h +++ b/openpgp-ffi/include/sequoia/openpgp/types.h @@ -445,29 +445,9 @@ typedef struct pgp_tpk_builder *pgp_tpk_builder_t; typedef struct pgp_writer_stack *pgp_writer_stack_t; /*/ -/// Specifies whether to encrypt for archival purposes or for -/// transport. +/// A recipient of an encrypted message. /*/ -typedef enum pgp_encryption_mode { - /*/ - /// Encrypt data for long-term storage. - /// - /// This should be used for things that should be decryptable for - /// a long period of time, e.g. backups, archives, etc. - /*/ - PGP_ENCRYPTION_MODE_AT_REST = 0, - - /*/ - /// Encrypt data for transport. - /// - /// This should be used to protect a message in transit. The - /// recipient is expected to take additional steps if she wants to - /// be able to decrypt it later on, e.g. store the decrypted - /// session key, or re-encrypt the session key with a different - /// key. - /*/ - PGP_ENCRYPTION_MODE_FOR_TRANSPORT = 1, -} pgp_encryption_mode_t; +typedef struct pgp_recipient *pgp_recipient_t; /// Communicates the message structure to the VerificationHelper. typedef struct pgp_message_structure *pgp_message_structure_t; diff --git a/openpgp-ffi/src/serialize.rs b/openpgp-ffi/src/serialize.rs index 33fa9181..4322241b 100644 --- a/openpgp-ffi/src/serialize.rs +++ b/openpgp-ffi/src/serialize.rs @@ -25,7 +25,9 @@ use self::openpgp::constants::{ use crate::error::Status; use crate::MoveFromRaw; +use crate::MoveIntoRaw; use crate::RefRaw; +use crate::RefMutRaw; use self::openpgp::serialize::{ writer, @@ -35,12 +37,13 @@ use self::openpgp::serialize::{ ArbitraryWriter, Signer, LiteralWriter, - EncryptionMode, Encryptor, }, }; -use super::tpk::TPK; +use super::keyid::KeyID; +use super::packet::key::Key; +use super::tpk::KeyIterWrapper; /// Streams an OpenPGP message. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] @@ -228,6 +231,74 @@ pub extern "C" fn pgp_literal_writer_new None)) } +/// A recipient of an encrypted message. +/// +/// Wraps [`sequoia-openpgp::serialize::stream::Recipient`]. +/// +/// [`sequoia-openpgp::serialize::stream::Recipient`]: ../../sequoia_openpgp/serialize/stream/struct.Recipient.html +#[crate::ffi_wrapper_type(prefix = "pgp_", derive = "Debug")] +pub struct Recipient<'a>(openpgp::serialize::stream::Recipient<'a>); + +/// Creates a new recipient with an explicit recipient keyid. +/// +/// Consumes `keyid`, references `key`. +#[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" +fn pgp_recipient_new<'a>(keyid: *mut KeyID, + key: *const Key) + -> *mut Recipient<'a> +{ + openpgp::serialize::stream::Recipient::new( + keyid.move_from_raw(), + key.ref_raw().mark_parts_public_ref(), + ).move_into_raw() +} + +/// Gets the KeyID. +#[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" +fn pgp_recipient_keyid(recipient: *const Recipient) -> *mut KeyID { + recipient.ref_raw().keyid().clone().move_into_raw() +} + +/// Sets the KeyID. +/// +/// Consumes `keyid`. +#[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" +fn pgp_recipient_set_keyid(recipient: *mut Recipient, keyid: *mut KeyID) { + recipient.ref_mut_raw().set_keyid(keyid.move_from_raw()); +} + +/// Collects recipients from a `pgp_tpk_key_iter_t`. +/// +/// Consumes the iterator. The returned buffer must be freed using +/// libc's allocator. +#[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" +fn pgp_recipients_from_key_iter<'a>( + iter_wrapper: *mut KeyIterWrapper<'a>, + result_len: *mut size_t) + -> *mut *mut Recipient<'a> +{ + let iter_wrapper = ffi_param_move!(iter_wrapper); + let result_len = ffi_param_ref_mut!(result_len); + let recipients = + iter_wrapper.iter + .map(|(_, _, key)| key.into()) + .collect::<Vec<openpgp::serialize::stream::Recipient>>(); + + let result = unsafe { + libc::calloc(recipients.len(), std::mem::size_of::<* mut Recipient>()) + as *mut *mut Recipient + }; + let r = unsafe { + slice::from_raw_parts_mut(result, + recipients.len()) + }; + *result_len = recipients.len(); + r.iter_mut().zip(recipients.into_iter()) + .for_each(|(r, recipient)| *r = recipient.move_into_raw()); + result +} + + /// Creates a new encryptor. /// /// The stream will be encrypted using a generated session key, @@ -237,15 +308,14 @@ pub extern "C" fn pgp_literal_writer_new /// The stream is encrypted using `cipher_algo`. Pass 0 for the /// default (which is what you usually want). #[::sequoia_ffi_macros::extern_fn] #[no_mangle] -pub extern "C" fn pgp_encryptor_new +pub extern "C" fn pgp_encryptor_new<'a> (errp: Option<&mut *mut crate::error::Error>, - inner: *mut writer::Stack<'static, Cookie>, + inner: *mut writer::Stack<'a, Cookie>, passwords: Option<&*const c_char>, passwords_len: size_t, - recipients: Option<&*const TPK>, recipients_len: size_t, - encryption_mode: u8, + recipients: Option<&*const Recipient<'a>>, recipients_len: size_t, cipher_algo: u8, aead_algo: u8) - -> *mut writer::Stack<'static, Cookie> + -> *mut writer::Stack<'a, Cookie> { ffi_make_fry_from_errp!(errp); let inner = ffi_param_move!(inner); @@ -260,20 +330,15 @@ pub extern "C" fn pgp_encryptor_new .to_bytes().to_owned().into()); } } - let recipients = if recipients_len > 0 { + let mut recipients_ = Vec::new(); + if recipients_len > 0 { let recipients = recipients.expect("Recipients is NULL"); - unsafe { + let recipients = unsafe { slice::from_raw_parts(recipients, recipients_len) + }; + for recipient in recipients { + recipients_.push(recipient.ref_raw()); } - } else { - &[] - }; - let recipients : Vec<&::sequoia_openpgp::TPK> - = recipients.into_iter().map(|&tpk| tpk.ref_raw()).collect(); - let encryption_mode = match encryption_mode { - 0 => EncryptionMode::AtRest, - 1 => EncryptionMode::ForTransport, - _ => panic!("Bad encryption mode: {}", encryption_mode), }; let cipher_algo : Option<SymmetricAlgorithm> = if cipher_algo == 0 { None @@ -287,8 +352,7 @@ pub extern "C" fn pgp_encryptor_new }; ffi_try_box!(Encryptor::new(*inner, &passwords_.iter().collect::<Vec<&Password>>(), - &recipients[..], - encryption_mode, + recipients_, cipher_algo, aead_algo)) } diff --git a/openpgp-ffi/src/tpk.rs b/openpgp-ffi/src/tpk.rs index 9777292b..b7c269fb 100644 --- a/openpgp-ffi/src/tpk.rs +++ b/openpgp-ffi/src/tpk.rs @@ -466,6 +466,7 @@ pub extern "C" fn pgp_user_id_binding_iter_next<'a>( /// Wraps a KeyIter for export via the FFI. pub struct KeyIterWrapper<'a> { + pub(crate) // For serialize.rs. iter: KeyIter<'a, openpgp::packet::key::PublicParts, openpgp::packet::key::UnspecifiedRole>, // Whether next has been called. diff --git a/openpgp/examples/encrypt-for.rs b/openpgp/examples/encrypt-for.rs index d416c321..327cb56d 100644 --- a/openpgp/examples/encrypt-for.rs +++ b/openpgp/examples/encrypt-for.rs @@ -7,9 +7,10 @@ use std::io; extern crate sequoia_openpgp as openpgp; use crate::openpgp::armor; use crate::openpgp::constants::DataFormat; +use crate::openpgp::packet::KeyFlags; use crate::openpgp::parse::Parse; use crate::openpgp::serialize::stream::{ - Message, LiteralWriter, Encryptor, EncryptionMode, + Message, LiteralWriter, Encryptor, }; fn main() { @@ -21,8 +22,8 @@ fn main() { } let mode = match args[1].as_ref() { - "at-rest" => EncryptionMode::AtRest, - "for-transport" => EncryptionMode::ForTransport, + "at-rest" => KeyFlags::default().set_encrypt_at_rest(true), + "for-transport" => KeyFlags::default().set_encrypt_for_transport(true), x => panic!("invalid mode: {:?}, \ must be either 'at-rest' or 'for-transport'", x), @@ -33,8 +34,13 @@ fn main() { openpgp::TPK::from_file(f) .expect("Failed to read key") }).collect(); - // Build a vector of references to hand to Encryptor. - let recipients: Vec<&openpgp::TPK> = tpks.iter().collect(); + + // Build a vector of recipients to hand to Encryptor. + let recipients = + tpks.iter() + .flat_map(|tpk| tpk.keys_valid().key_flags(mode.clone())) + .map(|(_, _, key)| key.into()) + .collect::<Vec<_>>(); // Compose a writer stack corresponding to the output format and // packet structure we want. First, we want the output to be @@ -49,7 +55,6 @@ fn main() { let encryptor = Encryptor::new(message, &[], // No symmetric encryption. &recipients, - mode, None, None) .expect("Failed to create encryptor"); let mut literal_writer = LiteralWriter::new(encryptor, DataFormat::Binary, diff --git a/openpgp/examples/generate-encrypt-decrypt.rs b/openpgp/examples/generate-encrypt-decrypt.rs index 301a4340..c0c4c4ed 100644 --- a/openpgp/examples/generate-encrypt-decrypt.rs +++ b/openpgp/examples/generate-encrypt-decrypt.rs @@ -6,6 +6,7 @@ extern crate sequoia_openpgp as openpgp; use crate::openpgp::crypto::SessionKey; use crate::openpgp::constants::SymmetricAlgorithm; use crate::openpgp::serialize::stream::*; +use crate::openpgp::packet::KeyFlags; use crate::openpgp::parse::stream::*; const MESSAGE: &'static str = "дружба"; @@ -40,14 +41,22 @@ fn generate() -> openpgp::Result<openpgp::TPK> { /// Encrypts the given message. fn encrypt(sink: &mut Write, plaintext: &str, recipient: &openpgp::TPK) -> openpgp::Result<()> { + // Build a vector of recipients to hand to Encryptor. + let recipients = + recipient.keys_valid() + .key_flags(KeyFlags::default() + .set_encrypt_at_rest(true) + .set_encrypt_for_transport(true)) + .map(|(_, _, key)| key.into()) + .collect::<Vec<_>>(); + // Start streaming an OpenPGP message. let message = Message::new(sink); // We want to encrypt a literal data packet. let encryptor = Encryptor::new(message, &[], // No symmetric encryption. - &[recipient], - EncryptionMode::ForTransport, + &recipients, None, None)?; // Emit a literal data packet. diff --git a/openpgp/examples/pad.rs b/openpgp/examples/pad.rs index b4e0f175..a959786d 100644 --- a/openpgp/examples/pad.rs +++ b/openpgp/examples/pad.rs @@ -7,9 +7,11 @@ use std::io; extern crate sequoia_openpgp as openpgp; use crate::openpgp::armor; use crate::openpgp::constants::DataFormat; +use crate::openpgp::KeyID; +use crate::openpgp::packet::KeyFlags; use crate::openpgp::parse::Parse; use crate::openpgp::serialize::stream::{ - Message, LiteralWriter, Encryptor, EncryptionMode, + Message, LiteralWriter, Encryptor, Recipient, }; use crate::openpgp::serialize::padding::*; @@ -22,8 +24,8 @@ fn main() { } let mode = match args[1].as_ref() { - "at-rest" => EncryptionMode::AtRest, - "for-transport" => EncryptionMode::ForTransport, + "at-rest" => KeyFlags::default().set_encrypt_at_rest(true), + "for-transport" => KeyFlags::default().set_encrypt_for_transport(true), x => panic!("invalid mode: {:?}, \ must be either 'at-rest' or 'for-transport'", x), @@ -34,8 +36,13 @@ fn main() { openpgp::TPK::from_file(f) .expect("Failed to read key") }).collect(); - // Build a vector of references to hand to Encryptor. - let recipients: Vec<&openpgp::TPK> = tpks.iter().collect(); + + // Build a vector of recipients to hand to Encryptor. + let recipients = + tpks.iter() + .flat_map(|tpk| tpk.keys_valid().key_flags(mode.clone())) + .map(|(_, _, key)| Recipient::new(KeyID::wildcard(), key)) + .collect::<Vec<_>>(); // Compose a writer stack corresponding to the output format and // packet structure we want. First, we want the output to be @@ -50,7 +57,6 @@ fn main() { let encryptor = Encryptor::new(message, &[], // No |