cryptoxide/
hmac.rs

1//! Implements the Hash Message Authentication Code (HMAC)
2//!
3//! # Examples
4//!
5//! HMAC-SHA256 using a 16 bytes key of a simple input data
6//!
7//! ```
8//! use cryptoxide::{hmac::Hmac, mac::Mac, sha2::Sha256};
9//!
10//! let input = b"data";
11//! let key = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
12//! let mut h = Hmac::new(Sha256::new(), &key);
13//! h.input(input);
14//! let mac = h.result();
15//! ```
16
17use core::iter::repeat;
18
19use crate::digest::Digest;
20use crate::mac::{Mac, MacResult};
21use alloc::vec::Vec;
22
23/// HMAC context parametrized by the hashing function
24pub struct Hmac<D> {
25    digest: D,
26    i_key: Vec<u8>,
27    o_key: Vec<u8>,
28    finished: bool,
29}
30
31fn derive_key(key: &mut [u8], mask: u8) {
32    for elem in key.iter_mut() {
33        *elem ^= mask;
34    }
35}
36
37// The key that Hmac processes must be the same as the block size of the underlying Digest. If the
38// provided key is smaller than that, we just pad it with zeros. If its larger, we hash it and then
39// pad it with zeros.
40fn expand_key<D: Digest>(digest: &mut D, key: &[u8]) -> Vec<u8> {
41    let bs = digest.block_size();
42    let mut expanded_key: Vec<u8> = repeat(0).take(bs).collect();
43
44    if key.len() <= bs {
45        expanded_key[0..key.len()].copy_from_slice(key);
46    } else {
47        let output_size = digest.output_bytes();
48        digest.input(key);
49        digest.result(&mut expanded_key[..output_size]);
50        digest.reset();
51    }
52    expanded_key
53}
54
55// Hmac uses two keys derived from the provided key - one by xoring every byte with 0x36 and another
56// with 0x5c.
57fn create_keys<D: Digest>(digest: &mut D, key: &[u8]) -> (Vec<u8>, Vec<u8>) {
58    let mut i_key = expand_key(digest, key);
59    let mut o_key = i_key.clone();
60    derive_key(&mut i_key, 0x36);
61    derive_key(&mut o_key, 0x5c);
62    (i_key, o_key)
63}
64
65impl<D: Digest> Hmac<D> {
66    /// Create a new Hmac instance.
67    ///
68    /// # Arguments
69    /// * digest - The Digest to use.
70    /// * key - The key to use.
71    ///
72    pub fn new(mut digest: D, key: &[u8]) -> Hmac<D> {
73        let (i_key, o_key) = create_keys(&mut digest, key);
74        digest.input(&i_key[..]);
75        Hmac {
76            digest: digest,
77            i_key: i_key,
78            o_key: o_key,
79            finished: false,
80        }
81    }
82}
83
84impl<D: Digest> Mac for Hmac<D> {
85    fn input(&mut self, data: &[u8]) {
86        assert!(!self.finished);
87        self.digest.input(data);
88    }
89
90    fn reset(&mut self) {
91        self.digest.reset();
92        self.digest.input(&self.i_key[..]);
93        self.finished = false;
94    }
95
96    fn result(&mut self) -> MacResult {
97        let output_size = self.digest.output_bytes();
98        let mut code: Vec<u8> = repeat(0).take(output_size).collect();
99
100        self.raw_result(&mut code);
101
102        MacResult::new_from_owned(code)
103    }
104
105    fn raw_result(&mut self, output: &mut [u8]) {
106        if !self.finished {
107            self.digest.result(output);
108
109            self.digest.reset();
110            self.digest.input(&self.o_key[..]);
111            self.digest.input(output);
112
113            self.finished = true;
114        }
115
116        self.digest.result(output);
117    }
118
119    fn output_bytes(&self) -> usize {
120        self.digest.output_bytes()
121    }
122}
123
124#[cfg(test)]
125mod test {
126    use crate::hmac::Hmac;
127    use crate::mac::Mac;
128
129    #[cfg(feature = "blake2")]
130    use crate::blake2s::Blake2s;
131
132    #[cfg(feature = "sha2")]
133    use crate::sha2::Sha256;
134
135    struct Test {
136        key: &'static [u8],
137        data: &'static [u8],
138        expected: &'static [u8],
139    }
140
141    // Test vectors from: http://tools.ietf.org/html/rfc2104
142
143    fn tests() -> [Test; 3] {
144        [
145            Test {
146                key: &[
147                    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
148                ],
149                data: b"Hi There",
150                expected: &[
151                    0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf,
152                    0x0b, 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9,
153                    0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7,
154                ],
155            },
156            Test {
157                key: b"Jefe",
158                data: b"what do ya want for nothing?",
159                expected: &[
160                    0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e, 0x6a, 0x04, 0x24, 0x26, 0x08,
161                    0x95, 0x75, 0xc7, 0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83, 0x9d, 0xec,
162                    0x58, 0xb9, 0x64, 0xec, 0x38, 0x43,
163                ],
164            },
165            Test {
166                key: &[
167                    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
168                    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
169                ],
170                data: &[
171                    0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
172                    0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
173                    0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
174                    0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
175                ],
176                expected: &[
177                    0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46, 0x85, 0x4d, 0xb8, 0xeb, 0xd0,
178                    0x91, 0x81, 0xa7, 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8, 0xc1, 0x22, 0xd9, 0x63,
179                    0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe,
180                ],
181            },
182        ]
183    }
184
185    #[cfg(feature = "sha2")]
186    #[test]
187    fn hmac_sha256() {
188        for t in tests().iter() {
189            let mut h = Hmac::new(Sha256::new(), &t.key[..]);
190            let mut output = [0u8; 32];
191            h.input(&t.data[..]);
192            h.raw_result(&mut output);
193            assert_eq!(&output[..], &t.expected[..]);
194        }
195    }
196
197    #[cfg(feature = "blake2")]
198    #[test]
199    fn hmac_blake2s() {
200        let key = [
201            0x05, 0x5a, 0x62, 0xc4, 0x6f, 0x56, 0x94, 0x0c, 0xb0, 0x00, 0xd5, 0x3d, 0x84, 0x2c,
202            0x0a, 0xbd, 0xba, 0x1c, 0x43, 0xb0, 0xa3, 0x0c, 0xa4, 0xc3, 0x8a, 0xd0, 0x84, 0xc2,
203            0x1c, 0x34, 0x99, 0x86,
204        ];
205        let data = b"hello";
206        let expected = [
207            0x9a, 0x4f, 0xe7, 0x47, 0xf8, 0x28, 0xa6, 0x15, 0x5e, 0xf8, 0x2b, 0xb2, 0x8c, 0xdb,
208            0x8f, 0x41, 0xfa, 0xd5, 0x29, 0xe0, 0x15, 0xf9, 0x25, 0x98, 0x74, 0x24, 0x70, 0x37,
209            0xaf, 0x28, 0xa6, 0x7a,
210        ];
211
212        let mut h = Hmac::new(Blake2s::new(32), &key[..]);
213        let mut output = [0u8; 32];
214        h.input(&data[..]);
215        h.raw_result(&mut output);
216        assert_eq!(&output[..], &expected[..]);
217    }
218}