summaryrefslogtreecommitdiffstats
path: root/guide/src/chapter_02.md
diff options
context:
space:
mode:
Diffstat (limited to 'guide/src/chapter_02.md')
-rw-r--r--guide/src/chapter_02.md716
1 files changed, 534 insertions, 182 deletions
diff --git a/guide/src/chapter_02.md b/guide/src/chapter_02.md
index 80d5cc1c..5db1cbdc 100644
--- a/guide/src/chapter_02.md
+++ b/guide/src/chapter_02.md
@@ -1,221 +1,573 @@
-Describes how to use some of Sequoia's parsers.
+Describes key creation, encryption, and decryption.
-Sequoia contains and exposes several parsers. In this chapter, we
-will cover some of them, starting from a high level parser, the
-[`TPKParser`] that parses transferable public keys ([`TPK`]s), all
-down to the actual OpenPGP [`PacketParser`].
+In this chapter, we will see how to use Sequoia's [low-level API] to
+generate an OpenPGP key, and use it to encrypt and decrypt some data.
+We will construct this program from top to bottom, concatenating the
+fragments yields the [`openpgp/examples/generate-encrypt-decrypt.rs`].
-[`TPKParser`]: ../../sequoia_openpgp/tpk/struct.TPKParser.html
-[`TPK`]: ../../sequoia_openpgp/struct.TPK.html
-[`PacketParser`]: ../../sequoia_openpgp/parse/struct.PacketParser.html
-
-# Parsing TPKs
-
-First, we will start with a string that presumably contains a
-transferable public key, and feed it into the [`TPKParser`]. On
-success, we can use or examine the resulting [`TPK`]:
+[low-level API]: ../../sequoia_openpgp/index.html
+[`openpgp/examples/generate-encrypt-decrypt.rs`]: https://gitlab.com/sequoia-pgp/sequoia/blob/master/openpgp/examples/generate-encrypt-decrypt.rs
```rust
+use std::io::{self, Write};
+
extern crate sequoia_openpgp as openpgp;
-use openpgp::parse::Parse;
-
-const KEY: &str =
- "-----BEGIN PGP PUBLIC KEY BLOCK-----
-
- xjMEXAfmvxYJKwYBBAHaRw8BAQdAVNM03IK1KDgDNCbf4XcARhfqzyx425FEJMQ5
- qF+DrwHNF+G8iM+BzrnPg8+Ezr/PhM6tzrvOt8+CwoQEExYKADYCHgMCmwEFglwH
- 5r8FiQWfpgAWIQTAh0R4plxUCh9zcrSiLq1hTRF0SgkQoi6tYU0RdEoCFQoAALip
- AP4sSVgNJogb/v0Qst0+WlmrJ6upG8Ynao5mnRFmfx2LjAEAyGJJBaEBB+x4kOse
- 9uACwAXFhBRLN9zGgbyySQ3fRwjOMwRcB+a/FgkrBgEEAdpHDwEBB0BXBFWMeVd1
- nNn/VqTVEgY3wknX/KkKfMWhslFJoyZ4L8LAOAQYFgoAMwKbAgWCXAfmvwWJBZ+m
- ABYhBMCHRHimXFQKH3NytKIurWFNEXRKCRCiLq1hTRF0SgIVCgB3dqAEGRYKACcF
- glwH5r8WIQRnpIdTo4Cms7fffcXmxol6TO+JJAkQ5saJekzviSQAAMuvAQDdRfbM
- u2bDtVqNLIP/0WD/5X0us49r1yXMH+Ilg5NEEQEAuSQ1pY+reS62ETUS0uKYhxxv
- 7OOsr8YM/ZMQ0exZsw/u+QEAuakAXrR7uFmWyigopQ7qMYfnK5zNfQNykvony5tS
- HpEBAJs3ZwHq+Q0ziAZNgcvdp0mklx8IXd8x59NjiP1t3mUBzjgEXAfmvxIKKwYB
- BAGXVQEFAQEHQJuIvcDm3Sh0+ZOE5hj7jCBas2xOCqYiG6+bWWieoxRrAwEICcKB
- BBgWCgAzApsMBYJcB+a/BYkFn6YAFiEEwIdEeKZcVAofc3K0oi6tYU0RdEoJEKIu
- rWFNEXRKAgsJAADx4wD/VrXZ7I/hBC37lzhyVEcCaHcorVXVn8ACCiyRmgmNbY4A
- /1lJmQJoDlpYlx3BAJ6RYuXRJoyU5KpcBf5afBPn8ncB
- =MHBq
- -----END PGP PUBLIC KEY BLOCK-----";
+use openpgp::serialize::stream::*;
+use openpgp::parse::stream::*;
+use openpgp::packet::key::SecretKey;
+
+const MESSAGE: &'static str = "дружба";
fn main() {
- let tpk = openpgp::TPK::from_bytes(KEY.as_bytes()).unwrap();
-
- assert_eq!(tpk.fingerprint().to_string(),
- "C087 4478 A65C 540A 1F73 72B4 A22E AD61 4D11 744A");
-
- // Iterate over UserIDs.
- assert_eq!(tpk.userids().count(), 1);
- assert_eq!(tpk.userids().nth(0).unwrap().userid(),
- &"Ἀριστοτέλης".into());
-
- // Iterate over subkeys.
- assert_eq!(tpk.subkeys().count(), 2);
- assert_eq!(tpk.subkeys().nth(0).unwrap().subkey().fingerprint().to_string(),
- "67A4 8753 A380 A6B3 B7DF 7DC5 E6C6 897A 4CEF 8924");
- assert_eq!(tpk.subkeys().nth(1).unwrap().subkey().fingerprint().to_string(),
- "185C DAA1 2723 0423 19E4 7F67 108F 2CAF 9034 356D");
+ // Generate a key.
+ let key = generate().unwrap();
+
+ // Encrypt the message.
+ let mut ciphertext = Vec::new();
+ encrypt(&mut ciphertext, MESSAGE, &key).unwrap();
+
+ // Decrypt the message.
+ let mut plaintext = Vec::new();
+ decrypt(&mut plaintext, &ciphertext, &key).unwrap();
+
+ assert_eq!(MESSAGE.as_bytes(), &plaintext[..]);
}
+#
+# /// Generates an encryption-capable key.
+# fn generate() -> openpgp::Result<openpgp::TPK> {
+# let (tpk, _revocation) = openpgp::tpk::TPKBuilder::default()
+# .add_userid("someone@example.org")
+# .add_encryption_subkey()
+# .generate()?;
+#
+# // Save the revocation certificate somewhere.
+#
+# Ok(tpk)
+# }
+#
+# /// Encrypts the given message.
+# fn encrypt(sink: &mut Write, plaintext: &str, recipient: &openpgp::TPK)
+# -> openpgp::Result<()> {
+# // 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)?;
+#
+# // Emit a literal data packet.
+# let mut literal_writer = LiteralWriter::new(
+# encryptor, openpgp::constants::DataFormat::Binary, None, None)?;
+#
+# // Encrypt the data.
+# literal_writer.write_all(plaintext.as_bytes())?;
+#
+# // Finalize the OpenPGP message to make sure that all data is
+# // written.
+# literal_writer.finalize()?;
+#
+# Ok(())
+# }
+#
+# /// Decrypts the given message.
+# fn decrypt(sink: &mut Write, ciphertext: &[u8], recipient: &openpgp::TPK)
+# -> openpgp::Result<()> {
+# // Make a helper that that feeds the recipient's secret key to the
+# // decryptor.
+# let helper = Helper {
+# secret: recipient,
+# };
+#
+# // Now, create a decryptor with a helper using the given TPKs.
+# let mut decryptor = Decryptor::from_bytes(ciphertext, helper)?;
+#
+# // Decrypt the data.
+# io::copy(&mut decryptor, sink)?;
+#
+# Ok(())
+# }
+#
+# struct Helper<'a> {
+# secret: &'a openpgp::TPK,
+# }
+#
+# impl<'a> VerificationHelper for Helper<'a> {
+# fn get_public_keys(&mut self, _ids: &[openpgp::KeyID])
+# -> openpgp::Result<Vec<openpgp::TPK>> {
+# // Return public keys for signature verification here.
+# Ok(Vec::new())
+# }
+#
+# fn check(&mut self, _sigs: Vec<Vec<VerificationResult>>)
+# -> openpgp::Result<()> {
+# // Implement your signature verification policy here.
+# Ok(())
+# }
+# }
+#
+# impl<'a> DecryptionHelper for Helper<'a> {
+# fn get_secret(&mut self,
+# _pkesks: &[&openpgp::packet::PKESK],
+# _skesks: &[&openpgp::packet::SKESK])
+# -> openpgp::Result<Option<Secret>>
+# {
+# // The encryption key is the first and only subkey.
+# let key = self.secret.subkeys().nth(0)
+# .map(|binding| binding.subkey().clone())
+# .unwrap();
+#
+# // The secret key is not encrypted.
+# let secret =
+# if let Some(SecretKey::Unencrypted {
+# ref mpis,
+# }) = key.secret() {
+# mpis.clone()
+# } else {
+# unreachable!()
+# };
+#
+# Ok(Some(Secret::Asymmetric {
+# identity: self.secret.fingerprint(),
+# key: key,
+# secret: secret,
+# }))
+# }
+# }
```
-# Parsing OpenPGP messages
+# Key generation
-Not all sequences of OpenPGP packets are in valid OpenPGP
-[`Message`]s, only those accepted by [this grammar] are. Sequoia
-contains a parser that parses packets and verifies the message
-structure using this grammar:
+First, we need to generate a new key. This key shall have one user
+id, and one encryption-capable subkey. We use the [`TPKBuilder`] to
+create it:
-[this grammar]: https://tools.ietf.org/html/rfc4880#section-11.3
-[`Message`]: ../../sequoia_openpgp/struct.Message.html
+[`TPKBuilder`]: ../../sequoia_openpgp/tpk/struct.TPKBuilder.html
```rust
-extern crate sequoia_openpgp as openpgp;
-use openpgp::parse::Parse;
+# use std::io::{self, Write};
+#
+# extern crate sequoia_openpgp as openpgp;
+# use openpgp::serialize::stream::*;
+# use openpgp::parse::stream::*;
+# use openpgp::packet::key::SecretKey;
+#
+# const MESSAGE: &'static str = "дружба";
+#
+# fn main() {
+# // Generate a key.
+# let key = generate().unwrap();
+#
+# // Encrypt the message.
+# let mut ciphertext = Vec::new();
+# encrypt(&mut ciphertext, MESSAGE, &key).unwrap();
+#
+# // Decrypt the message.
+# let mut plaintext = Vec::new();
+# decrypt(&mut plaintext, &ciphertext, &key).unwrap();
+#
+# assert_eq!(MESSAGE.as_bytes(), &plaintext[..]);
+# }
+#
+/// Generates an encryption-capable key.
+fn generate() -> openpgp::Result<openpgp::TPK> {
+ let (tpk, _revocation) = openpgp::tpk::TPKBuilder::default()
+ .add_userid("someone@example.org")
+ .add_encryption_subkey()
+ .generate()?;
+
+ // Save the revocation certificate somewhere.
+
+ Ok(tpk)
+}
+#
+# /// Encrypts the given message.
+# fn encrypt(sink: &mut Write, plaintext: &str, recipient: &openpgp::TPK)
+# -> openpgp::Result<()> {
+# // 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)?;
+#
+# // Emit a literal data packet.
+# let mut literal_writer = LiteralWriter::new(
+# encryptor, openpgp::constants::DataFormat::Binary, None, None)?;
+#
+# // Encrypt the data.
+# literal_writer.write_all(plaintext.as_bytes())?;
+#
+# // Finalize the OpenPGP message to make sure that all data is
+# // written.
+# literal_writer.finalize()?;
+#
+# Ok(())
+# }
+#
+# /// Decrypts the given message.
+# fn decrypt(sink: &mut Write, ciphertext: &[u8], recipient: &openpgp::TPK)
+# -> openpgp::Result<()> {
+# // Make a helper that that feeds the recipient's secret key to the
+# // decryptor.
+# let helper = Helper {
+# secret: recipient,
+# };
+#
+# // Now, create a decryptor with a helper using the given TPKs.
+# let mut decryptor = Decryptor::from_bytes(ciphertext, helper)?;
+#
+# // Decrypt the data.
+# io::copy(&mut decryptor, sink)?;
+#
+# Ok(())
+# }
+#
+# struct Helper<'a> {
+# secret: &'a openpgp::TPK,
+# }
+#
+# impl<'a> VerificationHelper for Helper<'a> {
+# fn get_public_keys(&mut self, _ids: &[openpgp::KeyID])
+# -> openpgp::Result<Vec<openpgp::TPK>> {
+# // Return public keys for signature verification here.
+# Ok(Vec::new())
+# }
+#
+# fn check(&mut self, _sigs: Vec<Vec<VerificationResult>>)
+# -> openpgp::Result<()> {
+# // Implement your signature verification policy here.
+# Ok(())
+# }
+# }
+#
+# impl<'a> DecryptionHelper for Helper<'a> {
+# fn get_secret(&mut self,
+# _pkesks: &[&openpgp::packet::PKESK],
+# _skesks: &[&openpgp::packet::SKESK])
+# -> openpgp::Result<Option<Secret>>
+# {
+# // The encryption key is the first and only subkey.
+# let key = self.secret.subkeys().nth(0)
+# .map(|binding| binding.subkey().clone())
+# .unwrap();
+#
+# // The secret key is not encrypted.
+# let secret =
+# if let Some(SecretKey::Unencrypted {
+# ref mpis,
+# }) = key.secret() {
+# mpis.clone()
+# } else {
+# unreachable!()
+# };
+#
+# Ok(Some(Secret::Asymmetric {
+# identity: self.secret.fingerprint(),
+# key: key,
+# secret: secret,
+# }))
+# }
+# }
+```
-const MESSAGE: &str =
- "-----BEGIN PGP MESSAGE-----
+# Encryption
- xA0DAAoW5saJekzviSQByxBiAAAAAADYtdiv2KfZgtipwnUEABYKACcFglwJHYoW
- IQRnpIdTo4Cms7fffcXmxol6TO+JJAkQ5saJekzviSQAAIJ6APwK6FxtHXn8txDl
- tBFsIXlOSLOs4BvArlZzZSMomIyFLAEAwCLJUChMICDxWXRlHxORqU5x6hlO3DdW
- sl/1DAbnRgI=
- =AqoO
- -----END PGP MESSAGE-----";
+To encrypt a message, we first compose a writer stack corresponding to
+the desired output format and packet structure. The resulting object
+implements [`io::Write`], and we simply write the plaintext to it.
-fn main() {
- let message = openpgp::Message::from_bytes(MESSAGE.as_bytes()).unwrap();
+[`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
- assert_eq!(message.body().and_then(|literal| literal.body()),
- Some("صداقة".as_bytes()));
+```rust
+# use std::io::{self, Write};
+#
+# extern crate sequoia_openpgp as openpgp;
+# use openpgp::serialize::stream::*;
+# use openpgp::parse::stream::*;
+# use openpgp::packet::key::SecretKey;
+#
+# const MESSAGE: &'static str = "дружба";
+#
+# fn main() {
+# // Generate a key.
+# let key = generate().unwrap();
+#
+# // Encrypt the message.
+# let mut ciphertext = Vec::new();
+# encrypt(&mut ciphertext, MESSAGE, &key).unwrap();
+#
+# // Decrypt the message.
+# let mut plaintext = Vec::new();
+# decrypt(&mut plaintext, &ciphertext, &key).unwrap();
+#
+# assert_eq!(MESSAGE.as_bytes(), &plaintext[..]);
+# }
+#
+# /// Generates an encryption-capable key.
+# fn generate() -> openpgp::Result<openpgp::TPK> {
+# let (tpk, _revocation) = openpgp::tpk::TPKBuilder::default()
+# .add_userid("someone@example.org")
+# .add_encryption_subkey()
+# .generate()?;
+#
+# // Save the revocation certificate somewhere.
+#
+# Ok(tpk)
+# }
+#
+/// Encrypts the given message.
+fn encrypt(sink: &mut Write, plaintext: &str, recipient: &openpgp::TPK)
+ -> openpgp::Result<()> {
+ // 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)?;
+
+ // Emit a literal data packet.
+ let mut literal_writer = LiteralWriter::new(
+ encryptor, openpgp::constants::DataFormat::Binary, None, None)?;
+
+ // Encrypt the data.
+ literal_writer.write_all(plaintext.as_bytes())?;
+
+ // Finalize the OpenPGP message to make sure that all data is
+ // written.
+ literal_writer.finalize()?;
+
+ Ok(())
}
+#
+# /// Decrypts the given message.
+# fn decrypt(sink: &mut Write, ciphertext: &[u8], recipient: &openpgp::TPK)
+# -> openpgp::Result<()> {
+# // Make a helper that that feeds the recipient's secret key to the
+# // decryptor.
+# let helper = Helper {
+# secret: recipient,
+# };
+#
+# // Now, create a decryptor with a helper using the given TPKs.
+# let mut decryptor = Decryptor::from_bytes(ciphertext, helper)?;
+#
+# // Decrypt the data.
+# io::copy(&mut decryptor, sink)?;
+#
+# Ok(())
+# }
+#
+# struct Helper<'a> {
+# secret: &'a openpgp::TPK,
+# }
+#
+# impl<'a> VerificationHelper for Helper<'a> {
+# fn get_public_keys(&mut self, _ids: &[openpgp::KeyID])
+# -> openpgp::Result<Vec<openpgp::TPK>> {
+# // Return public keys for signature verification here.
+# Ok(Vec::new())
+# }
+#
+# fn check(&mut self, _sigs: Vec<Vec<VerificationResult>>)
+# -> openpgp::Result<()> {
+# // Implement your signature verification policy here.
+# Ok(())
+# }
+# }
+#
+# impl<'a> DecryptionHelper for Helper<'a> {
+# fn get_secret(&mut self,
+# _pkesks: &[&openpgp::packet::PKESK],
+# _skesks: &[&openpgp::packet::SKESK])
+# -> openpgp::Result<Option<Secret>>
+# {
+# // The encryption key is the first and only subkey.
+# let key = self.secret.subkeys().nth(0)
+# .map(|binding| binding.subkey().clone())
+# .unwrap();
+#
+# // The secret key is not encrypted.
+# let secret =
+# if let Some(SecretKey::Unencrypted {
+# ref mpis,
+# }) = key.secret() {
+# mpis.clone()
+# } else {
+# unreachable!()
+# };
+#
+# Ok(Some(Secret::Asymmetric {
+# identity: self.secret.fingerprint(),
+# key: key,
+# secret: secret,
+# }))
+# }
+# }
```
-# Parsing packets into packet piles
+# Decryption
-[`PacketPile`]s are unstructured sequences of OpenPGP packets. Packet
-piles can be inspected, manipulated, validated using a formal grammar
-and thereby turned into [`Message`]s or [`TPK`]s using
-[`Message::from_packet_pile`] or [`TPK::from_packet_pile`], or just
-turned into a vector of [`Packet`]s:
+Decryption is more difficult than encryption. When we encrypt, we
+control the packet structure being generated. However, when we
+decrypt, the control flow is determined by the message being
+processed.
-[`PacketPile`]: ../../sequoia_openpgp/struct.PacketPile.html
-[`Packet`]: ../../sequoia_openpgp/enum.Packet.html
-[`TPK::from_packet_pile`]: ../../sequoia_openpgp/struct.TPK.html#method.from_packet_pile
-[`Message::from_packet_pile`]: ../../sequoia_openpgp/struct.Message.html#method.from_packet_pile
-
-```rust
-extern crate sequoia_openpgp as openpgp;
-use openpgp::parse::Parse;
+To use Sequoia's low-level streaming decryptor, we need to provide an
+object that implements [`VerificationHelper`] and
+[`DecryptionHelper`]. This object provides public and secret keys for
+the signature verification and decryption, and implements the
+signature verification policy.
-const MESSAGE: &str =
- "-----BEGIN PGP MESSAGE-----
+[`VerificationHelper`]: ../../sequoia_openpgp/parse/stream/trait.VerificationHelper.html
+[`DecryptionHelper`]: ../../sequoia_openpgp/parse/stream/trait.DecryptionHelper.html
- xA0DAAoW5saJekzviSQByxBiAAAAAADYtdiv2KfZgtipwnUEABYKACcFglwJHYoW
- IQRnpIdTo4Cms7fffcXmxol6TO+JJAkQ5saJekzviSQAAIJ6APwK6FxtHXn8txDl
- tBFsIXlOSLOs4BvArlZzZSMomIyFLAEAwCLJUChMICDxWXRlHxORqU5x6hlO3DdW
- sl/1DAbnRgI=
- =AqoO
- -----END PGP MESSAGE-----";
+To decrypt messages, we create a [`Decryptor`] with our helper.
+Decrypted data can be read from this using [`io::Read`].
-fn main() {
- let pile = openpgp::PacketPile::from_bytes(MESSAGE.as_bytes()).unwrap();
+[`Decryptor`]: ../../sequoia_openpgp/parse/stream/struct.Decryptor.html
+[`io::Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
- // For simplicity, turn the pile into a vector of packets.
- let packets: Vec<openpgp::Packet> = pile.into_children().collect();
+```rust
+# use std::io::{self, Write};
+#
+# extern crate sequoia_openpgp as openpgp;
+# use openpgp::serialize::stream::*;
+# use openpgp::parse::stream::*;
+# use openpgp::packet::key::SecretKey;
+#
+# const MESSAGE: &'static str = "дружба";
+#
+# fn main() {
+# // Generate a key.
+# let key = generate().unwrap();
+#
+# // Encrypt the message.
+# let mut ciphertext = Vec::new();
+# encrypt(&mut ciphertext, MESSAGE, &key).unwrap();
+#
+# // Decrypt the message.
+# let mut plaintext = Vec::new();
+# decrypt(&mut plaintext, &ciphertext, &key).unwrap();
+#
+# assert_eq!(MESSAGE.as_bytes(), &plaintext[..]);
+# }
+#
+# /// Generates an encryption-capable key.
+# fn generate() -> openpgp::Result<openpgp::TPK> {
+# let (tpk, _revocation) = openpgp::tpk::TPKBuilder::default()
+# .add_userid("someone@example.org")
+# .add_encryption_subkey()
+# .generate()?;
+#
+# // Save the revocation certificate somewhere.
+#
+# Ok(tpk)
+# }
+#
+# /// Encrypts the given message.
+# fn encrypt(sink: &mut Write, plaintext: &str, recipient: &openpgp::TPK)
+# -> openpgp::Result<()> {
+# // 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)?;
+#
+# // Emit a literal data packet.
+# let mut literal_writer = LiteralWriter::new(
+# encryptor, openpgp::constants::DataFormat::Binary, None, None)?;
+#
+# // Encrypt the data.
+# literal_writer.write_all(plaintext.as_bytes())?;
+#
+# // Finalize the OpenPGP message to make sure that all data is
+# // written.
+# literal_writer.finalize()?;
+#
+# Ok(())
+# }
+#
+/// Decrypts the given message.
+fn decrypt(sink: &mut Write, ciphertext: &[u8], recipient: &openpgp::TPK)
+ -> openpgp::Result<()> {
+ // Make a helper that that feeds the recipient's secret key to the
+ // decryptor.
+ let helper = Helper {
+ secret: recipient,
+ };
+
+ // Now, create a decryptor with a helper using the given TPKs.
+ let mut decryptor = Decryptor::from_bytes(ciphertext, helper)?;
+
+ // Decrypt the data.
+ io::copy(&mut decryptor, sink)?;
+
+ Ok(())
+}
- // There are three packets in that message.
- assert_eq!(packets.len(), 3);
+struct Helper<'a> {
+ secret: &'a openpgp::TPK,
+}
- // First, we expect an one pass signature packet.
- if let openpgp::Packet::OnePassSig(ref ops) = packets[0] {
- assert_eq!(ops.issuer().to_string(), "E6C6 897A 4CEF 8924");
- } else {
- panic!("expected one pass signature packet");
+impl<'a> VerificationHelper for Helper<'a> {
+ fn get_public_keys(&mut self, _ids: &[openpgp::KeyID])
+ -> openpgp::Result<Vec<openpgp::TPK>> {
+ // Return public keys for signature verification here.
+ Ok(Vec::new())
}
- // The second packet is the literal data packet.
- if let openpgp::Packet::Literal(ref literal) = packets[1] {
- assert_eq!(literal.body(), Some("صداقة".as_bytes()));
- } else {
- panic!("expected literal data packet");
+ fn check(&mut self, _sigs: Vec<Vec<VerificationResult>>)
+ -> openpgp::Result<()> {
+ // Implement your signature verification policy here.
+ Ok(())
}
+}
- // Finally, we expect the signature itself.
- if let openpgp::Packet::Signature(ref signature) = packets[2] {
- assert_eq!(signature.issuer_fingerprint().unwrap().to_string(),
- "67A4 8753 A380 A6B3 B7DF 7DC5 E6C6 897A 4CEF 8924");
- } else {
- panic!("expected signature packet");
+impl<'a> DecryptionHelper for Helper<'a> {
+ fn get_secret(&mut self,
+ _pkesks: &[&openpgp::packet::PKESK],
+ _skesks: &[&openpgp::packet::SKESK])
+ -> openpgp::Result<Option<Secret>>
+ {
+ // The encryption key is the first and only subkey.
+ let key = self.secret.subkeys().nth(0)
+ .map(|binding| binding.subkey().clone())
+ .unwrap();
+
+ // The secret key is not encrypted.
+ let secret =
+ if let Some(SecretKey::Unencrypted {
+ ref mpis,
+ }) = key.secret() {
+ mpis.clone()
+ } else {
+ unreachable!()
+ };
+
+ Ok(Some(Secret::Asymmetric {
+ identity: self.secret.fingerprint(),
+ key: key,
+ secret: secret,
+ }))
}
}
```
-# Streaming packet parsing
-
-Both the [`Message`]parser and the [`PacketPile`]parser build a tree
-structure in memory, and more importantly, they buffer the bodies of
-literal data packets. Both properties can be undesirable if a large
-number of packets is parsed, or the data contained in the message
-large. This problem is exacerbated by the fact that OpenPGP messages
-can be compressed, so that processing even small messages can lead to
-an unbounded amount of memory being allocated.
-
-To alleviate this problem, Sequoia features streaming interfaces that
-implement [`io::Read`] and [`io::Write`]. These interfaces allow
-processing of OpenPGP packets in constant space.
-
-[`io::Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
-[`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
-
-The core of Sequoia is our [`PacketParser`], upon which all higher
-level interfaces are built. It is the most flexible interface for
-processing OpenPGP packets, and it is the foundation for our streaming
-interfaces. Most of the time, it is not necessary to use this
-interface, but nevertheless, our parser is exposed as part of our API
-and can be used to quickly process large amounts of OpenPGP packets,
-e.g. for collecting statistics about the SKS keyserver dump. For a
-complete example, see [`openpgp/examples/statistics.rs`].
+# Further reading
-[`PacketParser`]: ../../sequoia_openpgp/parse/struct.PacketParser.html
-[`openpgp/examples/statistics.rs`]: https://gitlab.com/sequoia-pgp/sequoia/blob/master/openpgp/examples/statistics.rs
-
-```rust
-use std::io::Read;
+For more examples on how to read a key from a file, and then either
+encrypt or decrypt some messages, see
+[`openpgp/examples/encrypt-for.rs`] and
+[`openpgp/examples/decrypt-with.rs`].
-extern crate sequoia_openpgp as openpgp;
-use openpgp::parse::*;
-
-const MESSAGE: &str =
- "-----BEGIN PGP MESSAGE-----
-
- yMACA0JaaDYxQVkmU1nHKJOZA6l4wQTAABAAAAgACCAAUGaaCalNNxCUkepFQEtY
- hKSO3zFBWSZTWTYaxwsA6l5AAMAAAAggADCATUZBKSNSCUkcxQVkmU1k2GscLAOp
- eQADAAAAIIAAwgE1GQSkjUglJHMUFZJlNZNhrHCwDqXkAAwAAACCAAMIBNRkEpI1
- IJSRzFBWSZTWUmfJVgAWotAANkAAAggAFBmgClRjNkhJTMqEqoN9JCSnC7kinChI
- H89bU4A=
- =eySo
- -----END PGP MESSAGE-----";
-
-fn main() {
- let mut bytes_read = 0;
- let mut buf = vec![0; 1024 * 1024];
-
- let mut ppr = PacketParser::from_bytes(MESSAGE.as_bytes()).unwrap();
- while let PacketParserResult::Some(mut pp) = ppr {
- // Match on the kind of packet here while it is in the parser.
- if let openpgp::Packet::Literal(_) = pp.packet {
- // Stream the content of the literal packet.
- while let Ok(_) = pp.read_exact(&mut buf) {
- bytes_read += buf.len();
- }
- }
-
- // Start parsing the next packet.
- ppr = pp.recurse().unwrap().1;
- }
-
- assert_eq!(bytes_read, 128 * 1024 * 1024); // 128 megabytes
-}
-```
+[`openpgp/examples/encrypt-for.rs`]: https://gitlab.com/sequoia-pgp/sequoia/blob/master/openpgp/examples/encrypt-for.rs
+[`openpgp/examples/decrypt-with.rs`]: https://gitlab.com/sequoia-pgp/sequoia/blob/master/openpgp/examples/decrypt-with.rs