Add new SHAKE128/256 EVP message digest functions in OpenSSL 1.1.1, fixes #1017.

This commit is contained in:
Sameer 2018-11-21 15:29:35 -05:00
parent e0e0a96cb3
commit 38a4dccceb
1 changed files with 88 additions and 2 deletions

View File

@ -84,6 +84,16 @@ impl MessageDigest {
unsafe { MessageDigest(ffi::EVP_sha3_512()) } unsafe { MessageDigest(ffi::EVP_sha3_512()) }
} }
#[cfg(ossl111)]
pub fn shake_128() -> MessageDigest {
unsafe { MessageDigest(ffi::EVP_shake128()) }
}
#[cfg(ossl111)]
pub fn shake_256() -> MessageDigest {
unsafe { MessageDigest(ffi::EVP_shake256()) }
}
pub fn ripemd160() -> MessageDigest { pub fn ripemd160() -> MessageDigest {
unsafe { MessageDigest(ffi::EVP_ripemd160()) } unsafe { MessageDigest(ffi::EVP_ripemd160()) }
} }
@ -139,11 +149,29 @@ use self::State::*;
/// assert_eq!(&*res, spec); /// assert_eq!(&*res, spec);
/// ``` /// ```
/// ///
/// Use an XOF hasher (OpenSSL 1.1.1+):
///
/// ```
/// #[cfg(ossl111)]
/// {
/// use openssl::hash::{hash_xof, MessageDigest};
///
/// let data = b"\x41\x6c\x6c\x20\x79\x6f\x75\x72\x20\x62\x61\x73\x65\x20\x61\x72\x65\x20\x62\x65\x6c\x6f\x6e\x67\x20\x74\x6f\x20\x75\x73";
/// let spec = b"\x49\xd0\x69\x7f\xf5\x08\x11\x1d\x8b\x84\xf1\x5e\x46\xda\xf1\x35";
/// let mut buf = vec![0; 16];
/// hash_xof(MessageDigest::shake_128(), data, buf.as_mut_slice()).unwrap();
/// assert_eq!(buf, spec);
/// }
/// ```
///
/// # Warning /// # Warning
/// ///
/// Don't actually use MD5 and SHA-1 hashes, they're not secure anymore. /// Don't actually use MD5 and SHA-1 hashes, they're not secure anymore.
/// ///
/// Don't ever hash passwords, use the functions in the `pkcs5` module or bcrypt/scrypt instead. /// Don't ever hash passwords, use the functions in the `pkcs5` module or bcrypt/scrypt instead.
///
/// For extendable output functions (XOFs, i.e. SHAKE128/SHAKE256), you must use finish_xof instead
/// of finish and provide a buf to store the hash. The hash will be as long as the buf.
pub struct Hasher { pub struct Hasher {
ctx: *mut ffi::EVP_MD_CTX, ctx: *mut ffi::EVP_MD_CTX,
md: *const ffi::EVP_MD, md: *const ffi::EVP_MD,
@ -202,7 +230,7 @@ impl Hasher {
Ok(()) Ok(())
} }
/// Returns the hash of the data written and resets the hasher. /// Returns the hash of the data written and resets the non-XOF hasher.
pub fn finish(&mut self) -> Result<DigestBytes, ErrorStack> { pub fn finish(&mut self) -> Result<DigestBytes, ErrorStack> {
if self.state == Finalized { if self.state == Finalized {
self.init()?; self.init()?;
@ -222,6 +250,24 @@ impl Hasher {
}) })
} }
} }
/// Writes the hash of the data into the supplied buf and resets the XOF hasher.
/// The hash will be as long as the buf.
#[cfg(ossl111)]
pub fn finish_xof(&mut self, buf: &mut[u8]) -> Result<(), ErrorStack> {
if self.state == Finalized {
self.init()?;
}
unsafe {
cvt(ffi::EVP_DigestFinalXOF(
self.ctx,
buf.as_mut_ptr(),
buf.len(),
))?;
self.state = Finalized;
Ok(())
}
}
} }
impl Write for Hasher { impl Write for Hasher {
@ -311,13 +357,21 @@ impl fmt::Debug for DigestBytes {
} }
} }
/// Computes the hash of the `data` with the hash `t`. /// Computes the hash of the `data` with the non-XOF hasher `t`.
pub fn hash(t: MessageDigest, data: &[u8]) -> Result<DigestBytes, ErrorStack> { pub fn hash(t: MessageDigest, data: &[u8]) -> Result<DigestBytes, ErrorStack> {
let mut h = Hasher::new(t)?; let mut h = Hasher::new(t)?;
h.update(data)?; h.update(data)?;
h.finish() h.finish()
} }
/// Computes the hash of the `data` with the XOF hasher `t` and stores it in `buf`.
#[cfg(ossl111)]
pub fn hash_xof(t: MessageDigest, data: &[u8], buf: &mut[u8]) -> Result<(), ErrorStack> {
let mut h = Hasher::new(t)?;
h.update(data)?;
h.finish_xof(buf)
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use hex::{self, FromHex}; use hex::{self, FromHex};
@ -330,6 +384,14 @@ mod tests {
assert_eq!(hex::encode(res), hashtest.1); assert_eq!(hex::encode(res), hashtest.1);
} }
#[cfg(ossl111)]
fn hash_xof_test(hashtype: MessageDigest, hashtest: &(&str, &str)) {
let expected = Vec::from_hex(hashtest.1).unwrap();
let mut buf = vec![0; expected.len()];
hash_xof(hashtype, &Vec::from_hex(hashtest.0).unwrap(), buf.as_mut_slice()).unwrap();
assert_eq!(buf, expected);
}
fn hash_recycle_test(h: &mut Hasher, hashtest: &(&str, &str)) { fn hash_recycle_test(h: &mut Hasher, hashtest: &(&str, &str)) {
let _ = h.write_all(&Vec::from_hex(hashtest.0).unwrap()).unwrap(); let _ = h.write_all(&Vec::from_hex(hashtest.0).unwrap()).unwrap();
let res = h.finish().unwrap(); let res = h.finish().unwrap();
@ -484,6 +546,30 @@ mod tests {
} }
} }
#[cfg(ossl111)]
#[test]
fn test_shake_128() {
let tests = [("416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
"49d0697ff508111d8b84f15e46daf135"
)];
for test in tests.iter() {
hash_xof_test(MessageDigest::shake_128(), test);
}
}
#[cfg(ossl111)]
#[test]
fn test_shake_256() {
let tests = [("416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
"4e2dfdaa75d1e049d0eaeffe28e76b17cea47b650fb8826fe48b94664326a697"
)];
for test in tests.iter() {
hash_xof_test(MessageDigest::shake_256(), test);
}
}
#[test] #[test]
fn test_ripemd160() { fn test_ripemd160() {
let tests = [("616263", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc")]; let tests = [("616263", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc")];