hashr/
hmac.rs

1use std::io::{Error, Read};
2
3use crate::hash::HashFn;
4
5pub struct HMAC<const B: usize, const L: usize, H: HashFn<B, L>, F: Fn() -> H> {
6    key_opad: [u8; B],
7    hash_state: H,
8    hash_new_fn: F,
9}
10
11impl<const B: usize, const L: usize, H: HashFn<B, L>, F: Fn() -> H> HMAC<B, L, H, F> {
12    pub fn new(hash_new_fn: F, key: &[u8]) -> Self {
13        let mut final_key = [0u8; B];
14        if key.len() > B {
15            let mut key_hasher = hash_new_fn();
16            key_hasher.update(key);
17            final_key[..L].copy_from_slice(&key_hasher.finalize());
18        } else {
19            final_key[..key.len()].copy_from_slice(key);
20        }
21
22        let mut key_ipad = [0x36; B];
23        let mut key_opad = [0x5c; B];
24        for i in 0..B {
25            key_ipad[i] ^= final_key[i];
26            key_opad[i] ^= final_key[i];
27        }
28
29        let mut sha1state = hash_new_fn();
30        sha1state.update(key_ipad.as_slice());
31        Self {
32            hash_state: sha1state,
33            key_opad,
34            hash_new_fn,
35        }
36    }
37}
38
39impl<const B: usize, const L: usize, H: HashFn<B, L>, F: Fn() -> H> HashFn<B, L>
40    for HMAC<B, L, H, F>
41{
42    fn update(&mut self, data: &[u8]) {
43        self.hash_state.update(data);
44    }
45
46    fn finalize(&mut self) -> [u8; L] {
47        let first_hash = self.hash_state.finalize();
48        let f = &self.hash_new_fn;
49        let mut second_sha1_state = f();
50        second_sha1_state.update(&self.key_opad);
51        second_sha1_state.update(&first_hash);
52        second_sha1_state.finalize()
53    }
54}
55
56pub fn digest_from_bytes<const B: usize, const L: usize, H: HashFn<B, L>, F: Fn() -> H>(
57    hash_new_fn: F,
58    data: &[u8],
59    key: &[u8],
60) -> [u8; L] {
61    let mut state = HMAC::new(hash_new_fn, key);
62    state.update(data);
63    state.finalize()
64}
65
66pub fn digest_from_reader<
67    const B: usize,
68    const L: usize,
69    H: HashFn<B, L>,
70    F: Fn() -> H,
71    R: Read,
72>(
73    hash_new_fn: F,
74    mut r: R,
75    key: &[u8],
76) -> Result<[u8; L], Error> {
77    let mut state = HMAC::new(hash_new_fn, key);
78    let mut buf = [0u8; 512];
79
80    loop {
81        let n = r.read(&mut buf)?;
82
83        if n == 0 {
84            break;
85        }
86
87        state.update(&buf[..n]);
88    }
89
90    Ok(state.finalize())
91}
92
93#[cfg(test)]
94mod tests {
95    use super::digest_from_bytes;
96    use crate::hex;
97    use crate::sha1::SHA1;
98
99    #[test]
100    fn test_hmac_sha1_rfc_test_vectors() {
101        struct TestCase {
102            key: Vec<u8>,
103            data: Vec<u8>,
104            expected_digest: Vec<u8>,
105        }
106        let tests_cases: Vec<TestCase> = vec![
107            TestCase {
108                key: hex::decode_hex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b").unwrap(),
109                data: Vec::from("Hi There"),
110                expected_digest: hex::decode_hex("b617318655057264e28bc0b6fb378c8ef146be00")
111                    .unwrap(),
112            },
113            TestCase {
114                key: Vec::from("Jefe"),
115                data: Vec::from("what do ya want for nothing?"),
116                expected_digest: hex::decode_hex("effcdf6ae5eb2fa2d27416d5f184df9c259a7c79")
117                    .unwrap(),
118            },
119            TestCase {
120                key: hex::decode_hex("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").unwrap(),
121                data: Vec::from([0xdd; 50]),
122                expected_digest: hex::decode_hex("125d7342b9ac11cd91a39af48aa17b4f63f175d3")
123                    .unwrap(),
124            },
125            TestCase {
126                key: hex::decode_hex("0102030405060708090a0b0c0d0e0f10111213141516171819").unwrap(),
127                data: Vec::from([0xcd; 50]),
128                expected_digest: hex::decode_hex("4c9007f4026250c6bc8414f9bf50c86c2d7235da")
129                    .unwrap(),
130            },
131            TestCase {
132                key: hex::decode_hex("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c").unwrap(),
133                data: Vec::from("Test With Truncation"),
134                expected_digest: hex::decode_hex("4c1a03424b55e07fe7f27be1d58bb9324a9a5a04")
135                    .unwrap(),
136            },
137            TestCase {
138                key: Vec::from([0xaa; 80]),
139                data: Vec::from("Test Using Larger Than Block-Size Key - Hash Key First"),
140                expected_digest: hex::decode_hex("aa4ae5e15272d00e95705637ce8a3b55ed402112")
141                    .unwrap(),
142            },
143            TestCase {
144                key: Vec::from([0xaa; 80]),
145                data: Vec::from(
146                    "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data",
147                ),
148                expected_digest: hex::decode_hex("e8e99d0f45237d786d6bbaa7965c7808bbff1a91")
149                    .unwrap(),
150            },
151        ];
152
153        for test_case in tests_cases {
154            let digest = digest_from_bytes(SHA1::new, test_case.data.as_slice(), &test_case.key);
155            assert!(digest.eq(test_case.expected_digest.as_slice()))
156        }
157    }
158}