diff options
| author | Steven Fackler <[email protected]> | 2016-08-11 21:01:27 -0700 |
|---|---|---|
| committer | Steven Fackler <[email protected]> | 2016-08-11 21:01:27 -0700 |
| commit | 652326003cefe215dbfc838051e6114515cc5190 (patch) | |
| tree | 22dc99a726321cd8228004c34c40ca4a0648c594 /openssl/src/crypto/hmac.rs | |
| parent | Merge branch 'release-v0.7.14' into release (diff) | |
| parent | Release openssl-sys v0.7.15, openssl v0.8.0 (diff) | |
| download | rust-openssl-openssl-v0.8.0.tar.xz rust-openssl-openssl-v0.8.0.zip | |
Merge branch 'release-v0.7.15-sys-v0.8.0' into releaseopenssl-v0.8.0openssl-sys-v0.7.15
Diffstat (limited to 'openssl/src/crypto/hmac.rs')
| -rw-r--r-- | openssl/src/crypto/hmac.rs | 162 |
1 files changed, 78 insertions, 84 deletions
diff --git a/openssl/src/crypto/hmac.rs b/openssl/src/crypto/hmac.rs index 143c7b75..857be339 100644 --- a/openssl/src/crypto/hmac.rs +++ b/openssl/src/crypto/hmac.rs @@ -14,13 +14,15 @@ // use libc::{c_int, c_uint}; -use std::iter::repeat; use std::io; use std::io::prelude::*; +use std::cmp; +use ffi; +use HashTypeInternals; use crypto::hash::Type; -use ffi; -use ffi_extras; +use error::ErrorStack; +use c_helpers; #[derive(PartialEq, Copy, Clone)] enum State { @@ -33,6 +35,8 @@ use self::State::*; /// Provides HMAC computation. /// +/// Requires the `hmac` feature. +/// /// # Examples /// /// Calculate a HMAC in one go. @@ -43,34 +47,32 @@ use self::State::*; /// let key = b"Jefe"; /// let data = b"what do ya want for nothing?"; /// let spec = b"\x75\x0c\x78\x3e\x6a\xb0\xb5\x03\xea\xa8\x6e\x31\x0a\x5d\xb7\x38"; -/// let res = hmac(Type::MD5, key, data); +/// let res = hmac(Type::MD5, key, data).unwrap(); /// assert_eq!(res, spec); /// ``` /// /// Use the `Write` trait to supply the input in chunks. /// /// ``` -/// use std::io::prelude::*; /// use openssl::crypto::hash::Type; /// use openssl::crypto::hmac::HMAC; /// let key = b"Jefe"; /// let data: &[&[u8]] = &[b"what do ya ", b"want for nothing?"]; /// let spec = b"\x75\x0c\x78\x3e\x6a\xb0\xb5\x03\xea\xa8\x6e\x31\x0a\x5d\xb7\x38"; -/// let mut h = HMAC::new(Type::MD5, &*key); -/// h.write_all(data[0]); -/// h.write_all(data[1]); -/// let res = h.finish(); +/// let mut h = HMAC::new(Type::MD5, &*key).unwrap(); +/// h.update(data[0]).unwrap(); +/// h.update(data[1]).unwrap(); +/// let res = h.finish().unwrap(); /// assert_eq!(res, spec); /// ``` pub struct HMAC { ctx: ffi::HMAC_CTX, - type_: Type, state: State, } impl HMAC { /// Creates a new `HMAC` with the specified hash type using the `key`. - pub fn new(ty: Type, key: &[u8]) -> HMAC { + pub fn new(ty: Type, key: &[u8]) -> Result<HMAC, ErrorStack> { ffi::init(); let ctx = unsafe { @@ -82,89 +84,81 @@ impl HMAC { let mut h = HMAC { ctx: ctx, - type_: ty, state: Finalized, }; - h.init_once(md, key); - h + try!(h.init_once(md, key)); + Ok(h) } - #[inline] - fn init_once(&mut self, md: *const ffi::EVP_MD, key: &[u8]) { + fn init_once(&mut self, md: *const ffi::EVP_MD, key: &[u8]) -> Result<(), ErrorStack> { unsafe { - let r = ffi_extras::HMAC_Init_ex(&mut self.ctx, - key.as_ptr(), - key.len() as c_int, - md, - 0 as *const _); - assert_eq!(r, 1); + try_ssl!(c_helpers::rust_HMAC_Init_ex(&mut self.ctx, + key.as_ptr() as *const _, + key.len() as c_int, + md, + 0 as *mut _)); } self.state = Reset; + Ok(()) } - #[inline] - fn init(&mut self) { + fn init(&mut self) -> Result<(), ErrorStack> { match self.state { - Reset => return, + Reset => return Ok(()), Updated => { - self.finalize(); + try!(self.finish()); } Finalized => (), } // If the key and/or md is not supplied it's reused from the last time // avoiding redundant initializations unsafe { - let r = ffi_extras::HMAC_Init_ex(&mut self.ctx, - 0 as *const _, - 0, - 0 as *const _, - 0 as *const _); - assert_eq!(r, 1); + try_ssl!(c_helpers::rust_HMAC_Init_ex(&mut self.ctx, + 0 as *const _, + 0, + 0 as *const _, + 0 as *mut _)); } self.state = Reset; + Ok(()) } - #[inline] - fn update(&mut self, data: &[u8]) { + pub fn update(&mut self, mut data: &[u8]) -> Result<(), ErrorStack> { if self.state == Finalized { - self.init(); + try!(self.init()); } - unsafe { - let r = ffi_extras::HMAC_Update(&mut self.ctx, data.as_ptr(), data.len() as c_uint); - assert_eq!(r, 1); + while !data.is_empty() { + let len = cmp::min(data.len(), c_uint::max_value() as usize); + unsafe { + try_ssl!(c_helpers::rust_HMAC_Update(&mut self.ctx, data.as_ptr(), len as c_uint)); + } + data = &data[len..]; } self.state = Updated; + Ok(()) } - #[inline] - fn finalize(&mut self) -> Vec<u8> { + /// Returns the hash of the data written since creation or + /// the last `finish` and resets the hasher. + pub fn finish(&mut self) -> Result<Vec<u8>, ErrorStack> { if self.state == Finalized { - self.init(); + try!(self.init()); } - let md_len = self.type_.md_len(); - let mut res: Vec<u8> = repeat(0).take(md_len).collect(); unsafe { - let mut len = 0; - let r = ffi_extras::HMAC_Final(&mut self.ctx, res.as_mut_ptr(), &mut len); + let mut len = ffi::EVP_MAX_MD_SIZE; + let mut res = vec![0; len as usize]; + try_ssl!(c_helpers::rust_HMAC_Final(&mut self.ctx, res.as_mut_ptr(), &mut len)); + res.truncate(len as usize); self.state = Finalized; - assert_eq!(len as usize, md_len); - assert_eq!(r, 1); + Ok(res) } - res - } - - /// Returns the hash of the data written since creation or - /// the last `finish` and resets the hasher. - #[inline] - pub fn finish(&mut self) -> Vec<u8> { - self.finalize() } } impl Write for HMAC { #[inline] fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - self.update(buf); + try!(self.update(buf)); Ok(buf.len()) } @@ -173,17 +167,18 @@ impl Write for HMAC { } } +#[cfg(feature = "hmac_clone")] impl Clone for HMAC { + /// Requires the `hmac_clone` feature. fn clone(&self) -> HMAC { let mut ctx: ffi::HMAC_CTX; unsafe { ctx = ::std::mem::uninitialized(); - let r = ffi_extras::HMAC_CTX_copy(&mut ctx, &self.ctx); + let r = ffi::HMAC_CTX_copy(&mut ctx, &self.ctx); assert_eq!(r, 1); } HMAC { ctx: ctx, - type_: self.type_, state: self.state, } } @@ -193,9 +188,7 @@ impl Drop for HMAC { fn drop(&mut self) { unsafe { if self.state != Finalized { - let mut buf: Vec<u8> = repeat(0).take(self.type_.md_len()).collect(); - let mut len = 0; - ffi_extras::HMAC_Final(&mut self.ctx, buf.as_mut_ptr(), &mut len); + drop(self.finish()); } ffi::HMAC_CTX_cleanup(&mut self.ctx); } @@ -203,9 +196,9 @@ impl Drop for HMAC { } /// Computes the HMAC of the `data` with the hash `t` and `key`. -pub fn hmac(t: Type, key: &[u8], data: &[u8]) -> Vec<u8> { - let mut h = HMAC::new(t, key); - let _ = h.write_all(data); +pub fn hmac(t: Type, key: &[u8], data: &[u8]) -> Result<Vec<u8>, ErrorStack> { + let mut h = try!(HMAC::new(t, key)); + try!(h.update(data)); h.finish() } @@ -220,14 +213,14 @@ mod tests { fn test_hmac(ty: Type, tests: &[(Vec<u8>, Vec<u8>, Vec<u8>)]) { for &(ref key, ref data, ref res) in tests.iter() { - assert_eq!(hmac(ty, &**key, &**data), *res); + assert_eq!(hmac(ty, &**key, &**data).unwrap(), *res); } } fn test_hmac_recycle(h: &mut HMAC, test: &(Vec<u8>, Vec<u8>, Vec<u8>)) { let &(_, ref data, ref res) = test; - let _ = h.write_all(&**data); - assert_eq!(h.finish(), *res); + h.write_all(&**data).unwrap(); + assert_eq!(h.finish().unwrap(), *res); } #[test] @@ -273,7 +266,7 @@ mod tests { .to_vec(), "6f630fad67cda0ee1fb1f562db3aa53e".from_hex().unwrap())]; - let mut h = HMAC::new(MD5, &*tests[0].0); + let mut h = HMAC::new(MD5, &*tests[0].0).unwrap(); for i in 0..100usize { let test = &tests[i % 2]; test_hmac_recycle(&mut h, test); @@ -287,15 +280,16 @@ mod tests { b"Test Using Larger Than Block-Size Key - Hash Key First".to_vec(), "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd".from_hex().unwrap()); - let mut h = HMAC::new(Type::MD5, &*test.0); - let _ = h.write_all(&*test.1); - let _ = h.finish(); - let res = h.finish(); - let null = hmac(Type::MD5, &*test.0, &[]); + let mut h = HMAC::new(Type::MD5, &*test.0).unwrap(); + h.write_all(&*test.1).unwrap(); + h.finish().unwrap(); + let res = h.finish().unwrap(); + let null = hmac(Type::MD5, &*test.0, &[]).unwrap(); assert_eq!(res, null); } #[test] + #[cfg(feature = "hmac_clone")] fn test_clone() { let tests: [(Vec<u8>, Vec<u8>, Vec<u8>); 2] = [(repeat(0xaa_u8).take(80).collect(), @@ -307,26 +301,26 @@ mod tests { .to_vec(), "6f630fad67cda0ee1fb1f562db3aa53e".from_hex().unwrap())]; let p = tests[0].0.len() / 2; - let h0 = HMAC::new(Type::MD5, &*tests[0].0); + let h0 = HMAC::new(Type::MD5, &*tests[0].0).unwrap(); println!("Clone a new hmac"); let mut h1 = h0.clone(); - let _ = h1.write_all(&tests[0].1[..p]); + h1.write_all(&tests[0].1[..p]).unwrap(); { println!("Clone an updated hmac"); let mut h2 = h1.clone(); - let _ = h2.write_all(&tests[0].1[p..]); - let res = h2.finish(); + h2.write_all(&tests[0].1[p..]).unwrap(); + let res = h2.finish().unwrap(); assert_eq!(res, tests[0].2); } - let _ = h1.write_all(&tests[0].1[p..]); - let res = h1.finish(); + h1.write_all(&tests[0].1[p..]).unwrap(); + let res = h1.finish().unwrap(); assert_eq!(res, tests[0].2); println!("Clone a finished hmac"); let mut h3 = h1.clone(); - let _ = h3.write_all(&*tests[1].1); - let res = h3.finish(); + h3.write_all(&*tests[1].1).unwrap(); + let res = h3.finish().unwrap(); assert_eq!(res, tests[1].2); } @@ -373,7 +367,7 @@ mod tests { .to_vec(), "e8e99d0f45237d786d6bbaa7965c7808bbff1a91".from_hex().unwrap())]; - let mut h = HMAC::new(SHA1, &*tests[0].0); + let mut h = HMAC::new(SHA1, &*tests[0].0).unwrap(); for i in 0..100usize { let test = &tests[i % 2]; test_hmac_recycle(&mut h, test); @@ -399,11 +393,11 @@ mod tests { .to_vec())]; for (&(ref key, ref data), res) in tests.iter().zip(results.iter()) { - assert_eq!(hmac(ty, &**key, &**data), *res); + assert_eq!(hmac(ty, &**key, &**data).unwrap(), *res); } // recycle test - let mut h = HMAC::new(ty, &*tests[5].0); + let mut h = HMAC::new(ty, &*tests[5].0).unwrap(); for i in 0..100usize { let test = &tests[4 + i % 2]; let tup = (test.0.clone(), test.1.clone(), results[4 + i % 2].clone()); |