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