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