use proper Result instead of Option for encryption and decryption

This commit is contained in:
dignifiedquire
2019-09-18 17:07:28 +02:00
committed by holger krekel
parent cee0e22ce7
commit 8667de994e
4 changed files with 82 additions and 70 deletions

View File

@@ -196,8 +196,8 @@ pub fn dc_render_setup_file(context: &Context, passphrase: &str) -> Result<Strin
_ => Some(("Autocrypt-Prefer-Encrypt", "mutual")), _ => Some(("Autocrypt-Prefer-Encrypt", "mutual")),
}; };
let private_key_asc = private_key.to_asc(ac_headers); let private_key_asc = private_key.to_asc(ac_headers);
let encr = dc_pgp_symm_encrypt(&passphrase, private_key_asc.as_bytes()) let encr = dc_pgp_symm_encrypt(&passphrase, private_key_asc.as_bytes())?;
.ok_or(format_err!("Failed to encrypt private key."))?;
let replacement = format!( let replacement = format!(
concat!( concat!(
"-----BEGIN PGP MESSAGE-----\r\n", "-----BEGIN PGP MESSAGE-----\r\n",
@@ -385,7 +385,7 @@ fn set_self_key(
} }
pub unsafe fn dc_decrypt_setup_file( pub unsafe fn dc_decrypt_setup_file(
_context: &Context, context: &Context,
passphrase: *const libc::c_char, passphrase: *const libc::c_char,
filecontent: *const libc::c_char, filecontent: *const libc::c_char,
) -> *mut libc::c_char { ) -> *mut libc::c_char {
@@ -424,12 +424,17 @@ pub unsafe fn dc_decrypt_setup_file(
|| binary_bytes == 0) || binary_bytes == 0)
{ {
/* decrypt symmetrically */ /* decrypt symmetrically */
if let Some(plain) = dc_pgp_symm_decrypt( match dc_pgp_symm_decrypt(
as_str(passphrase), as_str(passphrase),
std::slice::from_raw_parts(binary as *const u8, binary_bytes), std::slice::from_raw_parts(binary as *const u8, binary_bytes),
) { ) {
let payload_c = CString::new(plain).unwrap(); Ok(plain) => {
payload = strdup(payload_c.as_ptr()); let payload_c = CString::new(plain).unwrap();
payload = strdup(payload_c.as_ptr());
}
Err(err) => {
error!(context, "Failed to decrypt message: {:?}", err);
}
} }
} }
} }

View File

@@ -296,7 +296,7 @@ impl E2eeHelper {
if (*plain).str_0.is_null() || (*plain).len <= 0 { if (*plain).str_0.is_null() || (*plain).len <= 0 {
ok_to_continue = false; ok_to_continue = false;
} else { } else {
if let Some(ctext_v) = dc_pgp_pk_encrypt( if let Ok(ctext_v) = dc_pgp_pk_encrypt(
std::slice::from_raw_parts( std::slice::from_raw_parts(
(*plain).str_0 as *const u8, (*plain).str_0 as *const u8,
(*plain).len, (*plain).len,
@@ -908,7 +908,7 @@ unsafe fn decrypt_part(
}; };
/*if we already have fingerprints, do not add more; this ensures, only the fingerprints from the outer-most part are collected */ /*if we already have fingerprints, do not add more; this ensures, only the fingerprints from the outer-most part are collected */
if let Some(plain) = dc_pgp_pk_decrypt( if let Ok(plain) = dc_pgp_pk_decrypt(
std::slice::from_raw_parts(decoded_data as *const u8, decoded_data_bytes), std::slice::from_raw_parts(decoded_data as *const u8, decoded_data_bytes),
&private_keyring, &private_keyring,
&public_keyring_for_validate, &public_keyring_for_validate,

View File

@@ -24,6 +24,8 @@ pub enum Error {
Utf8(std::str::Utf8Error), Utf8(std::str::Utf8Error),
#[fail(display = "{:?}", _0)] #[fail(display = "{:?}", _0)]
CStringError(crate::dc_tools::CStringError), CStringError(crate::dc_tools::CStringError),
#[fail(display = "PGP: {:?}", _0)]
Pgp(pgp::errors::Error),
} }
pub type Result<T> = std::result::Result<T, Error>; pub type Result<T> = std::result::Result<T, Error>;
@@ -70,6 +72,12 @@ impl From<crate::dc_tools::CStringError> for Error {
} }
} }
impl From<pgp::errors::Error> for Error {
fn from(err: pgp::errors::Error) -> Error {
Error::Pgp(err)
}
}
#[macro_export] #[macro_export]
macro_rules! bail { macro_rules! bail {
($e:expr) => { ($e:expr) => {

View File

@@ -12,6 +12,7 @@ use pgp::types::{CompressionAlgorithm, KeyTrait, SecretKeyTrait, StringToKey};
use rand::thread_rng; use rand::thread_rng;
use crate::dc_tools::*; use crate::dc_tools::*;
use crate::error::Error;
use crate::key::*; use crate::key::*;
use crate::keyring::*; use crate::keyring::*;
use crate::x::*; use crate::x::*;
@@ -189,7 +190,7 @@ pub fn dc_pgp_pk_encrypt(
plain: &[u8], plain: &[u8],
public_keys_for_encryption: &Keyring, public_keys_for_encryption: &Keyring,
private_key_for_signing: Option<&Key>, private_key_for_signing: Option<&Key>,
) -> Option<String> { ) -> Result<String, Error> {
let lit_msg = Message::new_literal_bytes("", plain); let lit_msg = Message::new_literal_bytes("", plain);
let pkeys: Vec<&SignedPublicKey> = public_keys_for_encryption let pkeys: Vec<&SignedPublicKey> = public_keys_for_encryption
.keys() .keys()
@@ -203,9 +204,10 @@ pub fn dc_pgp_pk_encrypt(
let mut rng = thread_rng(); let mut rng = thread_rng();
// TODO: measure time // TODO: measure time
// TODO: better error handling
let encrypted_msg = if let Some(private_key) = private_key_for_signing { let encrypted_msg = if let Some(private_key) = private_key_for_signing {
let skey: &SignedSecretKey = private_key.try_into().unwrap(); let skey: &SignedSecretKey = private_key
.try_into()
.map_err(|_| format_err!("Invalid private key"))?;
lit_msg lit_msg
.sign(skey, || "".into(), Default::default()) .sign(skey, || "".into(), Default::default())
@@ -215,9 +217,10 @@ pub fn dc_pgp_pk_encrypt(
lit_msg.encrypt_to_keys(&mut rng, Default::default(), &pkeys) lit_msg.encrypt_to_keys(&mut rng, Default::default(), &pkeys)
}; };
encrypted_msg let msg = encrypted_msg?;
.and_then(|msg| msg.to_armored_string(None)) let encoded_msg = msg.to_armored_string(None)?;
.ok()
Ok(encoded_msg)
} }
pub fn dc_pgp_pk_decrypt( pub fn dc_pgp_pk_decrypt(
@@ -225,77 +228,73 @@ pub fn dc_pgp_pk_decrypt(
private_keys_for_decryption: &Keyring, private_keys_for_decryption: &Keyring,
public_keys_for_validation: &Keyring, public_keys_for_validation: &Keyring,
ret_signature_fingerprints: Option<&mut HashSet<String>>, ret_signature_fingerprints: Option<&mut HashSet<String>>,
) -> Option<Vec<u8>> { ) -> Result<Vec<u8>, Error> {
// TODO: proper error handling let (msg, _) = Message::from_armor_single(Cursor::new(ctext))?;
if let Ok((msg, _)) = Message::from_armor_single(Cursor::new(ctext)) { let skeys: Vec<&SignedSecretKey> = private_keys_for_decryption
let skeys: Vec<&SignedSecretKey> = private_keys_for_decryption .keys()
.keys() .iter()
.iter() .filter_map(|key| {
.filter_map(|key| { let k: &Key = &key;
let k: &Key = &key; k.try_into().ok()
k.try_into().ok() })
}) .collect();
.collect();
msg.decrypt(|| "".into(), || "".into(), &skeys[..]) let (decryptor, _) = msg.decrypt(|| "".into(), || "".into(), &skeys[..])?;
.and_then(|(mut decryptor, _)| { let msgs = decryptor.collect::<Result<Vec<_>, _>>()?;
// TODO: how to handle the case when we detect multiple messages? ensure!(!msgs.is_empty(), "No valid messages found");
decryptor.next().expect("no message")
})
.and_then(|dec_msg| {
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();
for pkey in &pkeys { let dec_msg = &msgs[0];
if dec_msg.verify(&pkey.primary_key).is_ok() {
let fp = hex::encode_upper(pkey.fingerprint()); if let Some(ret_signature_fingerprints) = ret_signature_fingerprints {
ret_signature_fingerprints.insert(fp); 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();
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);
} }
dec_msg.get_content() }
}) }
.ok() }
.and_then(|content| content)
} else { match dec_msg.get_content()? {
None Some(content) => Ok(content),
None => bail!("Decrypted message is empty"),
} }
} }
/// Symmetric encryption. /// Symmetric encryption.
pub fn dc_pgp_symm_encrypt(passphrase: &str, plain: &[u8]) -> Option<String> { pub fn dc_pgp_symm_encrypt(passphrase: &str, plain: &[u8]) -> Result<String, Error> {
let mut rng = thread_rng(); let mut rng = thread_rng();
let lit_msg = Message::new_literal_bytes("", plain); let lit_msg = Message::new_literal_bytes("", plain);
let s2k = StringToKey::new_default(&mut rng); let s2k = StringToKey::new_default(&mut rng);
let msg = let msg =
lit_msg.encrypt_with_password(&mut rng, s2k, Default::default(), || passphrase.into()); lit_msg.encrypt_with_password(&mut rng, s2k, Default::default(), || passphrase.into())?;
msg.and_then(|msg| msg.to_armored_string(None)).ok() let encoded_msg = msg.to_armored_string(None)?;
Ok(encoded_msg)
} }
/// Symmetric decryption. /// Symmetric decryption.
pub fn dc_pgp_symm_decrypt(passphrase: &str, ctext: &[u8]) -> Option<Vec<u8>> { pub fn dc_pgp_symm_decrypt(passphrase: &str, ctext: &[u8]) -> Result<Vec<u8>, Error> {
let enc_msg = Message::from_bytes(Cursor::new(ctext)); let enc_msg = Message::from_bytes(Cursor::new(ctext))?;
let decryptor = enc_msg.decrypt_with_password(|| passphrase.into())?;
enc_msg let msgs = decryptor.collect::<Result<Vec<_>, _>>()?;
.and_then(|msg| { ensure!(!msgs.is_empty(), "No valid messages found");
let mut decryptor = msg.decrypt_with_password(|| passphrase.into())?;
match decryptor.next() { match msgs[0].get_content()? {
Some(x) => x, Some(content) => Ok(content),
None => Err(pgp::errors::Error::InvalidInput), None => bail!("Decrypted message is empty"),
} }
})
.and_then(|msg| msg.get_content())
.ok()
.and_then(|content| content)
} }