bitcoin_hashes/
hmac.rs

1// SPDX-License-Identifier: CC0-1.0
2
3// This module is largely copied from the rust-crypto ripemd.rs file;
4// while rust-crypto is licensed under Apache, that file specifically
5// was written entirely by Andrew Poelstra, who is re-licensing its
6// contents here as CC0.
7
8//! Hash-based Message Authentication Code (HMAC).
9//!
10
11use core::{borrow, fmt, ops, str};
12
13#[cfg(feature = "serde")]
14use serde::{Deserialize, Deserializer, Serialize, Serializer};
15
16use crate::{FromSliceError, Hash, HashEngine};
17
18/// A hash computed from a RFC 2104 HMAC. Parameterized by the underlying hash function.
19#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
20#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
21#[cfg_attr(feature = "schemars", schemars(transparent))]
22#[repr(transparent)]
23pub struct Hmac<T: Hash>(T);
24
25impl<T: Hash + str::FromStr> str::FromStr for Hmac<T> {
26    type Err = <T as str::FromStr>::Err;
27    fn from_str(s: &str) -> Result<Self, Self::Err> { Ok(Hmac(str::FromStr::from_str(s)?)) }
28}
29
30/// Pair of underlying hash midstates which represent the current state of an `HmacEngine`.
31pub struct HmacMidState<T: Hash> {
32    /// Midstate of the inner hash engine
33    pub inner: <T::Engine as HashEngine>::MidState,
34    /// Midstate of the outer hash engine
35    pub outer: <T::Engine as HashEngine>::MidState,
36}
37
38/// Pair of underyling hash engines, used for the inner and outer hash of HMAC.
39#[derive(Clone)]
40pub struct HmacEngine<T: Hash> {
41    iengine: T::Engine,
42    oengine: T::Engine,
43}
44
45impl<T: Hash> Default for HmacEngine<T> {
46    fn default() -> Self { HmacEngine::new(&[]) }
47}
48
49impl<T: Hash> HmacEngine<T> {
50    /// Constructs a new keyed HMAC from `key`.
51    ///
52    /// We only support underlying hashes whose block sizes are ≤ 128 bytes.
53    ///
54    /// # Panics
55    ///
56    /// Larger hashes will result in a panic.
57    pub fn new(key: &[u8]) -> HmacEngine<T> {
58        debug_assert!(T::Engine::BLOCK_SIZE <= 128);
59
60        let mut ipad = [0x36u8; 128];
61        let mut opad = [0x5cu8; 128];
62        let mut ret = HmacEngine { iengine: <T as Hash>::engine(), oengine: <T as Hash>::engine() };
63
64        if key.len() > T::Engine::BLOCK_SIZE {
65            let hash = <T as Hash>::hash(key);
66            for (b_i, b_h) in ipad.iter_mut().zip(&hash[..]) {
67                *b_i ^= *b_h;
68            }
69            for (b_o, b_h) in opad.iter_mut().zip(&hash[..]) {
70                *b_o ^= *b_h;
71            }
72        } else {
73            for (b_i, b_h) in ipad.iter_mut().zip(key) {
74                *b_i ^= *b_h;
75            }
76            for (b_o, b_h) in opad.iter_mut().zip(key) {
77                *b_o ^= *b_h;
78            }
79        };
80
81        HashEngine::input(&mut ret.iengine, &ipad[..T::Engine::BLOCK_SIZE]);
82        HashEngine::input(&mut ret.oengine, &opad[..T::Engine::BLOCK_SIZE]);
83        ret
84    }
85
86    /// A special constructor giving direct access to the underlying "inner" and "outer" engines.
87    pub fn from_inner_engines(iengine: T::Engine, oengine: T::Engine) -> HmacEngine<T> {
88        HmacEngine { iengine, oengine }
89    }
90}
91
92impl<T: Hash> HashEngine for HmacEngine<T> {
93    type MidState = HmacMidState<T>;
94
95    fn midstate(&self) -> Self::MidState {
96        HmacMidState { inner: self.iengine.midstate(), outer: self.oengine.midstate() }
97    }
98
99    const BLOCK_SIZE: usize = T::Engine::BLOCK_SIZE;
100
101    fn n_bytes_hashed(&self) -> usize { self.iengine.n_bytes_hashed() }
102
103    fn input(&mut self, buf: &[u8]) { self.iengine.input(buf) }
104}
105
106impl<T: Hash> fmt::Debug for Hmac<T> {
107    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&self.0, f) }
108}
109
110impl<T: Hash> fmt::Display for Hmac<T> {
111    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
112}
113
114impl<T: Hash> fmt::LowerHex for Hmac<T> {
115    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(&self.0, f) }
116}
117
118impl<T: Hash> ops::Index<usize> for Hmac<T> {
119    type Output = u8;
120    fn index(&self, index: usize) -> &u8 { &self.0[index] }
121}
122
123impl<T: Hash> ops::Index<ops::Range<usize>> for Hmac<T> {
124    type Output = [u8];
125    fn index(&self, index: ops::Range<usize>) -> &[u8] { &self.0[index] }
126}
127
128impl<T: Hash> ops::Index<ops::RangeFrom<usize>> for Hmac<T> {
129    type Output = [u8];
130    fn index(&self, index: ops::RangeFrom<usize>) -> &[u8] { &self.0[index] }
131}
132
133impl<T: Hash> ops::Index<ops::RangeTo<usize>> for Hmac<T> {
134    type Output = [u8];
135    fn index(&self, index: ops::RangeTo<usize>) -> &[u8] { &self.0[index] }
136}
137
138impl<T: Hash> ops::Index<ops::RangeFull> for Hmac<T> {
139    type Output = [u8];
140    fn index(&self, index: ops::RangeFull) -> &[u8] { &self.0[index] }
141}
142
143impl<T: Hash> borrow::Borrow<[u8]> for Hmac<T> {
144    fn borrow(&self) -> &[u8] { &self[..] }
145}
146
147impl<T: Hash> Hash for Hmac<T> {
148    type Engine = HmacEngine<T>;
149    type Bytes = T::Bytes;
150
151    fn from_engine(mut e: HmacEngine<T>) -> Hmac<T> {
152        let ihash = T::from_engine(e.iengine);
153        e.oengine.input(&ihash[..]);
154        let ohash = T::from_engine(e.oengine);
155        Hmac(ohash)
156    }
157
158    const LEN: usize = T::LEN;
159
160    fn from_slice(sl: &[u8]) -> Result<Hmac<T>, FromSliceError> { T::from_slice(sl).map(Hmac) }
161
162    fn to_byte_array(self) -> Self::Bytes { self.0.to_byte_array() }
163
164    fn as_byte_array(&self) -> &Self::Bytes { self.0.as_byte_array() }
165
166    fn from_byte_array(bytes: T::Bytes) -> Self { Hmac(T::from_byte_array(bytes)) }
167
168    fn all_zeros() -> Self {
169        let zeros = T::all_zeros();
170        Hmac(zeros)
171    }
172}
173
174#[cfg(feature = "serde")]
175impl<T: Hash + Serialize> Serialize for Hmac<T> {
176    fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
177        Serialize::serialize(&self.0, s)
178    }
179}
180
181#[cfg(feature = "serde")]
182impl<'de, T: Hash + Deserialize<'de>> Deserialize<'de> for Hmac<T> {
183    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Hmac<T>, D::Error> {
184        let bytes = Deserialize::deserialize(d)?;
185        Ok(Hmac(bytes))
186    }
187}
188
189#[cfg(test)]
190mod tests {
191    #[test]
192    #[cfg(feature = "alloc")]
193    fn test() {
194        use crate::{sha256, Hash, HashEngine, Hmac, HmacEngine};
195
196        #[derive(Clone)]
197        struct Test {
198            key: Vec<u8>,
199            input: Vec<u8>,
200            output: Vec<u8>,
201        }
202
203        #[rustfmt::skip]
204        let tests = vec![
205            // Test vectors copied from libsecp256k1
206            // Sadly the RFC2104 test vectors all use MD5 as their underlying hash function,
207            // which of course this library does not support.
208            Test {
209                key: vec![ 0x0b; 20],
210                input: vec![0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65],
211                output: vec![
212                    0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53,
213                    0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0x0b, 0xf1, 0x2b,
214                    0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7,
215                    0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7,
216                ],
217            },
218            Test {
219                key: vec![ 0x4a, 0x65, 0x66, 0x65 ],
220                input: vec![
221                    0x77, 0x68, 0x61, 0x74, 0x20, 0x64, 0x6f, 0x20,
222                    0x79, 0x61, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x20,
223                    0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x68,
224                    0x69, 0x6e, 0x67, 0x3f,
225                ],
226                output: vec![
227                    0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e,
228                    0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7,
229                    0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83,
230                    0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43,
231                ],
232            },
233            Test {
234                key: vec![ 0xaa; 20 ],
235                input: vec![ 0xdd; 50 ],
236                output: vec![
237                    0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46,
238                    0x85, 0x4d, 0xb8, 0xeb, 0xd0, 0x91, 0x81, 0xa7,
239                    0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8, 0xc1, 0x22,
240                    0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe,
241                ],
242            },
243            Test {
244                key: vec![
245                    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
246                    0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
247                    0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
248                    0x19
249                ],
250                input: vec![ 0xcd; 50 ],
251                output: vec![
252                    0x82, 0x55, 0x8a, 0x38, 0x9a, 0x44, 0x3c, 0x0e,
253                    0xa4, 0xcc, 0x81, 0x98, 0x99, 0xf2, 0x08, 0x3a,
254                    0x85, 0xf0, 0xfa, 0xa3, 0xe5, 0x78, 0xf8, 0x07,
255                    0x7a, 0x2e, 0x3f, 0xf4, 0x67, 0x29, 0x66, 0x5b,
256                ],
257            },
258            Test {
259                key: vec! [ 0xaa; 131 ],
260                input: vec![
261                    0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x69,
262                    0x6e, 0x67, 0x20, 0x4c, 0x61, 0x72, 0x67, 0x65,
263                    0x72, 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x42,
264                    0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x53, 0x69, 0x7a,
265                    0x65, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x2d, 0x20,
266                    0x48, 0x61, 0x73, 0x68, 0x20, 0x4b, 0x65, 0x79,
267                    0x20, 0x46, 0x69, 0x72, 0x73, 0x74,
268                ],
269                output: vec![
270                    0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f,
271                    0x0d, 0x8a, 0x26, 0xaa, 0xcb, 0xf5, 0xb7, 0x7f,
272                    0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14,
273                    0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54,
274                ],
275            },
276            Test {
277                key: vec! [ 0xaa; 131 ],
278                input: vec![
279                    0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
280                    0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x75,
281                    0x73, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x6c,
282                    0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, 0x68,
283                    0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
284                    0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x6b, 0x65,
285                    0x79, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x20,
286                    0x6c, 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74,
287                    0x68, 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63,
288                    0x6b, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x64,
289                    0x61, 0x74, 0x61, 0x2e, 0x20, 0x54, 0x68, 0x65,
290                    0x20, 0x6b, 0x65, 0x79, 0x20, 0x6e, 0x65, 0x65,
291                    0x64, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65,
292                    0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x64, 0x20,
293                    0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x62,
294                    0x65, 0x69, 0x6e, 0x67, 0x20, 0x75, 0x73, 0x65,
295                    0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65,
296                    0x20, 0x48, 0x4d, 0x41, 0x43, 0x20, 0x61, 0x6c,
297                    0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x2e,
298                ],
299                output: vec![
300                    0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb,
301                    0x27, 0x63, 0x5f, 0xbc, 0xd5, 0xb0, 0xe9, 0x44,
302                    0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93,
303                    0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2,
304                ],
305            },
306        ];
307
308        for test in tests {
309            let mut engine = HmacEngine::<sha256::Hash>::new(&test.key);
310            engine.input(&test.input);
311            let hash = Hmac::<sha256::Hash>::from_engine(engine);
312            assert_eq!(&hash[..], &test.output[..]);
313            assert_eq!(hash.as_byte_array(), test.output.as_slice());
314        }
315    }
316
317    #[cfg(feature = "serde")]
318    #[test]
319    fn hmac_sha512_serde() {
320        use serde_test::{assert_tokens, Configure, Token};
321
322        use crate::{sha512, Hash, Hmac};
323
324        #[rustfmt::skip]
325        static HASH_BYTES: [u8; 64] = [
326            0x8b, 0x41, 0xe1, 0xb7, 0x8a, 0xd1, 0x15, 0x21,
327            0x11, 0x3c, 0x52, 0xff, 0x18, 0x2a, 0x1b, 0x8e,
328            0x0a, 0x19, 0x57, 0x54, 0xaa, 0x52, 0x7f, 0xcd,
329            0x00, 0xa4, 0x11, 0x62, 0x0b, 0x46, 0xf2, 0x0f,
330            0xff, 0xfb, 0x80, 0x88, 0xcc, 0xf8, 0x54, 0x97,
331            0x12, 0x1a, 0xd4, 0x49, 0x9e, 0x08, 0x45, 0xb8,
332            0x76, 0xf6, 0xdd, 0x66, 0x40, 0x08, 0x8a, 0x2f,
333            0x0b, 0x2d, 0x8a, 0x60, 0x0b, 0xdf, 0x4c, 0x0c,
334        ];
335
336        let hash = Hmac::<sha512::Hash>::from_slice(&HASH_BYTES).expect("right number of bytes");
337        assert_tokens(&hash.compact(), &[Token::BorrowedBytes(&HASH_BYTES[..])]);
338        assert_tokens(
339            &hash.readable(),
340            &[Token::Str(
341                "8b41e1b78ad11521113c52ff182a1b8e0a195754aa527fcd00a411620b46f20f\
342                 fffb8088ccf85497121ad4499e0845b876f6dd6640088a2f0b2d8a600bdf4c0c",
343            )],
344        );
345    }
346}
347
348#[cfg(bench)]
349mod benches {
350    use test::Bencher;
351
352    use crate::{sha256, Hash, HashEngine, Hmac};
353
354    #[bench]
355    pub fn hmac_sha256_10(bh: &mut Bencher) {
356        let mut engine = Hmac::<sha256::Hash>::engine();
357        let bytes = [1u8; 10];
358        bh.iter(|| {
359            engine.input(&bytes);
360        });
361        bh.bytes = bytes.len() as u64;
362    }
363
364    #[bench]
365    pub fn hmac_sha256_1k(bh: &mut Bencher) {
366        let mut engine = Hmac::<sha256::Hash>::engine();
367        let bytes = [1u8; 1024];
368        bh.iter(|| {
369            engine.input(&bytes);
370        });
371        bh.bytes = bytes.len() as u64;
372    }
373
374    #[bench]
375    pub fn hmac_sha256_64k(bh: &mut Bencher) {
376        let mut engine = Hmac::<sha256::Hash>::engine();
377        let bytes = [1u8; 65536];
378        bh.iter(|| {
379            engine.input(&bytes);
380        });
381        bh.bytes = bytes.len() as u64;
382    }
383}