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