1use pgp::{
6 composed::{ArmorOptions, Message, MessageBuilder},
7 crypto::{aead::AeadAlgorithm, hash::HashAlgorithm, sym::SymmetricKeyAlgorithm},
8 types::{KeyDetails, KeyVersion, Password},
9};
10use rand::rngs::OsRng;
11
12use crate::{Error, PublicKey, Result, SecretKey, keys::hex};
13
14pub fn encrypt(data: &[u8], recipients: &[&PublicKey], signer: Option<&SecretKey>, armor: bool) -> Result<Vec<u8>> {
16 if recipients.is_empty() {
17 return Err(Error::NoEncryptionKey);
18 }
19 let subkeys: Vec<_> = recipients.iter().map(|r| r.encryption_subkeys()).collect();
20 if subkeys.iter().any(Vec::is_empty) {
21 return Err(Error::NoEncryptionKey);
22 }
23 let v6 = recipients.iter().all(|r| r.0.version() == KeyVersion::V6);
24 let mut builder = MessageBuilder::from_bytes("", data.to_vec());
25 if let Some(signer) = signer {
26 builder.sign(&signer.0.primary_key, Password::empty(), HashAlgorithm::Sha512);
27 }
28 let out = if v6 {
29 let mut builder =
30 builder.seipd_v2(OsRng, SymmetricKeyAlgorithm::AES256, AeadAlgorithm::Ocb, Default::default());
31 for subkey in subkeys.iter().flatten() {
32 builder.encrypt_to_key(OsRng, subkey)?;
33 }
34 if armor {
35 builder.to_armored_string(OsRng, ArmorOptions::default())?.into_bytes()
36 } else {
37 builder.to_vec(OsRng)?
38 }
39 } else {
40 let mut builder = builder.seipd_v1(OsRng, SymmetricKeyAlgorithm::AES256);
41 for subkey in subkeys.iter().flatten() {
42 builder.encrypt_to_key(OsRng, subkey)?;
43 }
44 if armor {
45 builder.to_armored_string(OsRng, ArmorOptions::default())?.into_bytes()
46 } else {
47 builder.to_vec(OsRng)?
48 }
49 };
50 Ok(out)
51}
52
53#[derive(Debug, Clone)]
55pub struct Decrypted {
56 pub data: Vec<u8>,
57 pub signed: bool,
59 pub verified_by: Option<String>,
61}
62
63pub fn decrypt(data: &[u8], keys: &[&SecretKey], senders: &[&PublicKey]) -> Result<Decrypted> {
65 let message = if is_armored(data) {
66 Message::from_armor(data).map_err(|_| Error::NotEncrypted)?.0
67 } else {
68 Message::from_bytes(data).map_err(|_| Error::NotEncrypted)?
69 };
70 if !message.is_encrypted() {
71 return Err(Error::NotEncrypted);
72 }
73 let passwords: Vec<Password> = keys.iter().map(|_| Password::empty()).collect();
74 let mut message = message
75 .decrypt_with_keys(passwords.iter().collect(), keys.iter().map(|k| &k.0).collect())
76 .map_err(|_| Error::Decrypt)?;
77 if message.is_compressed() {
78 message = message.decompress().map_err(|_| Error::Decrypt)?;
79 }
80 let data = message.as_data_vec().map_err(|_| Error::Decrypt)?;
81 let signed = matches!(message, Message::Signed { .. });
82 let verified_by = signed
83 .then(|| {
84 senders.iter().find_map(|sender| {
85 let keys = std::iter::once(&sender.0 as &dyn pgp::types::VerifyingKey)
86 .chain(sender.0.public_subkeys.iter().map(|s| s as &dyn pgp::types::VerifyingKey));
87 keys.into_iter().find(|k| message.verify(*k).is_ok()).map(|_| hex(sender.0.fingerprint().as_bytes()))
88 })
89 })
90 .flatten();
91 Ok(Decrypted { data, signed, verified_by })
92}
93
94pub(crate) fn is_armored(data: &[u8]) -> bool {
95 let start = data.iter().position(|b| !b.is_ascii_whitespace()).unwrap_or(0);
96 data[start..].starts_with(b"-----BEGIN PGP")
97}