mirror of
https://github.com/chatmail/core.git
synced 2026-05-19 23:06:32 +03:00
use proper Result instead of Option for encryption and decryption
This commit is contained in:
committed by
holger krekel
parent
cee0e22ce7
commit
8667de994e
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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) => {
|
||||||
|
|||||||
123
src/pgp.rs
123
src/pgp.rs
@@ -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)
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user