Add encryption

- actually encrypt the body of a mail
This commit is contained in:
Malte Meiboom
2025-12-17 11:11:28 +01:00
parent 64312da01d
commit eeda63f5ab
4 changed files with 55 additions and 7 deletions
+39
View File
@@ -4,12 +4,14 @@
// cryptographic functions
//
use std::io::Write;
use std::sync::Arc;
use anyhow;
use bytes::Bytes;
use sequoia_openpgp::parse::{PacketParser, PacketParserResult, Parse};
use sequoia_openpgp::policy::StandardPolicy;
use sequoia_openpgp::serialize::stream::{Message, Armorer, Encryptor, LiteralWriter};
use sequoia_openpgp::{Fingerprint, Cert, Packet};
use sequoia_openpgp::cert::raw::RawCertParser;
use sequoia_cert_store::{Store, CertStore, LazyCert};
@@ -20,6 +22,7 @@ use wot::{Depth, Path};
use crate::types::errors::HuskError;
use crate::types::husk_context::HuskContext;
use crate::types::introducer::Introducer;
use crate::types::recipient::Recipient;
pub fn get_local_trust_root(cert_store: &CertStore) -> anyhow::Result<Cert> {
@@ -155,6 +158,42 @@ pub fn is_encrypted(body: &Bytes) -> bool {
false
}
pub fn encrypt(context: &HuskContext<'_>, body: &Bytes, recipients: &Vec<Recipient>)
-> anyhow::Result<Bytes> {
let mut keys = Vec::new();
// XXX: handle the case where a certificate misses an encryption subkey
for rcpt in recipients {
if rcpt.can_encrypt() {
for cert in &rcpt.certs {
cert.with_policy(&context.policy, None)?
.keys()
.supported()
.alive()
.revoked(false)
.for_transport_encryption()
.for_each(|k| {
keys.push(k);
});
}
}
}
if keys.len() > 0 {
let mut sink = Vec::new();
let message = Message::new(&mut sink);
let message = Armorer::new(message).build()?;
let message = Encryptor::for_recipients(message, keys).build()?;
let mut message = LiteralWriter::new(message).build()?;
message.write_all(&body[..])?;
message.finalize()?;
Ok(Bytes::from(sink))
} else {
Err(HuskError::NoEncryptionKeys.into())
}
}
#[cfg(test)]
pub mod tests {
use bytes::Bytes;
+11 -4
View File
@@ -210,14 +210,21 @@ impl Daemon {
// none -> accept
// partial -> accept (later: split)
// full -> encrypt
// check mailbody
// is encrypted -> accept
// else -> encrypt
let protection = ProtectionPossibility::from(&context.mail);
if protection == ProtectionPossibility::Full {
// encrypt
// if an error occures the body is not exchanged
match crypto::encrypt(&context, &body, &context.mail.recipients) {
Ok(encrypted) => {
if cx.actions.replace_body(&encrypted).await.is_err() {
log::error!("Cannot exchange body");
}
},
Err(e) => {
log::error!("{}", e);
}
}
}
}
+3 -1
View File
@@ -11,5 +11,7 @@ pub enum HuskError {
#[error("Cannot find local trust root")]
NoLocalTrustRoot,
#[error("Cannot access cert store")]
NoCertStore
NoCertStore,
#[error("No encryption keys found")]
NoEncryptionKeys,
}
+2 -2
View File
@@ -23,7 +23,7 @@ pub struct MailContext<'mc> {
pub recipients: Vec<Recipient<'mc>>,
// header
body: Vec<Bytes>,
pub body_size: usize,
pub body_size: usize,
}
impl<'mc> MailContext<'mc> {
@@ -46,7 +46,7 @@ impl<'mc> MailContext<'mc> {
recipient.certs = certs;
self.recipients.push(recipient);
Ok(())
}