Skip to main content

mini_mail_auth/common/
crypto.rs

1use super::headers::{Writable, Writer};
2use crate::Result;
3use rsa::{pkcs1::DecodeRsaPrivateKey, Pkcs1v15Sign, RsaPrivateKey};
4use sha2::digest::Digest;
5use std::marker::PhantomData;
6
7// --- Traits ---
8
9pub trait SigningKey {
10    type Hasher: HashImpl;
11    fn sign(&self, input: impl Writable) -> Result<Vec<u8>>;
12    fn hash(&self, data: impl Writable) -> HashOutput {
13        let mut hasher = <Self::Hasher as HashImpl>::hasher();
14        data.write(&mut hasher);
15        hasher.complete()
16    }
17    fn algorithm(&self) -> Algorithm;
18}
19
20pub trait HashContext: Writer + Sized {
21    fn complete(self) -> HashOutput;
22}
23
24pub trait HashImpl {
25    type Context: HashContext;
26    fn hasher() -> Self::Context;
27}
28
29// --- Enums and Structs ---
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
32pub enum Algorithm {
33    #[default]
34    RsaSha256,
35}
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq)]
38#[repr(u64)]
39pub enum HashAlgorithm {
40    Sha256,
41}
42
43pub struct Sha256;
44
45#[non_exhaustive]
46pub enum HashOutput {
47    RustCryptoSha256(sha2::digest::Output<sha2::Sha256>),
48}
49
50// --- Implementations ---
51
52impl AsRef<[u8]> for HashOutput {
53    fn as_ref(&self) -> &[u8] {
54        match self {
55            Self::RustCryptoSha256(output) => output.as_ref(),
56        }
57    }
58}
59
60impl From<Algorithm> for HashAlgorithm {
61    fn from(_: Algorithm) -> Self {
62        HashAlgorithm::Sha256
63    }
64}
65
66// --- RSA Key ---
67
68#[derive(Debug)]
69pub struct RsaKey<T> {
70    inner: RsaPrivateKey,
71    padding: PhantomData<T>,
72}
73
74impl<T: HashImpl> RsaKey<T> {
75    pub fn from_pkcs1_pem(private_key_pem: &str) -> Result<Self> {
76        let inner = RsaPrivateKey::from_pkcs1_pem(private_key_pem)?;
77        Ok(RsaKey {
78            inner,
79            padding: PhantomData,
80        })
81    }
82}
83
84impl SigningKey for RsaKey<Sha256> {
85    type Hasher = Sha256;
86
87    fn sign(&self, input: impl Writable) -> Result<Vec<u8>> {
88        let hash = self.hash(input);
89        self.inner
90            .sign(
91                Pkcs1v15Sign::new::<<Self::Hasher as HashImpl>::Context>(),
92                hash.as_ref(),
93            )
94            .map_err(|e| e.into())
95    }
96
97    fn algorithm(&self) -> Algorithm {
98        Algorithm::RsaSha256
99    }
100}
101
102// --- SHA256 ---
103
104impl Writer for sha2::Sha256 {
105    fn write(&mut self, buf: &[u8]) {
106        self.update(buf);
107    }
108}
109
110impl HashImpl for Sha256 {
111    type Context = sha2::Sha256;
112    fn hasher() -> Self::Context {
113        <Self::Context as Digest>::new()
114    }
115}
116
117impl HashContext for sha2::Sha256 {
118    fn complete(self) -> HashOutput {
119        HashOutput::RustCryptoSha256(self.finalize())
120    }
121}