1 //! Generic implementation of Hash-based Message Authentication Code (HMAC).
2 //!
3 //! To use it you'll need a cryptographic hash function implementation from
4 //! RustCrypto project. You can either import specific crate (e.g. `sha2`), or
5 //! meta-crate `crypto-hashes` which reexport all related crates.
6 //!
7 //! # Usage
8 //! Let us demonstrate how to use HMAC using SHA256 as an example.
9 //!
10 //! To get the authentication code:
11 //!
12 //! ```rust
13 //! extern crate hmac;
14 //! extern crate sha2;
15 //!
16 //! use sha2::Sha256;
17 //! use hmac::{Hmac, Mac};
18 //!
19 //! // Create alias for HMAC-SHA256
20 //! type HmacSha256 = Hmac<Sha256>;
21 //!
22 //! # fn main() {
23 //! // Create HMAC-SHA256 instance which implements `Mac` trait
24 //! let mut mac = HmacSha256::new_varkey(b"my secret and secure key")
25 //!     .expect("HMAC can take key of any size");
26 //! mac.input(b"input message");
27 //!
28 //! // `result` has type `MacResult` which is a thin wrapper around array of
29 //! // bytes for providing constant time equality check
30 //! let result = mac.result();
31 //! // To get underlying array use `code` method, but be carefull, since
32 //! // incorrect use of the code value may permit timing attacks which defeat
33 //! // the security provided by the `MacResult`
34 //! let code_bytes = result.code();
35 //! # }
36 //! ```
37 //!
38 //! To verify the message:
39 //!
40 //! ```rust
41 //! # extern crate hmac;
42 //! # extern crate sha2;
43 //! # use sha2::Sha256;
44 //! # use hmac::{Hmac, Mac};
45 //! # fn main() {
46 //! # type HmacSha256 = Hmac<Sha256>;
47 //! let mut mac = HmacSha256::new_varkey(b"my secret and secure key")
48 //!     .expect("HMAC can take key of any size");
49 //!
50 //! mac.input(b"input message");
51 //!
52 //! # let code_bytes = mac.clone().result().code();
53 //! // `verify` will return `Ok(())` if code is correct, `Err(MacError)` otherwise
54 //! mac.verify(&code_bytes).unwrap();
55 //! # }
56 //! ```
57 //!
58 //! # Block and input sizes
59 //! Usually it is assumed that block size is larger than output size, due to the
60 //! generic nature of the implementation this edge case must be handled as well
61 //! to remove potential panic scenario. This is done by truncating hash output
62 //! to the hash block size if needed.
63 #![no_std]
64 #![doc(html_logo_url =
65     "https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png")]
66 pub extern crate digest;
67 pub extern crate crypto_mac;
68 
69 pub use crypto_mac::Mac;
70 use crypto_mac::{InvalidKeyLength, MacResult};
71 use digest::{Input, BlockInput, FixedOutput, Reset};
72 use digest::generic_array::{ArrayLength, GenericArray};
73 use digest::generic_array::sequence::GenericSequence;
74 use core::cmp::min;
75 use core::fmt;
76 
77 const IPAD: u8 = 0x36;
78 const OPAD: u8 = 0x5C;
79 
80 /// The `Hmac` struct represents an HMAC using a given hash function `D`.
81 pub struct Hmac<D>
82     where D: Input + BlockInput + FixedOutput + Reset + Default + Clone,
83           D::BlockSize: ArrayLength<u8>
84 {
85     digest: D,
86     i_key_pad: GenericArray<u8, D::BlockSize>,
87     opad_digest: D,
88 }
89 
90 impl<D> Clone for Hmac<D>
91     where D: Input + BlockInput + FixedOutput + Reset + Default + Clone,
92           D::BlockSize: ArrayLength<u8>
93 {
clone(&self) -> Hmac<D>94     fn clone(&self) -> Hmac<D> {
95         Hmac {
96             digest: self.digest.clone(),
97             i_key_pad: self.i_key_pad.clone(),
98             opad_digest: self.opad_digest.clone(),
99         }
100     }
101 }
102 
103 impl<D> fmt::Debug for Hmac<D>
104     where D: Input + BlockInput + FixedOutput + Reset + Default + Clone + fmt::Debug,
105           D::BlockSize: ArrayLength<u8>
106 {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result107     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
108         f.debug_struct("Hmac")
109          .field("digest", &self.digest)
110          .field("i_key_pad", &self.i_key_pad)
111          .field("opad_digest", &self.opad_digest)
112          .finish()
113     }
114 }
115 
116 impl <D> Mac for Hmac<D>
117     where D: Input + BlockInput + FixedOutput + Reset + Default + Clone,
118           D::BlockSize: ArrayLength<u8>,
119           D::OutputSize: ArrayLength<u8>
120 {
121     type OutputSize = D::OutputSize;
122     type KeySize = D::BlockSize;
123 
new(key: &GenericArray<u8, Self::KeySize>) -> Self124     fn new(key: &GenericArray<u8, Self::KeySize>) -> Self {
125         Self::new_varkey(key.as_slice()).unwrap()
126     }
127 
128     #[inline]
new_varkey(key: &[u8]) -> Result<Self, InvalidKeyLength>129     fn new_varkey(key: &[u8]) -> Result<Self, InvalidKeyLength> {
130         let mut hmac = Self {
131             digest: Default::default(),
132             i_key_pad: GenericArray::generate(|_| IPAD),
133             opad_digest: Default::default(),
134         };
135 
136         let mut opad = GenericArray::<u8, D::BlockSize>::generate(|_| OPAD);
137         debug_assert!(hmac.i_key_pad.len() == opad.len());
138 
139         // The key that Hmac processes must be the same as the block size of the
140         // underlying Digest. If the provided key is smaller than that, we just
141         // pad it with zeros. If its larger, we hash it and then pad it with
142         // zeros.
143         if key.len() <= hmac.i_key_pad.len() {
144             for (k_idx, k_itm) in key.iter().enumerate() {
145                 hmac.i_key_pad[k_idx] ^= *k_itm;
146                 opad[k_idx] ^= *k_itm;
147             }
148         } else {
149             let mut digest = D::default();
150             digest.input(key);
151             let output = digest.fixed_result();
152             // `n` is calculated at compile time and will equal
153             // D::OutputSize. This is used to ensure panic-free code
154             let n = min(output.len(), hmac.i_key_pad.len());
155             for idx in 0..n {
156                 hmac.i_key_pad[idx] ^= output[idx];
157                 opad[idx] ^= output[idx];
158             }
159         }
160 
161         hmac.digest.input(&hmac.i_key_pad);
162         hmac.opad_digest.input(&opad);
163 
164         Ok(hmac)
165     }
166 
167     #[inline]
input(&mut self, data: &[u8])168     fn input(&mut self, data: &[u8]) {
169         self.digest.input(data);
170     }
171 
172     #[inline]
result(self) -> MacResult<D::OutputSize>173     fn result(self) -> MacResult<D::OutputSize> {
174         let mut opad_digest = self.opad_digest.clone();
175         let hash = self.digest.fixed_result();
176         opad_digest.input(&hash);
177         MacResult::new(opad_digest.fixed_result())
178     }
179 
180     #[inline]
reset(&mut self)181     fn reset(&mut self) {
182         self.digest.reset();
183         self.digest.input(&self.i_key_pad);
184     }
185 }
186