fix: avoid blocking on expensive pgp operations

This commit is contained in:
dignifiedquire
2020-05-25 00:17:01 +02:00
parent 477e689c74
commit 2adeadfd73
9 changed files with 241 additions and 217 deletions

View File

@@ -87,30 +87,30 @@ impl EncryptHelper {
/// Tries to encrypt the passed in `mail`.
pub async fn encrypt(
&mut self,
self,
context: &Context,
min_verified: PeerstateVerifiedStatus,
mail_to_encrypt: lettre_email::PartBuilder,
peerstates: &[(Option<Peerstate<'_>>, &str)],
peerstates: Vec<(Option<Peerstate<'_>>, &str)>,
) -> Result<String> {
let mut keyring = Keyring::default();
for (peerstate, addr) in peerstates
.iter()
.filter_map(|(state, addr)| state.as_ref().map(|s| (s, addr)))
.into_iter()
.filter_map(|(state, addr)| state.map(|s| (s, addr)))
{
let key = peerstate.peek_key(min_verified).ok_or_else(|| {
let key = peerstate.take_key(min_verified).ok_or_else(|| {
format_err!("proper enc-key for {} missing, cannot encrypt", addr)
})?;
keyring.add_ref(key);
keyring.add(key);
}
let public_key = Key::from(self.public_key.clone());
keyring.add_ref(&public_key);
let public_key = Key::from(self.public_key);
keyring.add(public_key);
let sign_key = Key::from(SignedSecretKey::load_self(context).await?);
let raw_message = mail_to_encrypt.build().as_string().into_bytes();
let ctext = pgp::pk_encrypt(&raw_message, &keyring, Some(&sign_key))?;
let ctext = pgp::pk_encrypt(&raw_message, keyring, Some(sign_key)).await?;
Ok(ctext)
}
@@ -151,39 +151,38 @@ pub async fn try_decrypt(
}
/* possibly perform decryption */
let mut private_keyring = Keyring::default();
let mut public_keyring_for_validate = Keyring::default();
let mut out_mail = None;
let mut signatures = HashSet::default();
let self_addr = context.get_config(Config::ConfiguredAddr).await;
if let Some(self_addr) = self_addr {
if private_keyring
.load_self_private_for_decrypting(context, self_addr, &context.sql)
.await
if let Ok(private_keyring) =
Keyring::load_self_private_for_decrypting(context, self_addr).await
{
if peerstate.as_ref().map(|p| p.last_seen).unwrap_or_else(|| 0) == 0 {
peerstate = Peerstate::from_addr(&context, &from).await;
}
if let Some(ref peerstate) = peerstate {
if let Some(peerstate) = peerstate {
if peerstate.degrade_event.is_some() {
handle_degrade_event(context, &peerstate).await?;
}
if let Some(ref key) = peerstate.gossip_key {
public_keyring_for_validate.add_ref(key);
if let Some(key) = peerstate.gossip_key {
public_keyring_for_validate.add(key);
}
if let Some(ref key) = peerstate.public_key {
public_keyring_for_validate.add_ref(key);
if let Some(key) = peerstate.public_key {
public_keyring_for_validate.add(key);
}
}
out_mail = decrypt_if_autocrypt_message(
context,
mail,
&private_keyring,
&public_keyring_for_validate,
private_keyring,
public_keyring_for_validate,
&mut signatures,
)?;
)
.await?;
}
}
Ok((out_mail, signatures))
@@ -216,11 +215,11 @@ fn get_autocrypt_mime<'a, 'b>(mail: &'a ParsedMail<'b>) -> Result<&'a ParsedMail
Ok(&mail.subparts[1])
}
fn decrypt_if_autocrypt_message<'a>(
async fn decrypt_if_autocrypt_message<'a>(
context: &Context,
mail: &ParsedMail<'a>,
private_keyring: &Keyring,
public_keyring_for_validate: &Keyring,
private_keyring: Keyring,
public_keyring_for_validate: Keyring,
ret_valid_signatures: &mut HashSet<String>,
) -> Result<Option<Vec<u8>>> {
// The returned bool is true if we detected an Autocrypt-encrypted
@@ -240,20 +239,19 @@ fn decrypt_if_autocrypt_message<'a>(
info!(context, "Detected Autocrypt-mime message");
decrypt_part(
context,
encrypted_data_part,
private_keyring,
public_keyring_for_validate,
ret_valid_signatures,
)
.await
}
/// Returns Ok(None) if nothing encrypted was found.
fn decrypt_part(
_context: &Context,
async fn decrypt_part(
mail: &ParsedMail<'_>,
private_keyring: &Keyring,
public_keyring_for_validate: &Keyring,
private_keyring: Keyring,
public_keyring_for_validate: Keyring,
ret_valid_signatures: &mut HashSet<String>,
) -> Result<Option<Vec<u8>>> {
let data = mail.get_body_raw()?;
@@ -263,11 +261,12 @@ fn decrypt_part(
ensure!(ret_valid_signatures.is_empty(), "corrupt signatures");
let plain = pgp::pk_decrypt(
&data,
&private_keyring,
&public_keyring_for_validate,
data,
private_keyring,
public_keyring_for_validate,
Some(ret_valid_signatures),
)?;
)
.await?;
ensure!(!ret_valid_signatures.is_empty(), "no valid signatures");
return Ok(Some(plain));

View File

@@ -187,7 +187,7 @@ pub async fn render_setup_file(context: &Context, passphrase: &str) -> Result<St
true => Some(("Autocrypt-Prefer-Encrypt", "mutual")),
};
let private_key_asc = private_key.to_asc(ac_headers);
let encr = pgp::symm_encrypt(&passphrase, private_key_asc.as_bytes())?;
let encr = pgp::symm_encrypt(&passphrase, private_key_asc.as_bytes()).await?;
let replacement = format!(
concat!(
@@ -274,7 +274,7 @@ pub async fn continue_key_transfer(
if let Some(filename) = msg.get_file(context) {
let file = dc_open_file_std(context, filename)?;
let sc = normalize_setup_code(setup_code);
let armored_key = decrypt_setup_file(context, &sc, file)?;
let armored_key = decrypt_setup_file(&sc, file).await?;
set_self_key(context, &armored_key, true, true).await?;
maybe_add_bcc_self_device_msg(context).await?;
@@ -345,12 +345,11 @@ async fn set_self_key(
Ok(())
}
fn decrypt_setup_file<T: std::io::Read + std::io::Seek>(
_context: &Context,
async fn decrypt_setup_file<T: std::io::Read + std::io::Seek>(
passphrase: &str,
file: T,
) -> Result<String> {
let plain_bytes = pgp::symm_decrypt(passphrase, file)?;
let plain_bytes = pgp::symm_decrypt(passphrase, file).await?;
let plain_text = std::string::String::from_utf8(plain_bytes)?;
Ok(plain_text)
@@ -713,7 +712,7 @@ async fn export_self_keys(context: &Context, dir: impl AsRef<Path>) -> Result<()
for (id, public_key, private_key, is_default) in keys {
let id = Some(id).filter(|_| is_default != 0);
if let Some(key) = public_key {
if let Ok(key) = public_key {
if export_key_to_asc_file(context, &dir, id, &key)
.await
.is_err()
@@ -723,7 +722,7 @@ async fn export_self_keys(context: &Context, dir: impl AsRef<Path>) -> Result<()
} else {
export_errors += 1;
}
if let Some(key) = private_key {
if let Ok(key) = private_key {
if export_key_to_asc_file(context, &dir, id, &key)
.await
.is_err()
@@ -852,9 +851,6 @@ mod tests {
#[async_std::test]
async fn test_split_and_decrypt() {
let ctx = dummy_context().await;
let context = &ctx.ctx;
let buf_1 = S_EM_SETUPFILE.as_bytes().to_vec();
let (typ, headers, base64) = split_armored_data(&buf_1).unwrap();
assert_eq!(typ, BlockType::Message);
@@ -864,12 +860,10 @@ mod tests {
assert!(!base64.is_empty());
let setup_file = S_EM_SETUPFILE.to_string();
let decrypted = decrypt_setup_file(
context,
S_EM_SETUPCODE,
std::io::Cursor::new(setup_file.as_bytes()),
)
.unwrap();
let decrypted =
decrypt_setup_file(S_EM_SETUPCODE, std::io::Cursor::new(setup_file.as_bytes()))
.await
.unwrap();
let (typ, headers, _base64) = split_armored_data(decrypted.as_bytes()).unwrap();

View File

@@ -38,6 +38,8 @@ pub enum Error {
NoConfiguredAddr,
#[error("Configured address is invalid: {}", _0)]
InvalidConfiguredAddr(#[from] InvalidEmailError),
#[error("no data provided")]
Empty,
}
pub type Result<T> = std::result::Result<T, Error>;
@@ -260,22 +262,17 @@ impl Key {
!self.is_public()
}
pub fn from_slice(bytes: &[u8], key_type: KeyType) -> Option<Self> {
pub fn from_slice(bytes: &[u8], key_type: KeyType) -> Result<Self> {
if bytes.is_empty() {
return None;
return Err(Error::Empty);
}
let res: std::result::Result<Key, _> = match key_type {
KeyType::Public => SignedPublicKey::from_bytes(Cursor::new(bytes)).map(Into::into),
KeyType::Private => SignedSecretKey::from_bytes(Cursor::new(bytes)).map(Into::into),
let res = match key_type {
KeyType::Public => SignedPublicKey::from_bytes(Cursor::new(bytes))?.into(),
KeyType::Private => SignedSecretKey::from_bytes(Cursor::new(bytes))?.into(),
};
match res {
Ok(key) => Some(key),
Err(err) => {
eprintln!("Invalid key bytes: {:?}", err);
None
}
}
Ok(res)
}
pub fn from_armored_string(
@@ -625,7 +622,7 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD
KeyType::Private
},
);
assert!(bad_key.is_none());
assert!(bad_key.is_err());
}
}

View File

@@ -1,46 +1,47 @@
use std::borrow::Cow;
use anyhow::Result;
use crate::constants::KeyType;
use crate::context::Context;
use crate::key::Key;
use crate::sql::Sql;
#[derive(Default, Clone, Debug)]
pub struct Keyring<'a> {
keys: Vec<Cow<'a, Key>>,
pub struct Keyring {
keys: Vec<Key>,
}
impl<'a> Keyring<'a> {
pub fn add_owned(&mut self, key: Key) {
self.add(Cow::Owned(key))
impl Keyring {
pub fn add(&mut self, key: Key) {
self.keys.push(key)
}
pub fn add_ref(&mut self, key: &'a Key) {
self.add(Cow::Borrowed(key))
pub fn len(&self) -> usize {
self.keys.len()
}
fn add(&mut self, key: Cow<'a, Key>) {
self.keys.push(key);
pub fn is_empty(&self) -> bool {
self.keys.is_empty()
}
pub fn keys(&self) -> &[Cow<'a, Key>] {
pub fn keys(&self) -> &[Key] {
&self.keys
}
pub async fn load_self_private_for_decrypting(
&mut self,
context: &Context,
self_addr: impl AsRef<str>,
sql: &Sql,
) -> bool {
sql.query_get_value(
context,
"SELECT private_key FROM keypairs ORDER BY addr=? DESC, is_default DESC;",
paramsv![self_addr.as_ref().to_string()],
)
.await
.and_then(|blob: Vec<u8>| Key::from_slice(&blob, KeyType::Private))
.map(|key| self.add_owned(key))
.is_some()
) -> Result<Self> {
let blob: Vec<u8> = context
.sql
.query_get_value_result(
"SELECT private_key FROM keypairs ORDER BY addr=? DESC, is_default DESC;",
paramsv![self_addr.as_ref().to_string()],
)
.await?
.unwrap_or_default();
let key = async_std::task::spawn_blocking(move || Key::from_slice(&blob, KeyType::Private))
.await?;
Ok(Self { keys: vec![key] })
}
}

View File

@@ -463,7 +463,7 @@ impl<'a, 'b> MimeFactory<'a, 'b> {
let force_plaintext = self.should_force_plaintext();
let subject_str = self.subject_str().await;
let e2ee_guaranteed = self.is_e2ee_guaranteed();
let mut encrypt_helper = EncryptHelper::new(self.context).await?;
let encrypt_helper = EncryptHelper::new(self.context).await?;
let subject = encode_words(&subject_str);
@@ -560,7 +560,7 @@ impl<'a, 'b> MimeFactory<'a, 'b> {
}
let encrypted = encrypt_helper
.encrypt(self.context, min_verified, message, &peerstates)
.encrypt(self.context, min_verified, message, peerstates)
.await?;
outer_message = outer_message

View File

@@ -220,15 +220,15 @@ impl<'a> Peerstate<'a> {
res.public_key = row
.get(4)
.ok()
.and_then(|blob: Vec<u8>| Key::from_slice(&blob, KeyType::Public));
.and_then(|blob: Vec<u8>| Key::from_slice(&blob, KeyType::Public).ok());
res.gossip_key = row
.get(6)
.ok()
.and_then(|blob: Vec<u8>| Key::from_slice(&blob, KeyType::Public));
.and_then(|blob: Vec<u8>| Key::from_slice(&blob, KeyType::Public).ok());
res.verified_key = row
.get(9)
.ok()
.and_then(|blob: Vec<u8>| Key::from_slice(&blob, KeyType::Public));
.and_then(|blob: Vec<u8>| Key::from_slice(&blob, KeyType::Public).ok());
Ok(res)
})
@@ -367,6 +367,15 @@ impl<'a> Peerstate<'a> {
}
}
pub fn take_key(mut self, min_verified: PeerstateVerifiedStatus) -> Option<Key> {
match min_verified {
PeerstateVerifiedStatus::BidirectVerified => self.verified_key.take(),
PeerstateVerifiedStatus::Unverified => {
self.public_key.take().or_else(|| self.gossip_key.take())
}
}
}
pub fn peek_key(&self, min_verified: PeerstateVerifiedStatus) -> Option<&Key> {
match min_verified {
PeerstateVerifiedStatus::BidirectVerified => self.verified_key.as_ref(),

View File

@@ -238,124 +238,140 @@ fn select_pk_for_encryption(key: &SignedPublicKey) -> Option<SignedPublicKeyOrSu
/// Encrypts `plain` text using `public_keys_for_encryption`
/// and signs it using `private_key_for_signing`.
pub fn pk_encrypt(
pub async fn pk_encrypt(
plain: &[u8],
public_keys_for_encryption: &Keyring,
private_key_for_signing: Option<&Key>,
public_keys_for_encryption: Keyring,
private_key_for_signing: Option<Key>,
) -> Result<String> {
let lit_msg = Message::new_literal_bytes("", plain);
let pkeys: Vec<SignedPublicKeyOrSubkey> = public_keys_for_encryption
.keys()
.iter()
.filter_map(|key| {
key.as_ref()
async_std::task::spawn_blocking(move || {
let pkeys: Vec<SignedPublicKeyOrSubkey> = public_keys_for_encryption
.keys()
.iter()
.filter_map(|key| key.try_into().ok().and_then(select_pk_for_encryption))
.collect();
let pkeys_refs: Vec<&SignedPublicKeyOrSubkey> = pkeys.iter().collect();
let mut rng = thread_rng();
// TODO: measure time
let encrypted_msg = if let Some(ref private_key) = private_key_for_signing {
let skey: &SignedSecretKey = private_key
.try_into()
.ok()
.and_then(select_pk_for_encryption)
})
.collect();
let pkeys_refs: Vec<&SignedPublicKeyOrSubkey> = pkeys.iter().collect();
.map_err(|_| format_err!("Invalid private key"))?;
let mut rng = thread_rng();
lit_msg
.sign(skey, || "".into(), Default::default())
.and_then(|msg| msg.compress(CompressionAlgorithm::ZLIB))
.and_then(|msg| msg.encrypt_to_keys(&mut rng, Default::default(), &pkeys_refs))
} else {
lit_msg.encrypt_to_keys(&mut rng, Default::default(), &pkeys_refs)
};
// TODO: measure time
let encrypted_msg = if let Some(private_key) = private_key_for_signing {
let skey: &SignedSecretKey = private_key
.try_into()
.map_err(|_| format_err!("Invalid private key"))?;
let msg = encrypted_msg?;
let encoded_msg = msg.to_armored_string(None)?;
lit_msg
.sign(skey, || "".into(), Default::default())
.and_then(|msg| msg.compress(CompressionAlgorithm::ZLIB))
.and_then(|msg| msg.encrypt_to_keys(&mut rng, Default::default(), &pkeys_refs))
} else {
lit_msg.encrypt_to_keys(&mut rng, Default::default(), &pkeys_refs)
};
let msg = encrypted_msg?;
let encoded_msg = msg.to_armored_string(None)?;
Ok(encoded_msg)
Ok(encoded_msg)
})
.await
}
#[allow(clippy::implicit_hasher)]
pub fn pk_decrypt(
ctext: &[u8],
private_keys_for_decryption: &Keyring,
public_keys_for_validation: &Keyring,
pub async fn pk_decrypt(
ctext: Vec<u8>,
private_keys_for_decryption: Keyring,
public_keys_for_validation: Keyring,
ret_signature_fingerprints: Option<&mut HashSet<String>>,
) -> Result<Vec<u8>> {
let (msg, _) = Message::from_armor_single(Cursor::new(ctext))?;
let skeys: Vec<&SignedSecretKey> = private_keys_for_decryption
.keys()
.iter()
.filter_map(|key| {
let k: &Key = &key;
k.try_into().ok()
})
.collect();
let msgs = async_std::task::spawn_blocking(move || {
let cursor = Cursor::new(ctext);
let (msg, _) = Message::from_armor_single(cursor)?;
let skeys: Vec<&SignedSecretKey> = private_keys_for_decryption
.keys()
.iter()
.filter_map(|key| key.try_into().ok())
.collect();
let (decryptor, _) = msg.decrypt(|| "".into(), || "".into(), &skeys[..])?;
decryptor.collect::<pgp::errors::Result<Vec<_>>>()
})
.await?;
let (decryptor, _) = msg.decrypt(|| "".into(), || "".into(), &skeys[..])?;
let msgs = decryptor.collect::<pgp::errors::Result<Vec<_>>>()?;
ensure!(!msgs.is_empty(), "No valid messages found");
let dec_msg = &msgs[0];
let content = match msgs[0].get_content()? {
Some(content) => content,
None => bail!("Decrypted message is empty"),
};
if let Some(ret_signature_fingerprints) = ret_signature_fingerprints {
if !public_keys_for_validation.keys().is_empty() {
let pkeys: Vec<&SignedPublicKey> = public_keys_for_validation
.keys()
.iter()
.filter_map(|key| {
let k: &Key = &key;
k.try_into().ok()
})
.collect();
if !public_keys_for_validation.is_empty() {
let fingerprints = async_std::task::spawn_blocking(move || {
let dec_msg = &msgs[0];
for pkey in &pkeys {
if dec_msg.verify(&pkey.primary_key).is_ok() {
let fp = hex::encode_upper(pkey.fingerprint());
ret_signature_fingerprints.insert(fp);
let pkeys = public_keys_for_validation
.keys()
.iter()
.filter_map(|key| -> Option<&SignedPublicKey> { key.try_into().ok() });
let mut fingerprints = Vec::new();
for pkey in pkeys {
if dec_msg.verify(&pkey.primary_key).is_ok() {
let fp = hex::encode_upper(pkey.fingerprint());
fingerprints.push(fp);
}
}
}
fingerprints
})
.await;
ret_signature_fingerprints.extend(fingerprints);
}
}
match dec_msg.get_content()? {
Some(content) => Ok(content),
None => bail!("Decrypted message is empty"),
}
Ok(content)
}
/// Symmetric encryption.
pub fn symm_encrypt(passphrase: &str, plain: &[u8]) -> Result<String> {
let mut rng = thread_rng();
pub async fn symm_encrypt(passphrase: &str, plain: &[u8]) -> Result<String> {
let lit_msg = Message::new_literal_bytes("", plain);
let passphrase = passphrase.to_string();
let s2k = StringToKey::new_default(&mut rng);
let msg =
lit_msg.encrypt_with_password(&mut rng, s2k, Default::default(), || passphrase.into())?;
async_std::task::spawn_blocking(move || {
let mut rng = thread_rng();
let s2k = StringToKey::new_default(&mut rng);
let msg =
lit_msg.encrypt_with_password(&mut rng, s2k, Default::default(), || passphrase)?;
let encoded_msg = msg.to_armored_string(None)?;
let encoded_msg = msg.to_armored_string(None)?;
Ok(encoded_msg)
Ok(encoded_msg)
})
.await
}
/// Symmetric decryption.
pub fn symm_decrypt<T: std::io::Read + std::io::Seek>(
pub async fn symm_decrypt<T: std::io::Read + std::io::Seek>(
passphrase: &str,
ctext: T,
) -> Result<Vec<u8>> {
let (enc_msg, _) = Message::from_armor_single(ctext)?;
let decryptor = enc_msg.decrypt_with_password(|| passphrase.into())?;
let msgs = decryptor.collect::<pgp::errors::Result<Vec<_>>>()?;
ensure!(!msgs.is_empty(), "No valid messages found");
let passphrase = passphrase.to_string();
async_std::task::spawn_blocking(move || {
let decryptor = enc_msg.decrypt_with_password(|| passphrase)?;
match msgs[0].get_content()? {
Some(content) => Ok(content),
None => bail!("Decrypted message is empty"),
}
let msgs = decryptor.collect::<pgp::errors::Result<Vec<_>>>()?;
ensure!(!msgs.is_empty(), "No valid messages found");
match msgs[0].get_content()? {
Some(content) => Ok(content),
None => bail!("Decrypted message is empty"),
}
})
.await
}
#[cfg(test)]
@@ -437,17 +453,17 @@ mod tests {
/// A cyphertext encrypted to Alice & Bob, signed by Alice.
static ref CTEXT_SIGNED: String = {
let mut keyring = Keyring::default();
keyring.add_owned(KEYS.alice_public.clone());
keyring.add_ref(&KEYS.bob_public);
pk_encrypt(CLEARTEXT, &keyring, Some(&KEYS.alice_secret)).unwrap()
keyring.add(KEYS.alice_public.clone());
keyring.add(KEYS.bob_public.clone());
smol::block_on(pk_encrypt(CLEARTEXT, keyring, Some(KEYS.alice_secret.clone()))).unwrap()
};
/// A cyphertext encrypted to Alice & Bob, not signed.
static ref CTEXT_UNSIGNED: String = {
let mut keyring = Keyring::default();
keyring.add_owned(KEYS.alice_public.clone());
keyring.add_ref(&KEYS.bob_public);
pk_encrypt(CLEARTEXT, &keyring, None).unwrap()
keyring.add(KEYS.alice_public.clone());
keyring.add(KEYS.bob_public.clone());
smol::block_on(pk_encrypt(CLEARTEXT, keyring, None)).unwrap()
};
}
@@ -463,20 +479,21 @@ mod tests {
assert!(CTEXT_UNSIGNED.starts_with("-----BEGIN PGP MESSAGE-----"));
}
#[test]
fn test_decrypt_singed() {
#[async_std::test]
async fn test_decrypt_singed() {
// Check decrypting as Alice
let mut decrypt_keyring = Keyring::default();
decrypt_keyring.add_ref(&KEYS.alice_secret);
decrypt_keyring.add(KEYS.alice_secret.clone());
let mut sig_check_keyring = Keyring::default();
sig_check_keyring.add_ref(&KEYS.alice_public);
sig_check_keyring.add(KEYS.alice_public.clone());
let mut valid_signatures: HashSet<String> = Default::default();
let plain = pk_decrypt(
CTEXT_SIGNED.as_bytes(),
&decrypt_keyring,
&sig_check_keyring,
CTEXT_SIGNED.as_bytes().to_vec(),
decrypt_keyring,
sig_check_keyring,
Some(&mut valid_signatures),
)
.await
.map_err(|err| println!("{:?}", err))
.unwrap();
assert_eq!(plain, CLEARTEXT);
@@ -484,89 +501,94 @@ mod tests {
// Check decrypting as Bob
let mut decrypt_keyring = Keyring::default();
decrypt_keyring.add_ref(&KEYS.bob_secret);
decrypt_keyring.add(KEYS.bob_secret.clone());
let mut sig_check_keyring = Keyring::default();
sig_check_keyring.add_ref(&KEYS.alice_public);
sig_check_keyring.add(KEYS.alice_public.clone());
let mut valid_signatures: HashSet<String> = Default::default();
let plain = pk_decrypt(
CTEXT_SIGNED.as_bytes(),
&decrypt_keyring,
&sig_check_keyring,
CTEXT_SIGNED.as_bytes().to_vec(),
decrypt_keyring,
sig_check_keyring,
Some(&mut valid_signatures),
)
.await
.map_err(|err| println!("{:?}", err))
.unwrap();
assert_eq!(plain, CLEARTEXT);
assert_eq!(valid_signatures.len(), 1);
}
#[test]
fn test_decrypt_no_sig_check() {
#[async_std::test]
async fn test_decrypt_no_sig_check() {
let mut keyring = Keyring::default();
keyring.add_ref(&KEYS.alice_secret);
keyring.add(KEYS.alice_secret.clone());
let empty_keyring = Keyring::default();
let mut valid_signatures: HashSet<String> = Default::default();
let plain = pk_decrypt(
CTEXT_SIGNED.as_bytes(),
&keyring,
&empty_keyring,
CTEXT_SIGNED.as_bytes().to_vec(),
keyring,
empty_keyring,
Some(&mut valid_signatures),
)
.await
.unwrap();
assert_eq!(plain, CLEARTEXT);
assert_eq!(valid_signatures.len(), 0);
}
#[test]
fn test_decrypt_signed_no_key() {
#[async_std::test]
async fn test_decrypt_signed_no_key() {
// The validation does not have the public key of the signer.
let mut decrypt_keyring = Keyring::default();
decrypt_keyring.add_ref(&KEYS.bob_secret);
decrypt_keyring.add(KEYS.bob_secret.clone());
let mut sig_check_keyring = Keyring::default();
sig_check_keyring.add_ref(&KEYS.bob_public);
sig_check_keyring.add(KEYS.bob_public.clone());
let mut valid_signatures: HashSet<String> = Default::default();
let plain = pk_decrypt(
CTEXT_SIGNED.as_bytes(),
&decrypt_keyring,
&sig_check_keyring,
CTEXT_SIGNED.as_bytes().to_vec(),
decrypt_keyring,
sig_check_keyring,
Some(&mut valid_signatures),
)
.await
.unwrap();
assert_eq!(plain, CLEARTEXT);
assert_eq!(valid_signatures.len(), 0);
}
#[test]
fn test_decrypt_unsigned() {
#[async_std::test]
async fn test_decrypt_unsigned() {
let mut decrypt_keyring = Keyring::default();
decrypt_keyring.add_ref(&KEYS.bob_secret);
decrypt_keyring.add(KEYS.bob_secret.clone());
let sig_check_keyring = Keyring::default();
decrypt_keyring.add_ref(&KEYS.alice_public);
decrypt_keyring.add(KEYS.alice_public.clone());
let mut valid_signatures: HashSet<String> = Default::default();
let plain = pk_decrypt(
CTEXT_UNSIGNED.as_bytes(),
&decrypt_keyring,
&sig_check_keyring,
CTEXT_UNSIGNED.as_bytes().to_vec(),
decrypt_keyring,
sig_check_keyring,
Some(&mut valid_signatures),
)
.await
.unwrap();
assert_eq!(plain, CLEARTEXT);
assert_eq!(valid_signatures.len(), 0);
}
#[test]
fn test_decrypt_signed_no_sigret() {
#[async_std::test]
async fn test_decrypt_signed_no_sigret() {
// Check decrypting signed cyphertext without providing the HashSet for signatures.
let mut decrypt_keyring = Keyring::default();
decrypt_keyring.add_ref(&KEYS.bob_secret);
decrypt_keyring.add(KEYS.bob_secret.clone());
let mut sig_check_keyring = Keyring::default();
sig_check_keyring.add_ref(&KEYS.alice_public);
sig_check_keyring.add(KEYS.alice_public.clone());
let plain = pk_decrypt(
CTEXT_SIGNED.as_bytes(),
&decrypt_keyring,
&sig_check_keyring,
CTEXT_SIGNED.as_bytes().to_vec(),
decrypt_keyring,
sig_check_keyring,
None,
)
.await
.unwrap();
assert_eq!(plain, CLEARTEXT);
}