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