Skip to main content

mini_mail_auth/
lib.rs

1//! A minimal DKIM signing library for Rust.
2
3// Module declarations
4pub mod common;
5pub mod dkim;
6
7// Re-export the main signer struct and other necessary components.
8pub use common::crypto::{RsaKey, Sha256};
9pub use common::headers::HeaderWriter;
10pub use dkim::{DkimSigner, Signature};
11
12/// A simplified function to sign an email with an RSA-SHA256 DKIM signature.
13///
14/// # Arguments
15///
16/// * `email` - The full email content (headers and body) as a string slice.
17/// * `domain` - The signing domain (e.g., "example.com").
18/// * `selector` - The DKIM selector (e.g., "default").
19/// * `private_key` - The RSA private key in PKCS#1 PEM format.
20///
21/// # Returns
22///
23/// A `String` containing the DKIM signature header prepended to the original email.
24pub fn sign_email(email: &str, domain: &str, selector: &str, private_key: &str) -> String {
25    // Sign an e-mail message using RSA-SHA256
26    let pk_rsa = RsaKey::<Sha256>::from_pkcs1_pem(private_key).unwrap();
27    let signature_rsa = DkimSigner::from_key(pk_rsa)
28        .domain(domain)
29        .selector(selector)
30        .headers(["From", "To", "Subject"])
31        .sign(email.as_bytes())
32        .unwrap();
33
34    format!("{}{}", signature_rsa.to_header(), email)
35}
36
37/// A minimal error type for the library.
38#[derive(Debug, Clone, PartialEq, Eq)]
39pub enum Error {
40    NoHeadersFound,
41    CryptoError(String),
42    Base64,
43}
44
45pub type Result<T> = std::result::Result<T, Error>;
46
47impl std::error::Error for Error {}
48
49impl std::fmt::Display for Error {
50    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51        match self {
52            Error::NoHeadersFound => write!(f, "No headers found to sign"),
53            Error::CryptoError(err) => write!(f, "Cryptography error: {err}"),
54            Error::Base64 => write!(f, "Base64 encoding error."),
55        }
56    }
57}
58
59// Convert from rsa::errors::Error to our custom Error type.
60impl From<rsa::errors::Error> for Error {
61    fn from(err: rsa::errors::Error) -> Self {
62        Error::CryptoError(err.to_string())
63    }
64}
65
66// Convert from rsa::pkcs1::Error to our custom Error type.
67impl From<rsa::pkcs1::Error> for Error {
68    fn from(err: rsa::pkcs1::Error) -> Self {
69        Error::CryptoError(err.to_string())
70    }
71}