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