mail_auth/common/crypto/
mod.rs1use super::headers::{Writable, Writer};
8use crate::{Result, dkim::Canonicalization};
9
10#[cfg(any(feature = "ring", feature = "aws-lc-rs"))]
11mod ring_impls;
12#[cfg(any(feature = "ring", feature = "aws-lc-rs"))]
13pub use ring_impls::{Ed25519Key, RsaKey};
14#[cfg(any(feature = "ring", feature = "aws-lc-rs"))]
15pub(crate) use ring_impls::{Ed25519PublicKey, RsaPublicKey};
16
17pub trait SigningKey {
18 type Hasher: HashImpl;
19
20 fn sign(&self, input: impl Writable) -> Result<Vec<u8>>;
21
22 fn hash(&self, data: impl Writable) -> HashOutput {
23 let mut hasher = <Self::Hasher as HashImpl>::hasher();
24 data.write(&mut hasher);
25 hasher.complete()
26 }
27
28 fn algorithm(&self) -> Algorithm;
29}
30
31pub trait VerifyingKey {
32 fn verify<'a>(
33 &self,
34 headers: &mut dyn Iterator<Item = (&'a [u8], &'a [u8])>,
35 signature: &[u8],
36 canonicalication: Canonicalization,
37 algorithm: Algorithm,
38 ) -> Result<()>;
39}
40
41pub(crate) enum VerifyingKeyType {
42 Rsa,
43 Ed25519,
44}
45
46impl VerifyingKeyType {
47 pub(crate) fn verifying_key(
48 &self,
49 bytes: &[u8],
50 ) -> Result<Box<dyn VerifyingKey + Send + Sync>> {
51 match self {
52 #[cfg(any(feature = "ring", feature = "aws-lc-rs"))]
53 Self::Rsa => RsaPublicKey::verifying_key_from_bytes(bytes),
54 #[cfg(any(feature = "ring", feature = "aws-lc-rs"))]
55 Self::Ed25519 => Ed25519PublicKey::verifying_key_from_bytes(bytes),
56 }
57 }
58}
59
60pub trait HashContext: Writer + Sized {
61 fn complete(self) -> HashOutput;
62}
63
64pub trait HashImpl {
65 type Context: HashContext;
66
67 fn hasher() -> Self::Context;
68}
69
70#[derive(Clone, Copy)]
71pub struct Sha1;
72
73#[derive(Clone, Copy)]
74pub struct Sha256;
75
76#[derive(Debug, Clone, Copy, PartialEq, Eq)]
77#[repr(u64)]
78pub enum HashAlgorithm {
79 Sha1 = R_HASH_SHA1,
80 Sha256 = R_HASH_SHA256,
81}
82
83#[cfg(feature = "aws-lc-rs")]
84use aws_lc_rs as crypto_backend;
85#[cfg(all(feature = "ring", not(feature = "aws-lc-rs")))]
86use ring as crypto_backend;
87
88#[cfg(any(feature = "ring", feature = "aws-lc-rs"))]
89impl HashAlgorithm {
90 pub fn hash(&self, data: impl Writable) -> HashOutput {
91 match self {
92 Self::Sha1 => {
93 let mut hasher = crypto_backend::digest::Context::new(
94 &crypto_backend::digest::SHA1_FOR_LEGACY_USE_ONLY,
95 );
96 data.write(&mut hasher);
97 HashOutput::Digest(hasher.finish())
98 }
99 Self::Sha256 => {
100 let mut hasher =
101 crypto_backend::digest::Context::new(&crypto_backend::digest::SHA256);
102 data.write(&mut hasher);
103 HashOutput::Digest(hasher.finish())
104 }
105 }
106 }
107}
108
109#[non_exhaustive]
110pub enum HashOutput {
111 #[cfg(any(feature = "ring", feature = "aws-lc-rs"))]
112 Digest(crypto_backend::digest::Digest),
113}
114
115impl AsRef<[u8]> for HashOutput {
116 fn as_ref(&self) -> &[u8] {
117 match self {
118 #[cfg(any(feature = "ring", feature = "aws-lc-rs"))]
119 Self::Digest(output) => output.as_ref(),
120 }
121 }
122}
123
124#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
125#[repr(u8)]
126pub enum Algorithm {
127 RsaSha1,
128 #[default]
129 RsaSha256,
130 Ed25519Sha256,
131}
132
133pub(crate) const R_HASH_SHA1: u64 = 0x01;
134pub(crate) const R_HASH_SHA256: u64 = 0x02;