common_crypto/
hmac.rs

1use std::ffi::c_void;
2
3#[repr(u32)]
4enum Algorithm {
5    SHA1,
6    MD5,
7    SHA256,
8    SHA384,
9    SHA512,
10    SHA224,
11}
12
13#[repr(C)]
14struct Context {
15    ctx: [u32; 96],
16}
17
18impl Default for Context {
19    fn default() -> Self {
20        Self { ctx: [0u32; 96] }
21    }
22}
23
24extern "C" {
25    fn CCHmac(
26        algorithm: Algorithm,
27        key: *const c_void,
28        key_len: usize,
29        data: *const c_void,
30        data_len: usize,
31        out: *mut c_void,
32    );
33
34    fn CCHmacInit(ctx: *mut Context, algorithm: Algorithm, key: *const c_void, len: usize);
35
36    fn CCHmacUpdate(ctx: *mut Context, data: *const c_void, len: usize);
37
38    fn CCHmacFinal(ctx: *mut Context, output: *mut c_void);
39}
40
41pub struct HMAC;
42
43impl HMAC {
44    fn generate(algorithm: Algorithm, key: &[u8], data: &[u8], hash: &mut [u8]) {
45        unsafe {
46            CCHmac(
47                algorithm,
48                key.as_ptr() as *const c_void,
49                key.len(),
50                data.as_ptr() as *const c_void,
51                data.len(),
52                hash.as_mut_ptr() as *mut c_void,
53            )
54        }
55    }
56}
57
58macro_rules! implement_digest {
59    ($func:ident, $algorithm:ident, $len:expr) => {
60        impl HMAC {
61            pub fn $func(key: impl AsRef<[u8]>, data: impl AsRef<[u8]>) -> [u8; $len] {
62                let mut hash = [0u8; $len];
63
64                Self::generate(
65                    Algorithm::$algorithm,
66                    key.as_ref(),
67                    data.as_ref(),
68                    &mut hash,
69                );
70
71                hash
72            }
73        }
74
75        pub struct $algorithm {
76            context: Context,
77        }
78
79        impl $algorithm {
80            pub fn new(key: impl AsRef<[u8]>) -> Self {
81                let mut context = Context::default();
82
83                unsafe {
84                    CCHmacInit(
85                        &mut context,
86                        Algorithm::$algorithm,
87                        key.as_ref().as_ptr() as *const c_void,
88                        key.as_ref().len(),
89                    );
90                }
91
92                Self { context }
93            }
94
95            pub fn update(&mut self, data: impl AsRef<[u8]>) {
96                unsafe {
97                    CCHmacUpdate(
98                        &mut self.context,
99                        data.as_ref().as_ptr() as *const c_void,
100                        data.as_ref().len(),
101                    );
102                }
103            }
104
105            pub fn finish(mut self) -> [u8; $len] {
106                let mut output = [0u8; $len];
107
108                unsafe {
109                    CCHmacFinal(&mut self.context, output.as_mut_ptr() as *mut c_void);
110                }
111
112                output
113            }
114        }
115    };
116}
117
118implement_digest!(md5, MD5, 16);
119implement_digest!(sha1, SHA1, 20);
120implement_digest!(sha224, SHA224, 28);
121implement_digest!(sha256, SHA256, 32);
122implement_digest!(sha384, SHA384, 48);
123implement_digest!(sha512, SHA512, 64);