summaryrefslogtreecommitdiffstats
path: root/openpgp/benches
diff options
context:
space:
mode:
authorNora Widdecke <nora@sequoia-pgp.org>2021-02-09 14:58:46 +0100
committerNora Widdecke <nora@sequoia-pgp.org>2021-04-13 12:38:16 +0200
commitd9c64350e210b3d9fde378029285bbdb6848a475 (patch)
tree83163f26a42804f995840a4c5d853a2285e2c15e /openpgp/benches
parentf8bbf6f27f259662bbb9bfca6b399445d44019c0 (diff)
bench: Add encrypt+sign and decrypt+verify.
Diffstat (limited to 'openpgp/benches')
-rw-r--r--openpgp/benches/common/decrypt.rs114
-rw-r--r--openpgp/benches/common/encrypt.rs44
-rw-r--r--openpgp/benches/decrypt_message.rs5
-rw-r--r--openpgp/benches/decrypt_verify_message.rs51
-rw-r--r--openpgp/benches/encrypt_sign_message.rs47
5 files changed, 233 insertions, 28 deletions
diff --git a/openpgp/benches/common/decrypt.rs b/openpgp/benches/common/decrypt.rs
index 48f157c5..fa507aa7 100644
--- a/openpgp/benches/common/decrypt.rs
+++ b/openpgp/benches/common/decrypt.rs
@@ -1,20 +1,22 @@
-use sequoia_openpgp::cert::Cert;
-use sequoia_openpgp::crypto::{Password, SessionKey};
-use sequoia_openpgp::packet::prelude::*;
-use sequoia_openpgp::packet::{PKESK, SKESK};
-use sequoia_openpgp::parse::stream::{
- DecryptionHelper, DecryptorBuilder, MessageStructure, VerificationHelper,
+use sequoia_openpgp as openpgp;
+use openpgp::cert::Cert;
+use openpgp::crypto::{Password, SessionKey};
+use openpgp::packet::prelude::*;
+use openpgp::packet::{PKESK, SKESK};
+use openpgp::parse::stream::{
+ DecryptionHelper, DecryptorBuilder, MessageLayer, MessageStructure,
+ VerificationHelper, VerificationError
};
-use sequoia_openpgp::parse::Parse;
-use sequoia_openpgp::policy::StandardPolicy;
-use sequoia_openpgp::types::SymmetricAlgorithm;
-use sequoia_openpgp::{Fingerprint, KeyHandle, Result};
+use openpgp::parse::Parse;
+use openpgp::policy::StandardPolicy;
+use openpgp::types::SymmetricAlgorithm;
+use openpgp::{Fingerprint, KeyHandle, Result};
use std::io::Write;
// Borrowed from the examples at
-// sequoia_openpgp::parse::stream::DecryptionHelper
-// sequoia_openpgp::parse::stream::Decryptor
+// openpgp::parse::stream::DecryptionHelper
+// openpgp::parse::stream::Decryptor
struct PasswordHelper {
password: Password,
}
@@ -62,7 +64,7 @@ pub fn decrypt_with_password(
sink: &mut dyn Write,
ciphertext: &[u8],
password: &str,
-) -> sequoia_openpgp::Result<()> {
+) -> openpgp::Result<()> {
let password = password.into();
// Make a helper that that feeds the password to the decryptor.
let helper = PasswordHelper { password };
@@ -79,17 +81,49 @@ pub fn decrypt_with_password(
}
// Borrowed from the examples at
-// sequoia_openpgp::parse::stream::DecryptionHelper
-// sequoia_openpgp::parse::stream::Decryptor
+// openpgp::parse::stream::DecryptionHelper
+// openpgp::parse::stream::Decryptor
struct CertHelper<'a> {
- cert: &'a Cert,
+ sender: Option<&'a Cert>,
+ recipient: &'a Cert,
}
impl VerificationHelper for CertHelper<'_> {
+ // get candidates for having created the signature
fn get_certs(&mut self, _ids: &[KeyHandle]) -> Result<Vec<Cert>> {
- Ok(Vec::new())
+ let mut certs = Vec::new();
+ // maybe check that the cert matches (one of the) ids
+ if let Some(sender) = self.sender {
+ certs.push(sender.clone());
+ }
+ Ok(certs)
}
- fn check(&mut self, _structure: MessageStructure) -> Result<()> {
+ // does the signature match the policy
+ // e.g. am I the intended recipient
+ fn check(&mut self, structure: MessageStructure) -> Result<()> {
+ for (i, layer) in structure.into_iter().enumerate() {
+ match layer {
+ MessageLayer::Encryption { .. } if i == 0 => (),
+ MessageLayer::Compression { .. } if i == 1 => (),
+ MessageLayer::SignatureGroup { ref results }
+ if i == 1 || i == 2 =>
+ {
+ if !results.iter().any(|r| r.is_ok()) {
+ for result in results {
+ let error = result.as_ref().err().unwrap();
+ println!("{:?}", error);
+ }
+ return Err(anyhow::anyhow!("No valid signature"));
+ }
+ }
+ _ => {
+ return Err(anyhow::anyhow!(
+ "Unexpected message structure {:?}",
+ layer
+ ))
+ }
+ }
+ }
Ok(())
}
}
@@ -107,10 +141,8 @@ impl DecryptionHelper for CertHelper<'_> {
{
let p = &StandardPolicy::new();
- // check that pkesk has right recipient
- // if yes, use decrypt function
- let keys: Vec<Key<key::SecretParts, key::UnspecifiedRole>> = self
- .cert
+ let cand_secret_keys: Vec<Key<key::SecretParts, key::UnspecifiedRole>> = self
+ .recipient
.keys()
.with_policy(p, None)
.for_transport_encryption()
@@ -119,7 +151,9 @@ impl DecryptionHelper for CertHelper<'_> {
.map(|amalgamation| amalgamation.key().clone().into())
.collect();
- let successful_key = keys
+ // check that pkesk has right recipient
+ // if yes, use decrypt function
+ let successful_key = cand_secret_keys
.iter()
.cloned()
.filter_map(|key| {
@@ -152,9 +186,39 @@ pub fn decrypt_with_cert(
sink: &mut dyn Write,
ciphertext: &[u8],
cert: &Cert,
-) -> sequoia_openpgp::Result<()> {
+) -> openpgp::Result<()> {
+ // Make a helper that that feeds the password to the decryptor.
+ let helper = CertHelper {
+ sender: None,
+ recipient: cert,
+ };
+
+ // Now, create a decryptor with a helper using the given Certs.
+ let p = &StandardPolicy::new();
+ let mut decryptor = DecryptorBuilder::from_bytes(ciphertext)?
+ .with_policy(p, None, helper)?;
+
+ // Decrypt the data.
+ std::io::copy(&mut decryptor, sink)?;
+
+ Ok(())
+}
+
+// This is marked as dead_code. Seems that using a function only from within
+// a benchmark loop hides it from the compiler.
+#[allow(dead_code)]
+// Decrypts the given message using the given password.
+pub fn decrypt_and_verify(
+ sink: &mut dyn Write,
+ ciphertext: &[u8],
+ sender: &Cert,
+ recipient: &Cert,
+) -> openpgp::Result<()> {
// Make a helper that that feeds the password to the decryptor.
- let helper = CertHelper { cert };
+ let helper = CertHelper {
+ sender: Some(sender),
+ recipient,
+ };
// Now, create a decryptor with a helper using the given Certs.
let p = &StandardPolicy::new();
diff --git a/openpgp/benches/common/encrypt.rs b/openpgp/benches/common/encrypt.rs
index 0b5c94d7..edd898b5 100644
--- a/openpgp/benches/common/encrypt.rs
+++ b/openpgp/benches/common/encrypt.rs
@@ -1,7 +1,9 @@
use sequoia_openpgp as openpgp;
use openpgp::cert::Cert;
use openpgp::policy::StandardPolicy;
-use openpgp::serialize::stream::{Encryptor, LiteralWriter, Message};
+use openpgp::serialize::stream::{
+ padding::Padder, Armorer, Encryptor, LiteralWriter, Message, Signer,
+};
use std::io::Write;
@@ -27,6 +29,46 @@ pub fn encrypt_to_cert(
Ok(sink)
}
+// naively encrypt and sign, without caring for revocation or expiration
+pub fn encrypt_to_cert_and_sign(
+ bytes: &[u8],
+ sender: &Cert,
+ recipient: &Cert,
+) -> openpgp::Result<Vec<u8>> {
+ let mut sink = vec![];
+
+ let p = &StandardPolicy::new();
+ let signing_keypair = sender
+ .keys()
+ .with_policy(p, None)
+ .secret()
+ .for_signing()
+ .nth(0)
+ .unwrap()
+ .key()
+ .clone()
+ .into_keypair()?;
+
+ let recipients = recipient
+ .keys()
+ .with_policy(p, None)
+ .supported()
+ .for_transport_encryption()
+ .for_storage_encryption();
+
+ let message = Message::new(&mut sink);
+ let message = Armorer::new(message).build()?;
+ let message = Encryptor::for_recipients(message, recipients).build()?;
+ let message = Padder::new(message).build()?;
+ let message = Signer::new(message, signing_keypair)
+ //.add_intended_recipient(&recipient)
+ .build()?;
+ let mut w = LiteralWriter::new(message).build()?;
+ w.write_all(bytes)?;
+ w.finalize()?;
+ Ok(sink)
+}
+
pub fn encrypt_with_password(
bytes: &[u8],
password: &str,
diff --git a/openpgp/benches/decrypt_message.rs b/openpgp/benches/decrypt_message.rs
index b59fb550..23987fc3 100644
--- a/openpgp/benches/decrypt_message.rs
+++ b/openpgp/benches/decrypt_message.rs
@@ -2,8 +2,9 @@ use criterion::{
criterion_group, criterion_main, BenchmarkId, Criterion, Throughput,
};
-use sequoia_openpgp::cert::Cert;
-use sequoia_openpgp::parse::Parse;
+use sequoia_openpgp as openpgp;
+use openpgp::cert::Cert;
+use openpgp::parse::Parse;
mod common;
use common::decrypt;
diff --git a/openpgp/benches/decrypt_verify_message.rs b/openpgp/benches/decrypt_verify_message.rs
new file mode 100644
index 00000000..33f15c3e
--- /dev/null
+++ b/openpgp/benches/decrypt_verify_message.rs
@@ -0,0 +1,51 @@
+use criterion::{
+ criterion_group, criterion_main, BenchmarkId, Criterion, Throughput,
+};
+
+use sequoia_openpgp as openpgp;
+use openpgp::cert::Cert;
+use openpgp::parse::Parse;
+
+mod common;
+use common::decrypt;
+use common::encrypt;
+
+lazy_static::lazy_static! {
+ static ref SENDER: Cert =
+ Cert::from_bytes(&include_bytes!("../tests/data/keys/sender.pgp")[..])
+ .unwrap();
+ static ref RECIPIENT: Cert =
+ Cert::from_bytes(&include_bytes!("../tests/data/keys/recipient.pgp")[..])
+ .unwrap();
+ static ref ZEROS_1_MB: Vec<u8> = vec![0; 1 * 1024 * 1024];
+ static ref ZEROS_10_MB: Vec<u8> = vec![0; 10 * 1024 * 1024];
+}
+
+fn decrypt_and_verify(bytes: &[u8], sender: &Cert, recipient: &Cert) {
+ let mut sink = Vec::new();
+ decrypt::decrypt_and_verify(&mut sink, &bytes, sender, recipient).unwrap();
+}
+
+fn bench_decrypt_verify(c: &mut Criterion) {
+ let mut group = c.benchmark_group("decrypt and verify message");
+
+ // Encrypt a very short, medium and very long message,
+ // and then benchmark decryption.
+ let messages = &[b"Hello world.", &ZEROS_1_MB[..], &ZEROS_10_MB[..]];
+
+ messages.iter().for_each(|m| {
+ let encrypted =
+ encrypt::encrypt_to_cert_and_sign(m, &SENDER, &RECIPIENT).unwrap();
+ group.throughput(Throughput::Bytes(encrypted.len() as u64));
+ group.bench_with_input(
+ BenchmarkId::new("decrypt and verify", m.len()),
+ &encrypted,
+ |b, e| b.iter(|| decrypt_and_verify(&e, &SENDER, &RECIPIENT)),
+ );
+ });
+
+ group.finish();
+}
+
+criterion_group!(benches, bench_decrypt_verify);
+criterion_main!(benches);
diff --git a/openpgp/benches/encrypt_sign_message.rs b/openpgp/benches/encrypt_sign_message.rs
new file mode 100644
index 00000000..03916f71
--- /dev/null
+++ b/openpgp/benches/encrypt_sign_message.rs
@@ -0,0 +1,47 @@
+use criterion::{
+ criterion_group, criterion_main, BenchmarkId, Criterion, Throughput,
+};
+
+use sequoia_openpgp as openpgp;
+use openpgp::cert::Cert;
+use openpgp::parse::Parse;
+
+mod common;
+use common::encrypt;
+
+lazy_static::lazy_static! {
+ static ref ZEROS_1_MB: Vec<u8> = vec![0; 1 * 1024 * 1024];
+ static ref ZEROS_10_MB: Vec<u8> = vec![0; 10 * 1024 * 1024];
+}
+
+pub fn encrypt_to_donald_sign_by_ivanka(bytes: &[u8]) {
+ let sender = Cert::from_bytes(
+ &include_bytes!("../tests/data/keys/ivanka-private.gpg")[..],
+ )
+ .unwrap();
+ let recipient = Cert::from_bytes(
+ &include_bytes!("../tests/data/keys/the-donald-private.gpg")[..],
+ )
+ .unwrap();
+ encrypt::encrypt_to_cert_and_sign(bytes, &sender, &recipient).unwrap();
+}
+
+fn bench_encrypt_sign(c: &mut Criterion) {
+ let mut group = c.benchmark_group("encrypt and sign message");
+
+ // Encrypt a very short, medium and very long message.
+ let messages = &[b"Hello world.", &ZEROS_1_MB[..], &ZEROS_10_MB[..]];
+
+ for message in messages {
+ group.throughput(Throughput::Bytes(message.len() as u64));
+ group.bench_with_input(
+ BenchmarkId::new("encrypt and sign", message.len()),
+ &message,
+ |b, m| b.iter(|| encrypt_to_donald_sign_by_ivanka(&m)),
+ );
+ }
+ group.finish();
+}
+
+criterion_group!(benches, bench_encrypt_sign);
+criterion_main!(benches);