diff options
-rw-r--r-- | openpgp/Cargo.toml | 8 | ||||
-rw-r--r-- | openpgp/benches/common/decrypt.rs | 114 | ||||
-rw-r--r-- | openpgp/benches/common/encrypt.rs | 44 | ||||
-rw-r--r-- | openpgp/benches/decrypt_message.rs | 5 | ||||
-rw-r--r-- | openpgp/benches/decrypt_verify_message.rs | 51 | ||||
-rw-r--r-- | openpgp/benches/encrypt_sign_message.rs | 47 | ||||
-rw-r--r-- | openpgp/tests/data/keys/recipient.pgp | 34 | ||||
-rw-r--r-- | openpgp/tests/data/keys/sender.pgp | 34 |
8 files changed, 309 insertions, 28 deletions
diff --git a/openpgp/Cargo.toml b/openpgp/Cargo.toml index 1710ba31..e8851369 100644 --- a/openpgp/Cargo.toml +++ b/openpgp/Cargo.toml @@ -100,3 +100,11 @@ harness = false [[bench]] name = "decrypt_message" harness = false + +[[bench]] +name = "encrypt_sign_message" +harness = false + +[[bench]] +name = "decrypt_verify_message" +harness = false 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); diff --git a/openpgp/tests/data/keys/recipient.pgp b/openpgp/tests/data/keys/recipient.pgp new file mode 100644 index 00000000..6ca9c75d --- /dev/null +++ b/openpgp/tests/data/keys/recipient.pgp @@ -0,0 +1,34 @@ +-----BEGIN PGP PRIVATE KEY BLOCK----- +Comment: 5CF6 06BD 495F 956D FCB2 7ECC F1AB A7B5 80AC CEA4 +Comment: <recipient@example.com> + +xVgEYCPsqRYJKwYBBAHaRw8BAQdAyl+b2R+JeEfZ31BuDWeGiFAy8eY94qCVc7qF +u/rvtXYAAQCfwQXpLpl+IfcV3ZUEihbhMA9asAGJi2j4FoVBRxI9VA08wsALBB8W +CgB9BYJgI+ypAwsJBwkQ8auntYCszqRHFAAAAAAAHgAgc2FsdEBub3RhdGlvbnMu +c2VxdW9pYS1wZ3Aub3JnkBdVl2KuiH68rzSswYrKhIrUqWqGvVdRyRV6f733btID +FQoIApsBAh4BFiEEXPYGvUlflW38sn7M8auntYCszqQAAAvPAP9lC6JGGFXKWov6 +p+SZKq6qL83meOZQ54dBCq38h/zuTwD/eYjBNeNwSazSI+Qu9YD5YuJRgONTmUNP +Sgz5swMj5gTNFzxyZWNpcGllbnRAZXhhbXBsZS5jb20+wsAOBBMWCgCABYJgI+yp +AwsJBwkQ8auntYCszqRHFAAAAAAAHgAgc2FsdEBub3RhdGlvbnMuc2VxdW9pYS1w +Z3Aub3JnofcsAmtPZEK1hy0wdsSoSFFyB77Z0hCce9ntDVvoLuUDFQoIApkBApsB +Ah4BFiEEXPYGvUlflW38sn7M8auntYCszqQAAG6vAP43PGtJlVZFx/Mjk+VLK8Y2 +rHeEslPPI0QbmQweIY7+igD/RkJU2WpL8TS2bhEk4gGD93cr+Yx9d34rzcDuRDI/ +3gjHWARgI+ypFgkrBgEEAdpHDwEBB0BVlAiKHOzhsAh9R4bdzayASc1xCQg6iRpS +9CEGgxrJmAABAIXd7slG2jRbHTdrsCIP4FUqaC3XLOXBVNOMRF40nx8hDm7CwMIE +GBYKATQFgmAj7KkJEPGrp7WArM6kRxQAAAAAAB4AIHNhbHRAbm90YXRpb25zLnNl +cXVvaWEtcGdwLm9yZ5QTcp0kytebTq8hEkY+lzYH9XFHfcIgOCRKKBBJKq14ApsC +Ah4BvqAEGRYKAG8FgmAj7KkJEBpj51UNI+Y4RxQAAAAAAB4AIHNhbHRAbm90YXRp +b25zLnNlcXVvaWEtcGdwLm9yZ6EvXHFWkX0SxwyNW4IA/fjYbP1OtH9FKOZ8fyOs +hrLYFiEEF4/e0UMm/i0EBI7GGmPnVQ0j5jgAANGlAP0UiVrwDe9hpJqkvzSCuWZ3 +dcRFN99oDr6wxmori3zUdQD+MSglK7p0HadqwWAKBXsXYWxDNXOb7shyl4fP8DCU +jQ4WIQRc9ga9SV+Vbfyyfszxq6e1gKzOpAAALosBAI+CEzGmb+RowPzQX8GmpJsU +cpdCHOs7m0oVMq93Yh/WAP9l20ZKarqyqqh4ce5c/ElSMwEAOzp1EOoiTQzCJM2S +DMddBGAj7KkSCisGAQQBl1UBBQEBB0BZC7zH6V3bbQ3egHS/Jq/cWV2vkoswpt1A +qzEwRC/CDQMBCAkAAP9rIgacMmlwbILiWz0gOkdk7rzPBVgLh4+IYaYBq2ZbEA2p +wsADBBgWCgB1BYJgI+ypCRDxq6e1gKzOpEcUAAAAAAAeACBzYWx0QG5vdGF0aW9u +cy5zZXF1b2lhLXBncC5vcmf3RzS0xBiVO+HAWnEH6SGYc5MRgyAO1bNr1SYwEWLL +egKbDAIeARYhBFz2Br1JX5Vt/LJ+zPGrp7WArM6kAADRRQD+P4o3cQP72K1Zj3F1 +OTmQZK5gbokA6pRlL+cXND1kX8wBAL9aVpcPIEictRneZHT9xytDwjW9LRKEteSi +vjF27ooN +=EzWF +-----END PGP PRIVATE KEY BLOCK----- diff --git a/openpgp/tests/data/keys/sender.pgp b/openpgp/tests/data/keys/sender.pgp new file mode 100644 index 00000000..d6189f58 --- /dev/null +++ b/openpgp/tests/data/keys/sender.pgp @@ -0,0 +1,34 @@ +-----BEGIN PGP PRIVATE KEY BLOCK----- +Comment: C9CE CC00 2086 58E6 183D A1C6 AB27 F577 2E0E 7843 +Comment: <sender@example.com> + +xVgEYCPsxRYJKwYBBAHaRw8BAQdAUYZaTFKQNbjjRYLzTwy3Q8bB0NTFtgvf+XCA +IrCGlmQAAQC+mWrY1zkvlOUzTM86YCXHVv+17ANSxcQWcdRT06O8XhE4wsALBB8W +CgB9BYJgI+zFAwsJBwkQqyf1dy4OeENHFAAAAAAAHgAgc2FsdEBub3RhdGlvbnMu +c2VxdW9pYS1wZ3Aub3JnWXvgQQecnMWO/fYncaPEbcZfKx4gDAexicJP7jqTYroD +FQoIApsBAh4BFiEEyc7MACCGWOYYPaHGqyf1dy4OeEMAAL/kAQCphI/dOFGLoyM8 +nylwNNsR4eMwY2R+FQeg5/fa2hVw2QEA4bQLA3NV7ipe/NjhTr2Jg7VJOMTRRkz6 +8mN/x6QGxgTNFDxzZW5kZXJAZXhhbXBsZS5jb20+wsAOBBMWCgCABYJgI+zFAwsJ +BwkQqyf1dy4OeENHFAAAAAAAHgAgc2FsdEBub3RhdGlvbnMuc2VxdW9pYS1wZ3Au +b3JnIXF3QU6P6+GXFwbQEECgzntsyO8gvXlLepy/ucn+vYoDFQoIApkBApsBAh4B +FiEEyc7MACCGWOYYPaHGqyf1dy4OeEMAAEjUAQCFIkopGT8XtynPC8EK8xGUUDIQ +r2iMHo8hWUj54P05dwEAz21A3Zsfri2aJCFm6PF/PI1lgveOhIkmymPHn4u0HgDH +WARgI+zFFgkrBgEEAdpHDwEBB0CVc1gpEwyJwcfrKthXOf8Etrbyu5PYowQ4VjCf +USIWsAABAP3mLXdK97WvUtw4EB3C7Eco9W++7tlz6qvJg+qwW4YVEqrCwMIEGBYK +ATQFgmAj7MUJEKsn9XcuDnhDRxQAAAAAAB4AIHNhbHRAbm90YXRpb25zLnNlcXVv +aWEtcGdwLm9yZyztCZP7RO0A16UDnaBGz5INoSUHpMfKK1qxNjliywEMApsCAh4B +vqAEGRYKAG8FgmAj7MUJEJmUVZwG7s2BRxQAAAAAAB4AIHNhbHRAbm90YXRpb25z +LnNlcXVvaWEtcGdwLm9yZ7S9NDPI3eUn/BpxSx/4hVGWIZw4lOcQK2Kh9jrhC6WD +FiEEN7I0OVSvcntqZncCmZRVnAbuzYEAAML+AQCIcsXZ2eFMp29lZXubgWhu/A6+ +9s31IuaoxlfTq+mLJQEAhRkzX14wAInsjW0mU/ZOWYjgtqvQNv+MI0CjQdpEAwcW +IQTJzswAIIZY5hg9ocarJ/V3Lg54QwAAU6YBAOOBEW6s61h+PJ1uai5tdPuAf0Zv +YxG3MIYDolq5lXeGAQDyV6bwplTWAQycLo1X5+41Bt83NtxVOE4beqsV+/9TBcdd +BGAj7MUSCisGAQQBl1UBBQEBB0AbjB79xZ0YRFyoiGFHC4dFWbGy4V+SfwsFl/fD +vLhTRQMBCAkAAP9h4mp41OcmJVpHhX7aBdWBMYwnrDklRBRBkMgY3qcMYA7rwsAD +BBgWCgB1BYJgI+zFCRCrJ/V3Lg54Q0cUAAAAAAAeACBzYWx0QG5vdGF0aW9ucy5z +ZXF1b2lhLXBncC5vcmf1V+e7SqWcmY8cvjM69asiI1ja4oZDZ3OV4r8Wkqs2dgKb +DAIeARYhBMnOzAAghljmGD2hxqsn9XcuDnhDAADlYwD+P3oMVWOsWhKkWrutqbgW +Ozik7yeh1H90w5I2XHNFtVIA/1dW/azFsqrNHf8ZFmmfGsJ3h/MePsz/ao4BJ69v +CsAI +=lNEM +-----END PGP PRIVATE KEY BLOCK----- |