1use std::io;
7
8use rand::{thread_rng, CryptoRng, Rng};
9
10use crate::{
11 native::{
12 self,
13 crypto::{hash::HashAlgorithm, public_key::PublicKeyAlgorithm},
14 types::{CompressionAlgorithm, KeyId, KeyTrait, Mpi, PublicKeyTrait},
15 Message, SignedPublicKey, SignedPublicSubKey,
16 },
17 utils::spawn_blocking,
18 Error, Result,
19};
20
21#[derive(Debug)]
26pub enum SignedPublicKeyOrSubkey<'a> {
27 Key(&'a SignedPublicKey),
28 Subkey(&'a SignedPublicSubKey),
29}
30
31impl KeyTrait for SignedPublicKeyOrSubkey<'_> {
32 fn fingerprint(&self) -> Vec<u8> {
33 match self {
34 Self::Key(k) => k.fingerprint(),
35 Self::Subkey(k) => k.fingerprint(),
36 }
37 }
38
39 fn key_id(&self) -> KeyId {
40 match self {
41 Self::Key(k) => k.key_id(),
42 Self::Subkey(k) => k.key_id(),
43 }
44 }
45
46 fn algorithm(&self) -> PublicKeyAlgorithm {
47 match self {
48 Self::Key(k) => k.algorithm(),
49 Self::Subkey(k) => k.algorithm(),
50 }
51 }
52}
53
54impl PublicKeyTrait for SignedPublicKeyOrSubkey<'_> {
55 fn verify_signature(
56 &self,
57 hash: HashAlgorithm,
58 data: &[u8],
59 sig: &[Mpi],
60 ) -> native::errors::Result<()> {
61 match self {
62 Self::Key(k) => k.verify_signature(hash, data, sig),
63 Self::Subkey(k) => k.verify_signature(hash, data, sig),
64 }
65 }
66
67 fn encrypt<R: Rng + CryptoRng>(
68 &self,
69 rng: &mut R,
70 plain: &[u8],
71 ) -> native::errors::Result<Vec<Mpi>> {
72 match self {
73 Self::Key(k) => k.encrypt(rng, plain),
74 Self::Subkey(k) => k.encrypt(rng, plain),
75 }
76 }
77
78 fn to_writer_old(&self, writer: &mut impl io::Write) -> native::errors::Result<()> {
79 match self {
80 Self::Key(k) => k.to_writer_old(writer),
81 Self::Subkey(k) => k.to_writer_old(writer),
82 }
83 }
84}
85
86fn find_pkey_for_encryption(key: &SignedPublicKey) -> Option<SignedPublicKeyOrSubkey> {
92 if key.is_encryption_key() {
93 Some(SignedPublicKeyOrSubkey::Key(key))
94 } else {
95 key.public_subkeys
96 .iter()
97 .find(|subkey| subkey.is_encryption_key())
98 .map(SignedPublicKeyOrSubkey::Subkey)
99 }
100}
101
102pub async fn encrypt(pkeys: Vec<SignedPublicKey>, plain_bytes: Vec<u8>) -> Result<Vec<u8>> {
104 spawn_blocking(move || {
105 let mut rng = thread_rng();
106
107 let msg = Message::new_literal_bytes("", &plain_bytes);
108
109 let pkeys: Vec<SignedPublicKeyOrSubkey> =
110 pkeys.iter().filter_map(find_pkey_for_encryption).collect();
111 let pkeys_refs: Vec<&SignedPublicKeyOrSubkey> = pkeys.iter().collect();
112
113 let encrypted_bytes = msg
114 .compress(CompressionAlgorithm::ZLIB)
115 .map_err(Error::CompressMessageError)?
116 .encrypt_to_keys(&mut rng, Default::default(), &pkeys_refs)
117 .map_err(Error::EncryptMessageError)?
118 .to_armored_bytes(None)
119 .map_err(Error::ExportEncryptedMessageToArmorError)?;
120
121 Ok(encrypted_bytes)
122 })
123 .await?
124}