Merge pull request #1018 from sameer/master
Add SHA3 & SHAKE128/256 EVP message digest functions in OpenSSL 1.1.1, fixes #1017.
This commit is contained in:
commit
894b924f1d
|
|
@ -17,7 +17,7 @@ save_openssl: &SAVE_OPENSSL
|
||||||
paths:
|
paths:
|
||||||
- /openssl
|
- /openssl
|
||||||
deps_key: &DEPS_KEY
|
deps_key: &DEPS_KEY
|
||||||
key: deps-1.20.0-{{ checksum "Cargo.lock" }}-{{ checksum "~/lib_key" }}-2
|
key: deps-1.24.1-{{ checksum "Cargo.lock" }}-{{ checksum "~/lib_key" }}-2
|
||||||
restore_deps: &RESTORE_DEPS
|
restore_deps: &RESTORE_DEPS
|
||||||
restore_cache:
|
restore_cache:
|
||||||
<<: *DEPS_KEY
|
<<: *DEPS_KEY
|
||||||
|
|
@ -31,7 +31,7 @@ save_deps: &SAVE_DEPS
|
||||||
job: &JOB
|
job: &JOB
|
||||||
working_directory: ~/build
|
working_directory: ~/build
|
||||||
docker:
|
docker:
|
||||||
- image: rust:1.20.0
|
- image: rust:1.24.1
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- run: apt-get update
|
- run: apt-get update
|
||||||
|
|
@ -74,7 +74,7 @@ macos_job: &MACOS_JOB
|
||||||
- checkout
|
- checkout
|
||||||
- run: sudo mkdir /opt
|
- run: sudo mkdir /opt
|
||||||
- run: sudo chown -R $USER /usr/local /opt
|
- run: sudo chown -R $USER /usr/local /opt
|
||||||
- run: curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.20.0
|
- run: curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.24.1
|
||||||
- run: sudo ln -s $CARGO_HOME/bin/* /usr/local/bin
|
- run: sudo ln -s $CARGO_HOME/bin/* /usr/local/bin
|
||||||
- run: cargo generate-lockfile --verbose
|
- run: cargo generate-lockfile --verbose
|
||||||
- run: echo "homebrew-x86_64-apple-darwin" > ~/lib_key
|
- run: echo "homebrew-x86_64-apple-darwin" > ~/lib_key
|
||||||
|
|
@ -134,7 +134,7 @@ jobs:
|
||||||
musl-vendored:
|
musl-vendored:
|
||||||
<<: *JOB
|
<<: *JOB
|
||||||
docker:
|
docker:
|
||||||
- image: rust:1.21.0
|
- image: rust:1.24.1
|
||||||
environment:
|
environment:
|
||||||
<<: [*VENDORED, *MUSL, *BASE]
|
<<: [*VENDORED, *MUSL, *BASE]
|
||||||
x86_64-vendored:
|
x86_64-vendored:
|
||||||
|
|
|
||||||
|
|
@ -5,20 +5,20 @@ environment:
|
||||||
- TARGET: i686-pc-windows-gnu
|
- TARGET: i686-pc-windows-gnu
|
||||||
BITS: 32
|
BITS: 32
|
||||||
MSYS2: 1
|
MSYS2: 1
|
||||||
OPENSSL_VERSION: 1_1_0i
|
OPENSSL_VERSION: 1_1_0j
|
||||||
- TARGET: x86_64-pc-windows-msvc
|
- TARGET: x86_64-pc-windows-msvc
|
||||||
BITS: 64
|
BITS: 64
|
||||||
OPENSSL_VERSION: 1_1_0i
|
OPENSSL_VERSION: 1_1_0j
|
||||||
OPENSSL_DIR: C:\OpenSSL
|
OPENSSL_DIR: C:\OpenSSL
|
||||||
|
|
||||||
# 1.0.2, 64/32 bit
|
# 1.0.2, 64/32 bit
|
||||||
- TARGET: x86_64-pc-windows-gnu
|
- TARGET: x86_64-pc-windows-gnu
|
||||||
BITS: 64
|
BITS: 64
|
||||||
MSYS2: 1
|
MSYS2: 1
|
||||||
OPENSSL_VERSION: 1_0_2p
|
OPENSSL_VERSION: 1_0_2q
|
||||||
- TARGET: i686-pc-windows-msvc
|
- TARGET: i686-pc-windows-msvc
|
||||||
BITS: 32
|
BITS: 32
|
||||||
OPENSSL_VERSION: 1_0_2p
|
OPENSSL_VERSION: 1_0_2q
|
||||||
OPENSSL_DIR: C:\OpenSSL
|
OPENSSL_DIR: C:\OpenSSL
|
||||||
- TARGET: x86_64-pc-windows-msvc
|
- TARGET: x86_64-pc-windows-msvc
|
||||||
VCPKG_DEFAULT_TRIPLET: x64-windows
|
VCPKG_DEFAULT_TRIPLET: x64-windows
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,8 @@ extern "C" {
|
||||||
pub fn EVP_DigestFinal_ex(ctx: *mut EVP_MD_CTX, res: *mut u8, n: *mut u32) -> c_int;
|
pub fn EVP_DigestFinal_ex(ctx: *mut EVP_MD_CTX, res: *mut u8, n: *mut u32) -> c_int;
|
||||||
pub fn EVP_DigestInit(ctx: *mut EVP_MD_CTX, typ: *const EVP_MD) -> c_int;
|
pub fn EVP_DigestInit(ctx: *mut EVP_MD_CTX, typ: *const EVP_MD) -> c_int;
|
||||||
pub fn EVP_DigestFinal(ctx: *mut EVP_MD_CTX, res: *mut u8, n: *mut u32) -> c_int;
|
pub fn EVP_DigestFinal(ctx: *mut EVP_MD_CTX, res: *mut u8, n: *mut u32) -> c_int;
|
||||||
|
#[cfg(ossl111)]
|
||||||
|
pub fn EVP_DigestFinalXOF(ctx: *mut EVP_MD_CTX, res: *mut u8, len: usize) -> c_int;
|
||||||
|
|
||||||
pub fn EVP_BytesToKey(
|
pub fn EVP_BytesToKey(
|
||||||
typ: *const EVP_CIPHER,
|
typ: *const EVP_CIPHER,
|
||||||
|
|
@ -148,6 +150,18 @@ extern "C" {
|
||||||
pub fn EVP_sha256() -> *const EVP_MD;
|
pub fn EVP_sha256() -> *const EVP_MD;
|
||||||
pub fn EVP_sha384() -> *const EVP_MD;
|
pub fn EVP_sha384() -> *const EVP_MD;
|
||||||
pub fn EVP_sha512() -> *const EVP_MD;
|
pub fn EVP_sha512() -> *const EVP_MD;
|
||||||
|
#[cfg(ossl111)]
|
||||||
|
pub fn EVP_sha3_224() -> *const EVP_MD;
|
||||||
|
#[cfg(ossl111)]
|
||||||
|
pub fn EVP_sha3_256() -> *const EVP_MD;
|
||||||
|
#[cfg(ossl111)]
|
||||||
|
pub fn EVP_sha3_384() -> *const EVP_MD;
|
||||||
|
#[cfg(ossl111)]
|
||||||
|
pub fn EVP_sha3_512() -> *const EVP_MD;
|
||||||
|
#[cfg(ossl111)]
|
||||||
|
pub fn EVP_shake128() -> *const EVP_MD;
|
||||||
|
#[cfg(ossl111)]
|
||||||
|
pub fn EVP_shake256() -> *const EVP_MD;
|
||||||
pub fn EVP_ripemd160() -> *const EVP_MD;
|
pub fn EVP_ripemd160() -> *const EVP_MD;
|
||||||
pub fn EVP_des_ecb() -> *const EVP_CIPHER;
|
pub fn EVP_des_ecb() -> *const EVP_CIPHER;
|
||||||
pub fn EVP_des_ede3() -> *const EVP_CIPHER;
|
pub fn EVP_des_ede3() -> *const EVP_CIPHER;
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,36 @@ impl MessageDigest {
|
||||||
unsafe { MessageDigest(ffi::EVP_sha512()) }
|
unsafe { MessageDigest(ffi::EVP_sha512()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(ossl111)]
|
||||||
|
pub fn sha3_224() -> MessageDigest {
|
||||||
|
unsafe { MessageDigest(ffi::EVP_sha3_224()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(ossl111)]
|
||||||
|
pub fn sha3_256() -> MessageDigest {
|
||||||
|
unsafe { MessageDigest(ffi::EVP_sha3_256()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(ossl111)]
|
||||||
|
pub fn sha3_384() -> MessageDigest {
|
||||||
|
unsafe { MessageDigest(ffi::EVP_sha3_384()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(ossl111)]
|
||||||
|
pub fn sha3_512() -> MessageDigest {
|
||||||
|
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()) }
|
||||||
}
|
}
|
||||||
|
|
@ -119,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,
|
||||||
|
|
@ -182,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()?;
|
||||||
|
|
@ -202,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 {
|
||||||
|
|
@ -291,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};
|
||||||
|
|
@ -310,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();
|
||||||
|
|
@ -414,6 +496,80 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(ossl111)]
|
||||||
|
#[test]
|
||||||
|
fn test_sha3_224() {
|
||||||
|
let tests = [("416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
|
||||||
|
"1de092dd9fbcbbf450f26264f4778abd48af851f2832924554c56913"
|
||||||
|
)];
|
||||||
|
|
||||||
|
for test in tests.iter() {
|
||||||
|
hash_test(MessageDigest::sha3_224(), test);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(ossl111)]
|
||||||
|
#[test]
|
||||||
|
fn test_sha3_256() {
|
||||||
|
let tests = [("416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
|
||||||
|
"b38e38f08bc1c0091ed4b5f060fe13e86aa4179578513ad11a6e3abba0062f61"
|
||||||
|
)];
|
||||||
|
|
||||||
|
for test in tests.iter() {
|
||||||
|
hash_test(MessageDigest::sha3_256(), test);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(ossl111)]
|
||||||
|
#[test]
|
||||||
|
fn test_sha3_384() {
|
||||||
|
let tests = [("416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
|
||||||
|
"966ee786ab3482dd811bf7c8fa8db79aa1f52f6c3c369942ef14240ebd857c6ff626ec35d9e131ff64d328\
|
||||||
|
ef2008ff16"
|
||||||
|
)];
|
||||||
|
|
||||||
|
for test in tests.iter() {
|
||||||
|
hash_test(MessageDigest::sha3_384(), test);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(ossl111)]
|
||||||
|
#[test]
|
||||||
|
fn test_sha3_512() {
|
||||||
|
let tests = [("416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
|
||||||
|
"c072288ef728cd53a029c47687960b9225893532f42b923156e37020bdc1eda753aafbf30af859d4f4c3a1\
|
||||||
|
807caee3a79f8eb02dcd61589fbbdf5f40c8787a72"
|
||||||
|
)];
|
||||||
|
|
||||||
|
for test in tests.iter() {
|
||||||
|
hash_test(MessageDigest::sha3_512(), test);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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")];
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue