mirror of
https://github.com/chatmail/core.git
synced 2026-05-19 14:56:33 +03:00
refactor: It's not actually necessary for Alice to remember how the message was encrypted
This commit is contained in:
@@ -71,7 +71,7 @@ fn criterion_benchmark(c: &mut Criterion) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let (mut msg, _) =
|
let mut msg =
|
||||||
decrypt(encrypted.clone().into_bytes(), &[], black_box(&secrets)).unwrap();
|
decrypt(encrypted.clone().into_bytes(), &[], black_box(&secrets)).unwrap();
|
||||||
let decrypted = msg.as_data_vec().unwrap();
|
let decrypted = msg.as_data_vec().unwrap();
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ fn criterion_benchmark(c: &mut Criterion) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let (mut msg, _) = decrypt(
|
let mut msg = decrypt(
|
||||||
encrypted.clone().into_bytes(),
|
encrypted.clone().into_bytes(),
|
||||||
&[key_pair.secret.clone()],
|
&[key_pair.secret.clone()],
|
||||||
black_box(&secrets),
|
black_box(&secrets),
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ pub fn try_decrypt<'a>(
|
|||||||
mail: &'a ParsedMail<'a>,
|
mail: &'a ParsedMail<'a>,
|
||||||
private_keyring: &'a [SignedSecretKey],
|
private_keyring: &'a [SignedSecretKey],
|
||||||
shared_secrets: &[String],
|
shared_secrets: &[String],
|
||||||
) -> Result<Option<(::pgp::composed::Message<'static>, Option<usize>)>> {
|
) -> Result<Option<::pgp::composed::Message<'static>>> {
|
||||||
let Some(encrypted_data_part) = get_encrypted_mime(mail) else {
|
let Some(encrypted_data_part) = get_encrypted_mime(mail) else {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -136,10 +136,6 @@ pub(crate) struct MimeMessage {
|
|||||||
/// Sender timestamp in secs since epoch. Allowed to be in the future due to unsynchronized
|
/// Sender timestamp in secs since epoch. Allowed to be in the future due to unsynchronized
|
||||||
/// clocks, but not too much.
|
/// clocks, but not too much.
|
||||||
pub(crate) timestamp_sent: i64,
|
pub(crate) timestamp_sent: i64,
|
||||||
|
|
||||||
/// How the message was encrypted (and now successfully decrypted):
|
|
||||||
/// The asymmetric key, an AUTH token, or a broadcast's shared secret.
|
|
||||||
pub(crate) was_encrypted_with: EncryptedWith,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
@@ -238,25 +234,6 @@ pub enum SystemMessage {
|
|||||||
CallEnded = 67,
|
CallEnded = 67,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub(crate) enum EncryptedWith {
|
|
||||||
AsymmetricKey,
|
|
||||||
BroadcastSecret(String),
|
|
||||||
AuthToken(String),
|
|
||||||
None,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EncryptedWith {
|
|
||||||
pub(crate) fn auth_token(&self) -> Option<&str> {
|
|
||||||
match self {
|
|
||||||
EncryptedWith::AsymmetricKey => None,
|
|
||||||
EncryptedWith::BroadcastSecret(_) => None,
|
|
||||||
EncryptedWith::AuthToken(token) => Some(token),
|
|
||||||
EncryptedWith::None => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const MIME_AC_SETUP_FILE: &str = "application/autocrypt-setup";
|
const MIME_AC_SETUP_FILE: &str = "application/autocrypt-setup";
|
||||||
|
|
||||||
impl MimeMessage {
|
impl MimeMessage {
|
||||||
@@ -389,64 +366,51 @@ impl MimeMessage {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
let num_broadcast_secrets = secrets.len();
|
|
||||||
secrets.extend(token::lookup_all(context, token::Namespace::Auth).await?);
|
secrets.extend(token::lookup_all(context, token::Namespace::Auth).await?);
|
||||||
|
|
||||||
let (mail, is_encrypted, decrypted_with) = match tokio::task::block_in_place(|| {
|
let (mail, is_encrypted) =
|
||||||
try_decrypt(&mail, &private_keyring, &secrets)
|
match tokio::task::block_in_place(|| try_decrypt(&mail, &private_keyring, &secrets)) {
|
||||||
}) {
|
Ok(Some(mut msg)) => {
|
||||||
Ok(Some((mut msg, index_of_secret))) => {
|
mail_raw = msg.as_data_vec().unwrap_or_default();
|
||||||
mail_raw = msg.as_data_vec().unwrap_or_default();
|
|
||||||
|
|
||||||
let decrypted_mail = mailparse::parse_mail(&mail_raw)?;
|
let decrypted_mail = mailparse::parse_mail(&mail_raw)?;
|
||||||
if std::env::var(crate::DCC_MIME_DEBUG).is_ok() {
|
if std::env::var(crate::DCC_MIME_DEBUG).is_ok() {
|
||||||
info!(
|
info!(
|
||||||
context,
|
context,
|
||||||
"decrypted message mime-body:\n{}",
|
"decrypted message mime-body:\n{}",
|
||||||
String::from_utf8_lossy(&mail_raw),
|
String::from_utf8_lossy(&mail_raw),
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
decrypted_msg = Some(msg);
|
|
||||||
|
|
||||||
timestamp_sent = Self::get_timestamp_sent(
|
|
||||||
&decrypted_mail.headers,
|
|
||||||
timestamp_sent,
|
|
||||||
timestamp_rcvd,
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Some(protected_aheader_value) = decrypted_mail
|
|
||||||
.headers
|
|
||||||
.get_header_value(HeaderDef::Autocrypt)
|
|
||||||
{
|
|
||||||
aheader_value = Some(protected_aheader_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
let decrypted_with = if let Some(index_of_secret) = index_of_secret {
|
|
||||||
let used_secret = secrets.into_iter().nth(index_of_secret).unwrap_or_default();
|
|
||||||
if index_of_secret < num_broadcast_secrets {
|
|
||||||
EncryptedWith::BroadcastSecret(used_secret)
|
|
||||||
} else {
|
|
||||||
EncryptedWith::AuthToken(used_secret)
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
EncryptedWith::AsymmetricKey
|
|
||||||
};
|
|
||||||
|
|
||||||
(Ok(decrypted_mail), true, decrypted_with)
|
decrypted_msg = Some(msg);
|
||||||
}
|
|
||||||
Ok(None) => {
|
timestamp_sent = Self::get_timestamp_sent(
|
||||||
mail_raw = Vec::new();
|
&decrypted_mail.headers,
|
||||||
decrypted_msg = None;
|
timestamp_sent,
|
||||||
(Ok(mail), false, EncryptedWith::None)
|
timestamp_rcvd,
|
||||||
}
|
);
|
||||||
Err(err) => {
|
|
||||||
mail_raw = Vec::new();
|
if let Some(protected_aheader_value) = decrypted_mail
|
||||||
decrypted_msg = None;
|
.headers
|
||||||
warn!(context, "decryption failed: {:#}", err);
|
.get_header_value(HeaderDef::Autocrypt)
|
||||||
(Err(err), false, EncryptedWith::None)
|
{
|
||||||
}
|
aheader_value = Some(protected_aheader_value);
|
||||||
};
|
}
|
||||||
|
|
||||||
|
(Ok(decrypted_mail), true)
|
||||||
|
}
|
||||||
|
Ok(None) => {
|
||||||
|
mail_raw = Vec::new();
|
||||||
|
decrypted_msg = None;
|
||||||
|
(Ok(mail), false)
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
mail_raw = Vec::new();
|
||||||
|
decrypted_msg = None;
|
||||||
|
warn!(context, "decryption failed: {:#}", err);
|
||||||
|
(Err(err), false)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let autocrypt_header = if !incoming {
|
let autocrypt_header = if !incoming {
|
||||||
None
|
None
|
||||||
@@ -656,7 +620,6 @@ impl MimeMessage {
|
|||||||
is_bot: None,
|
is_bot: None,
|
||||||
timestamp_rcvd,
|
timestamp_rcvd,
|
||||||
timestamp_sent,
|
timestamp_sent,
|
||||||
was_encrypted_with: decrypted_with,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
match partial {
|
match partial {
|
||||||
|
|||||||
14
src/pgp.rs
14
src/pgp.rs
@@ -251,7 +251,7 @@ pub fn decrypt(
|
|||||||
ctext: Vec<u8>,
|
ctext: Vec<u8>,
|
||||||
private_keys_for_decryption: &[SignedSecretKey],
|
private_keys_for_decryption: &[SignedSecretKey],
|
||||||
shared_secrets: &[String],
|
shared_secrets: &[String],
|
||||||
) -> Result<(pgp::composed::Message<'static>, Option<usize>)> {
|
) -> Result<pgp::composed::Message<'static>> {
|
||||||
let cursor = Cursor::new(ctext);
|
let cursor = Cursor::new(ctext);
|
||||||
let (msg, _headers) = Message::from_armor(cursor)?;
|
let (msg, _headers) = Message::from_armor(cursor)?;
|
||||||
|
|
||||||
@@ -277,12 +277,7 @@ pub fn decrypt(
|
|||||||
// remove one layer of compression
|
// remove one layer of compression
|
||||||
let msg = msg.decompress()?;
|
let msg = msg.decompress()?;
|
||||||
|
|
||||||
let decrypted_with_secret = ring_result
|
Ok(msg)
|
||||||
.message_password
|
|
||||||
.iter()
|
|
||||||
.position(|&p| p == InnerRingResult::Ok);
|
|
||||||
|
|
||||||
Ok((msg, decrypted_with_secret))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns fingerprints
|
/// Returns fingerprints
|
||||||
@@ -418,7 +413,7 @@ mod tests {
|
|||||||
HashSet<Fingerprint>,
|
HashSet<Fingerprint>,
|
||||||
Vec<u8>,
|
Vec<u8>,
|
||||||
)> {
|
)> {
|
||||||
let (mut msg, _) = decrypt(ctext.to_vec(), private_keys_for_decryption, &[])?;
|
let mut msg = decrypt(ctext.to_vec(), private_keys_for_decryption, &[])?;
|
||||||
let content = msg.as_data_vec()?;
|
let content = msg.as_data_vec()?;
|
||||||
let ret_signature_fingerprints =
|
let ret_signature_fingerprints =
|
||||||
valid_signature_fingerprints(&msg, public_keys_for_validation);
|
valid_signature_fingerprints(&msg, public_keys_for_validation);
|
||||||
@@ -622,14 +617,13 @@ mod tests {
|
|||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let bob_private_keyring = crate::key::load_self_secret_keyring(bob).await?;
|
let bob_private_keyring = crate::key::load_self_secret_keyring(bob).await?;
|
||||||
let (mut decrypted, index_of_secret) = decrypt(
|
let mut decrypted = decrypt(
|
||||||
ctext.into(),
|
ctext.into(),
|
||||||
&bob_private_keyring,
|
&bob_private_keyring,
|
||||||
&[shared_secret.to_string()],
|
&[shared_secret.to_string()],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
assert_eq!(decrypted.as_data_vec()?, plain);
|
assert_eq!(decrypted.as_data_vec()?, plain);
|
||||||
assert_eq!(index_of_secret, Some(0));
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -388,10 +388,7 @@ pub(crate) async fn handle_securejoin_handshake(
|
|||||||
}
|
}
|
||||||
// verify that the `Secure-Join-Auth:`-header matches the secret written to the QR code,
|
// verify that the `Secure-Join-Auth:`-header matches the secret written to the QR code,
|
||||||
// or that the message was encrypted with the secret written to the QR code.
|
// or that the message was encrypted with the secret written to the QR code.
|
||||||
let auth = mime_message
|
let Some(auth) = mime_message.get_header(HeaderDef::SecureJoinAuth) else {
|
||||||
.get_header(HeaderDef::SecureJoinAuth)
|
|
||||||
.or_else(|| mime_message.was_encrypted_with.auth_token());
|
|
||||||
let Some(auth) = auth else {
|
|
||||||
warn!(
|
warn!(
|
||||||
context,
|
context,
|
||||||
"Ignoring {step} message because of missing auth code."
|
"Ignoring {step} message because of missing auth code."
|
||||||
|
|||||||
Reference in New Issue
Block a user