1diff --git a/src/hmac.rs b/src/hmac.rs 2new file mode 100644 3index 0000000..601ae01 4--- /dev/null 5+++ b/src/hmac.rs 6@@ -0,0 +1,68 @@ 7+use crate::cvt_p; 8+use crate::error::ErrorStack; 9+use crate::md::MdRef; 10+use foreign_types::ForeignTypeRef; 11+use openssl_macros::corresponds; 12+use libc::{c_void, c_uint}; 13+use std::convert::TryFrom; 14+ 15+/// Computes the HMAC as a one-shot operation. 16+/// 17+/// Calculates the HMAC of data, using the given |key| 18+/// and hash function |md|, and returns the result re-using the space from 19+/// buffer |out|. On entry, |out| must contain at least |EVP_MD_size| bytes 20+/// of space. The actual length of the result is used to resize the returned 21+/// slice. An output size of |EVP_MAX_MD_SIZE| will always be large enough. 22+/// It returns a resized |out| or ErrorStack on error. 23+#[corresponds(HMAC)] 24+#[inline] 25+pub fn hmac<'a>( 26+ md: &MdRef, 27+ key: &[u8], 28+ data: &[u8], 29+ out: &'a mut [u8] 30+) -> Result<&'a [u8], ErrorStack> { 31+ let mut out_len = c_uint::try_from(out.len()).unwrap(); 32+ unsafe { 33+ cvt_p(ffi::HMAC( 34+ md.as_ptr(), 35+ key.as_ptr() as *const c_void, 36+ key.len(), 37+ data.as_ptr(), 38+ data.len(), 39+ out.as_mut_ptr(), 40+ &mut out_len 41+ ))?; 42+ } 43+ Ok(&out[..out_len as usize]) 44+} 45+ 46+#[cfg(test)] 47+mod tests { 48+ use super::*; 49+ use crate::md::Md; 50+ use crate::memcmp; 51+ 52+ const SHA_256_DIGEST_SIZE:usize = 32; 53+ 54+ #[test] 55+ fn hmac_sha256_test() { 56+ let expected_hmac = [0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0xb, 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x0, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7]; 57+ let mut out: [u8; SHA_256_DIGEST_SIZE] = [0; SHA_256_DIGEST_SIZE]; 58+ let key:[u8; 20] = [0x0b; 20]; 59+ let data = b"Hi There"; 60+ let hmac_result = hmac(Md::sha256(), &key, data, &mut out).expect("Couldn't calculate sha256 hmac"); 61+ expect!(memcmp::eq(&hmac_result, &expected_hmac)); 62+ } 63+ 64+ #[test] 65+ fn hmac_sha256_test_big_buffer() { 66+ let expected_hmac = [0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0xb, 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x0, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7]; 67+ let mut out: [u8; 100] = [0; 100]; 68+ let key:[u8;20] = [0x0b; 20]; 69+ let data = b"Hi There"; 70+ let hmac_result = hmac(Md::sha256(), &key, data, &mut out).expect("Couldn't calculate sha256 hmac"); 71+ expect_eq!(hmac_result.len(), SHA_256_DIGEST_SIZE); 72+ expect!(memcmp::eq(&hmac_result, &expected_hmac)); 73+ } 74+} 75