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