1 //! Message digest (hash) computation support.
2 //!
3 //! # Examples
4 //!
5 //! Calculate a hash in one go:
6 //!
7 //! ```
8 //! # fn main() -> Result<(), Box<dyn std::error::Error>> {
9 //! use openssl::hash::{hash, MessageDigest};
10 //!
11 //! let data = b"\x42\xF4\x97\xE0";
12 //! let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2";
13 //! let res = hash(MessageDigest::md5(), data)?;
14 //! assert_eq!(&*res, spec);
15 //! # Ok(()) }
16 //! ```
17 //!
18 //! Supply the input in chunks:
19 //!
20 //! ```
21 //! use openssl::hash::{Hasher, MessageDigest};
22 //!
23 //! # fn main() -> Result<(), Box<dyn std::error::Error>> {
24 //! let mut hasher = Hasher::new(MessageDigest::sha256())?;
25 //! hasher.update(b"test")?;
26 //! hasher.update(b"this")?;
27 //! let digest: &[u8] = &hasher.finish()?;
28 //!
29 //! let expected = hex::decode("9740e652ab5b4acd997a7cca13d6696702ccb2d441cca59fc6e285127f28cfe6")?;
30 //! assert_eq!(digest, expected);
31 //! # Ok(()) }
32 //! ```
33 use cfg_if::cfg_if;
34 use std::ffi::CString;
35 use std::fmt;
36 use std::io;
37 use std::io::prelude::*;
38 use std::ops::{Deref, DerefMut};
39 use std::ptr;
40 
41 use crate::error::ErrorStack;
42 use crate::nid::Nid;
43 use crate::{cvt, cvt_p};
44 
45 cfg_if! {
46     if #[cfg(any(ossl110, boringssl, libressl382))] {
47         use ffi::{EVP_MD_CTX_free, EVP_MD_CTX_new};
48     } else {
49         use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free};
50     }
51 }
52 
53 /// A message digest algorithm.
54 #[derive(Copy, Clone, PartialEq, Eq)]
55 pub struct MessageDigest(*const ffi::EVP_MD);
56 
57 impl MessageDigest {
58     /// Creates a `MessageDigest` from a raw OpenSSL pointer.
59     ///
60     /// # Safety
61     ///
62     /// The caller must ensure the pointer is valid.
from_ptr(x: *const ffi::EVP_MD) -> Self63     pub unsafe fn from_ptr(x: *const ffi::EVP_MD) -> Self {
64         MessageDigest(x)
65     }
66 
67     /// Returns the `MessageDigest` corresponding to an `Nid`.
68     ///
69     /// This corresponds to [`EVP_get_digestbynid`].
70     ///
71     /// [`EVP_get_digestbynid`]: https://www.openssl.org/docs/manmaster/crypto/EVP_DigestInit.html
from_nid(type_: Nid) -> Option<MessageDigest>72     pub fn from_nid(type_: Nid) -> Option<MessageDigest> {
73         unsafe {
74             let ptr = ffi::EVP_get_digestbynid(type_.as_raw());
75             if ptr.is_null() {
76                 None
77             } else {
78                 Some(MessageDigest(ptr))
79             }
80         }
81     }
82 
83     /// Returns the `MessageDigest` corresponding to an algorithm name.
84     ///
85     /// This corresponds to [`EVP_get_digestbyname`].
86     ///
87     /// [`EVP_get_digestbyname`]: https://www.openssl.org/docs/manmaster/crypto/EVP_DigestInit.html
from_name(name: &str) -> Option<MessageDigest>88     pub fn from_name(name: &str) -> Option<MessageDigest> {
89         ffi::init();
90         let name = CString::new(name).ok()?;
91         unsafe {
92             let ptr = ffi::EVP_get_digestbyname(name.as_ptr());
93             if ptr.is_null() {
94                 None
95             } else {
96                 Some(MessageDigest(ptr))
97             }
98         }
99     }
100 
101     #[cfg(not(boringssl))]
null() -> MessageDigest102     pub fn null() -> MessageDigest {
103         unsafe { MessageDigest(ffi::EVP_md_null()) }
104     }
105 
md5() -> MessageDigest106     pub fn md5() -> MessageDigest {
107         unsafe { MessageDigest(ffi::EVP_md5()) }
108     }
109 
sha1() -> MessageDigest110     pub fn sha1() -> MessageDigest {
111         unsafe { MessageDigest(ffi::EVP_sha1()) }
112     }
113 
sha224() -> MessageDigest114     pub fn sha224() -> MessageDigest {
115         unsafe { MessageDigest(ffi::EVP_sha224()) }
116     }
117 
sha256() -> MessageDigest118     pub fn sha256() -> MessageDigest {
119         unsafe { MessageDigest(ffi::EVP_sha256()) }
120     }
121 
sha384() -> MessageDigest122     pub fn sha384() -> MessageDigest {
123         unsafe { MessageDigest(ffi::EVP_sha384()) }
124     }
125 
sha512() -> MessageDigest126     pub fn sha512() -> MessageDigest {
127         unsafe { MessageDigest(ffi::EVP_sha512()) }
128     }
129 
130     #[cfg(any(ossl111, libressl380))]
sha3_224() -> MessageDigest131     pub fn sha3_224() -> MessageDigest {
132         unsafe { MessageDigest(ffi::EVP_sha3_224()) }
133     }
134 
135     #[cfg(any(ossl111, libressl380))]
sha3_256() -> MessageDigest136     pub fn sha3_256() -> MessageDigest {
137         unsafe { MessageDigest(ffi::EVP_sha3_256()) }
138     }
139 
140     #[cfg(any(ossl111, libressl380))]
sha3_384() -> MessageDigest141     pub fn sha3_384() -> MessageDigest {
142         unsafe { MessageDigest(ffi::EVP_sha3_384()) }
143     }
144 
145     #[cfg(any(ossl111, libressl380))]
sha3_512() -> MessageDigest146     pub fn sha3_512() -> MessageDigest {
147         unsafe { MessageDigest(ffi::EVP_sha3_512()) }
148     }
149 
150     #[cfg(ossl111)]
shake_128() -> MessageDigest151     pub fn shake_128() -> MessageDigest {
152         unsafe { MessageDigest(ffi::EVP_shake128()) }
153     }
154 
155     #[cfg(ossl111)]
shake_256() -> MessageDigest156     pub fn shake_256() -> MessageDigest {
157         unsafe { MessageDigest(ffi::EVP_shake256()) }
158     }
159 
160     #[cfg(not(osslconf = "OPENSSL_NO_RMD160"))]
161     #[cfg(not(boringssl))]
ripemd160() -> MessageDigest162     pub fn ripemd160() -> MessageDigest {
163         unsafe { MessageDigest(ffi::EVP_ripemd160()) }
164     }
165 
166     #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM3")))]
sm3() -> MessageDigest167     pub fn sm3() -> MessageDigest {
168         unsafe { MessageDigest(ffi::EVP_sm3()) }
169     }
170 
171     #[allow(clippy::trivially_copy_pass_by_ref)]
as_ptr(&self) -> *const ffi::EVP_MD172     pub fn as_ptr(&self) -> *const ffi::EVP_MD {
173         self.0
174     }
175 
176     /// The block size of the digest in bytes.
177     #[allow(clippy::trivially_copy_pass_by_ref)]
block_size(&self) -> usize178     pub fn block_size(&self) -> usize {
179         unsafe { ffi::EVP_MD_block_size(self.0) as usize }
180     }
181 
182     /// The size of the digest in bytes.
183     #[allow(clippy::trivially_copy_pass_by_ref)]
size(&self) -> usize184     pub fn size(&self) -> usize {
185         unsafe { ffi::EVP_MD_size(self.0) as usize }
186     }
187 
188     /// The name of the digest.
189     #[allow(clippy::trivially_copy_pass_by_ref)]
type_(&self) -> Nid190     pub fn type_(&self) -> Nid {
191         Nid::from_raw(unsafe { ffi::EVP_MD_type(self.0) })
192     }
193 }
194 
195 unsafe impl Sync for MessageDigest {}
196 unsafe impl Send for MessageDigest {}
197 
198 #[derive(PartialEq, Copy, Clone)]
199 enum State {
200     Reset,
201     Updated,
202     Finalized,
203 }
204 
205 use self::State::*;
206 
207 /// Provides message digest (hash) computation.
208 ///
209 /// # Examples
210 ///
211 /// ```
212 /// use openssl::hash::{Hasher, MessageDigest};
213 ///
214 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
215 /// let data = [b"\x42\xF4", b"\x97\xE0"];
216 /// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2";
217 /// let mut h = Hasher::new(MessageDigest::md5())?;
218 /// h.update(data[0])?;
219 /// h.update(data[1])?;
220 /// let res = h.finish()?;
221 /// assert_eq!(&*res, spec);
222 /// # Ok(()) }
223 /// ```
224 ///
225 /// # Warning
226 ///
227 /// Don't actually use MD5 and SHA-1 hashes, they're not secure anymore.
228 ///
229 /// Don't ever hash passwords, use the functions in the `pkcs5` module or bcrypt/scrypt instead.
230 ///
231 /// For extendable output functions (XOFs, i.e. SHAKE128/SHAKE256),
232 /// you must use [`Hasher::finish_xof`] instead of [`Hasher::finish`]
233 /// and provide a `buf` to store the hash. The hash will be as long as
234 /// the `buf`.
235 pub struct Hasher {
236     ctx: *mut ffi::EVP_MD_CTX,
237     md: *const ffi::EVP_MD,
238     type_: MessageDigest,
239     state: State,
240 }
241 
242 unsafe impl Sync for Hasher {}
243 unsafe impl Send for Hasher {}
244 
245 impl Hasher {
246     /// Creates a new `Hasher` with the specified hash type.
new(ty: MessageDigest) -> Result<Hasher, ErrorStack>247     pub fn new(ty: MessageDigest) -> Result<Hasher, ErrorStack> {
248         ffi::init();
249 
250         let ctx = unsafe { cvt_p(EVP_MD_CTX_new())? };
251 
252         let mut h = Hasher {
253             ctx,
254             md: ty.as_ptr(),
255             type_: ty,
256             state: Finalized,
257         };
258         h.init()?;
259         Ok(h)
260     }
261 
init(&mut self) -> Result<(), ErrorStack>262     fn init(&mut self) -> Result<(), ErrorStack> {
263         match self.state {
264             Reset => return Ok(()),
265             Updated => {
266                 self.finish()?;
267             }
268             Finalized => (),
269         }
270         unsafe {
271             cvt(ffi::EVP_DigestInit_ex(self.ctx, self.md, ptr::null_mut()))?;
272         }
273         self.state = Reset;
274         Ok(())
275     }
276 
277     /// Feeds data into the hasher.
update(&mut self, data: &[u8]) -> Result<(), ErrorStack>278     pub fn update(&mut self, data: &[u8]) -> Result<(), ErrorStack> {
279         if self.state == Finalized {
280             self.init()?;
281         }
282         unsafe {
283             cvt(ffi::EVP_DigestUpdate(
284                 self.ctx,
285                 data.as_ptr() as *mut _,
286                 data.len(),
287             ))?;
288         }
289         self.state = Updated;
290         Ok(())
291     }
292 
293     /// Returns the hash of the data written and resets the non-XOF hasher.
finish(&mut self) -> Result<DigestBytes, ErrorStack>294     pub fn finish(&mut self) -> Result<DigestBytes, ErrorStack> {
295         if self.state == Finalized {
296             self.init()?;
297         }
298         unsafe {
299             #[cfg(not(boringssl))]
300             let mut len = ffi::EVP_MAX_MD_SIZE;
301             #[cfg(boringssl)]
302             let mut len = ffi::EVP_MAX_MD_SIZE as u32;
303             let mut buf = [0; ffi::EVP_MAX_MD_SIZE as usize];
304             cvt(ffi::EVP_DigestFinal_ex(
305                 self.ctx,
306                 buf.as_mut_ptr(),
307                 &mut len,
308             ))?;
309             self.state = Finalized;
310             Ok(DigestBytes {
311                 buf,
312                 len: len as usize,
313             })
314         }
315     }
316 
317     /// Writes the hash of the data into the supplied buf and resets the XOF hasher.
318     /// The hash will be as long as the buf.
319     #[cfg(ossl111)]
finish_xof(&mut self, buf: &mut [u8]) -> Result<(), ErrorStack>320     pub fn finish_xof(&mut self, buf: &mut [u8]) -> Result<(), ErrorStack> {
321         if self.state == Finalized {
322             self.init()?;
323         }
324         unsafe {
325             cvt(ffi::EVP_DigestFinalXOF(
326                 self.ctx,
327                 buf.as_mut_ptr(),
328                 buf.len(),
329             ))?;
330             self.state = Finalized;
331             Ok(())
332         }
333     }
334 }
335 
336 impl Write for Hasher {
337     #[inline]
write(&mut self, buf: &[u8]) -> io::Result<usize>338     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
339         self.update(buf)?;
340         Ok(buf.len())
341     }
342 
flush(&mut self) -> io::Result<()>343     fn flush(&mut self) -> io::Result<()> {
344         Ok(())
345     }
346 }
347 
348 impl Clone for Hasher {
clone(&self) -> Hasher349     fn clone(&self) -> Hasher {
350         let ctx = unsafe {
351             let ctx = EVP_MD_CTX_new();
352             assert!(!ctx.is_null());
353             let r = ffi::EVP_MD_CTX_copy_ex(ctx, self.ctx);
354             assert_eq!(r, 1);
355             ctx
356         };
357         Hasher {
358             ctx,
359             md: self.md,
360             type_: self.type_,
361             state: self.state,
362         }
363     }
364 }
365 
366 impl Drop for Hasher {
drop(&mut self)367     fn drop(&mut self) {
368         unsafe {
369             if self.state != Finalized {
370                 drop(self.finish());
371             }
372             EVP_MD_CTX_free(self.ctx);
373         }
374     }
375 }
376 
377 /// The resulting bytes of a digest.
378 ///
379 /// This type derefs to a byte slice - it exists to avoid allocating memory to
380 /// store the digest data.
381 #[derive(Copy)]
382 pub struct DigestBytes {
383     pub(crate) buf: [u8; ffi::EVP_MAX_MD_SIZE as usize],
384     pub(crate) len: usize,
385 }
386 
387 impl Clone for DigestBytes {
388     #[inline]
clone(&self) -> DigestBytes389     fn clone(&self) -> DigestBytes {
390         *self
391     }
392 }
393 
394 impl Deref for DigestBytes {
395     type Target = [u8];
396 
397     #[inline]
deref(&self) -> &[u8]398     fn deref(&self) -> &[u8] {
399         &self.buf[..self.len]
400     }
401 }
402 
403 impl DerefMut for DigestBytes {
404     #[inline]
deref_mut(&mut self) -> &mut [u8]405     fn deref_mut(&mut self) -> &mut [u8] {
406         &mut self.buf[..self.len]
407     }
408 }
409 
410 impl AsRef<[u8]> for DigestBytes {
411     #[inline]
as_ref(&self) -> &[u8]412     fn as_ref(&self) -> &[u8] {
413         self.deref()
414     }
415 }
416 
417 impl fmt::Debug for DigestBytes {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result418     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
419         fmt::Debug::fmt(&**self, fmt)
420     }
421 }
422 
423 /// Computes the hash of the `data` with the non-XOF hasher `t`.
424 ///
425 /// # Examples
426 ///
427 /// ```
428 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
429 /// use openssl::hash::{hash, MessageDigest};
430 ///
431 /// let data = b"\x42\xF4\x97\xE0";
432 /// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2";
433 /// let res = hash(MessageDigest::md5(), data)?;
434 /// assert_eq!(&*res, spec);
435 /// # Ok(()) }
436 /// ```
hash(t: MessageDigest, data: &[u8]) -> Result<DigestBytes, ErrorStack>437 pub fn hash(t: MessageDigest, data: &[u8]) -> Result<DigestBytes, ErrorStack> {
438     let mut h = Hasher::new(t)?;
439     h.update(data)?;
440     h.finish()
441 }
442 
443 /// Computes the hash of the `data` with the XOF hasher `t` and stores it in `buf`.
444 ///
445 /// # Examples
446 ///
447 /// ```
448 /// use openssl::hash::{hash_xof, MessageDigest};
449 ///
450 /// 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";
451 /// let spec = b"\x49\xd0\x69\x7f\xf5\x08\x11\x1d\x8b\x84\xf1\x5e\x46\xda\xf1\x35";
452 /// let mut buf = vec![0; 16];
453 /// hash_xof(MessageDigest::shake_128(), data, buf.as_mut_slice()).unwrap();
454 /// assert_eq!(buf, spec);
455 /// ```
456 ///
457 #[cfg(ossl111)]
hash_xof(t: MessageDigest, data: &[u8], buf: &mut [u8]) -> Result<(), ErrorStack>458 pub fn hash_xof(t: MessageDigest, data: &[u8], buf: &mut [u8]) -> Result<(), ErrorStack> {
459     let mut h = Hasher::new(t)?;
460     h.update(data)?;
461     h.finish_xof(buf)
462 }
463 
464 #[cfg(test)]
465 mod tests {
466     use hex::{self, FromHex};
467     use std::io::prelude::*;
468 
469     use super::*;
470 
hash_test(hashtype: MessageDigest, hashtest: &(&str, &str))471     fn hash_test(hashtype: MessageDigest, hashtest: &(&str, &str)) {
472         let res = hash(hashtype, &Vec::from_hex(hashtest.0).unwrap()).unwrap();
473         assert_eq!(hex::encode(res), hashtest.1);
474     }
475 
476     #[cfg(ossl111)]
hash_xof_test(hashtype: MessageDigest, hashtest: &(&str, &str))477     fn hash_xof_test(hashtype: MessageDigest, hashtest: &(&str, &str)) {
478         let expected = Vec::from_hex(hashtest.1).unwrap();
479         let mut buf = vec![0; expected.len()];
480         hash_xof(
481             hashtype,
482             &Vec::from_hex(hashtest.0).unwrap(),
483             buf.as_mut_slice(),
484         )
485         .unwrap();
486         assert_eq!(buf, expected);
487     }
488 
hash_recycle_test(h: &mut Hasher, hashtest: &(&str, &str))489     fn hash_recycle_test(h: &mut Hasher, hashtest: &(&str, &str)) {
490         h.write_all(&Vec::from_hex(hashtest.0).unwrap()).unwrap();
491         let res = h.finish().unwrap();
492         assert_eq!(hex::encode(res), hashtest.1);
493     }
494 
495     // Test vectors from http://www.nsrl.nist.gov/testdata/
496     const MD5_TESTS: [(&str, &str); 13] = [
497         ("", "d41d8cd98f00b204e9800998ecf8427e"),
498         ("7F", "83acb6e67e50e31db6ed341dd2de1595"),
499         ("EC9C", "0b07f0d4ca797d8ac58874f887cb0b68"),
500         ("FEE57A", "e0d583171eb06d56198fc0ef22173907"),
501         ("42F497E0", "7c430f178aefdf1487fee7144e9641e2"),
502         ("C53B777F1C", "75ef141d64cb37ec423da2d9d440c925"),
503         ("89D5B576327B", "ebbaf15eb0ed784c6faa9dc32831bf33"),
504         ("5D4CCE781EB190", "ce175c4b08172019f05e6b5279889f2c"),
505         ("81901FE94932D7B9", "cd4d2f62b8cdb3a0cf968a735a239281"),
506         ("C9FFDEE7788EFB4EC9", "e0841a231ab698db30c6c0f3f246c014"),
507         ("66AC4B7EBA95E53DC10B", "a3b3cea71910d9af56742aa0bb2fe329"),
508         ("A510CD18F7A56852EB0319", "577e216843dd11573574d3fb209b97d8"),
509         (
510             "AAED18DBE8938C19ED734A8D",
511             "6f80fb775f27e0a4ce5c2f42fc72c5f1",
512         ),
513     ];
514 
515     #[test]
test_md5()516     fn test_md5() {
517         for test in MD5_TESTS.iter() {
518             hash_test(MessageDigest::md5(), test);
519         }
520 
521         assert_eq!(MessageDigest::md5().block_size(), 64);
522         assert_eq!(MessageDigest::md5().size(), 16);
523         assert_eq!(MessageDigest::md5().type_().as_raw(), Nid::MD5.as_raw());
524     }
525 
526     #[test]
test_md5_recycle()527     fn test_md5_recycle() {
528         let mut h = Hasher::new(MessageDigest::md5()).unwrap();
529         for test in MD5_TESTS.iter() {
530             hash_recycle_test(&mut h, test);
531         }
532     }
533 
534     #[test]
test_finish_twice()535     fn test_finish_twice() {
536         let mut h = Hasher::new(MessageDigest::md5()).unwrap();
537         h.write_all(&Vec::from_hex(MD5_TESTS[6].0).unwrap())
538             .unwrap();
539         h.finish().unwrap();
540         let res = h.finish().unwrap();
541         let null = hash(MessageDigest::md5(), &[]).unwrap();
542         assert_eq!(&*res, &*null);
543     }
544 
545     #[test]
546     #[allow(clippy::redundant_clone)]
test_clone()547     fn test_clone() {
548         let i = 7;
549         let inp = Vec::from_hex(MD5_TESTS[i].0).unwrap();
550         assert!(inp.len() > 2);
551         let p = inp.len() / 2;
552         let h0 = Hasher::new(MessageDigest::md5()).unwrap();
553 
554         println!("Clone a new hasher");
555         let mut h1 = h0.clone();
556         h1.write_all(&inp[..p]).unwrap();
557         {
558             println!("Clone an updated hasher");
559             let mut h2 = h1.clone();
560             h2.write_all(&inp[p..]).unwrap();
561             let res = h2.finish().unwrap();
562             assert_eq!(hex::encode(res), MD5_TESTS[i].1);
563         }
564         h1.write_all(&inp[p..]).unwrap();
565         let res = h1.finish().unwrap();
566         assert_eq!(hex::encode(res), MD5_TESTS[i].1);
567 
568         println!("Clone a finished hasher");
569         let mut h3 = h1.clone();
570         h3.write_all(&Vec::from_hex(MD5_TESTS[i + 1].0).unwrap())
571             .unwrap();
572         let res = h3.finish().unwrap();
573         assert_eq!(hex::encode(res), MD5_TESTS[i + 1].1);
574     }
575 
576     #[test]
test_sha1()577     fn test_sha1() {
578         let tests = [("616263", "a9993e364706816aba3e25717850c26c9cd0d89d")];
579 
580         for test in tests.iter() {
581             hash_test(MessageDigest::sha1(), test);
582         }
583 
584         assert_eq!(MessageDigest::sha1().block_size(), 64);
585         assert_eq!(MessageDigest::sha1().size(), 20);
586         assert_eq!(MessageDigest::sha1().type_().as_raw(), Nid::SHA1.as_raw());
587     }
588 
589     #[test]
test_sha256()590     fn test_sha256() {
591         let tests = [(
592             "616263",
593             "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
594         )];
595 
596         for test in tests.iter() {
597             hash_test(MessageDigest::sha256(), test);
598         }
599 
600         assert_eq!(MessageDigest::sha256().block_size(), 64);
601         assert_eq!(MessageDigest::sha256().size(), 32);
602         assert_eq!(
603             MessageDigest::sha256().type_().as_raw(),
604             Nid::SHA256.as_raw()
605         );
606     }
607 
608     #[test]
test_sha512()609     fn test_sha512() {
610         let tests = [(
611             "737465766566696e647365766572797468696e67",
612             "ba61d1f1af0f2dd80729f6cc900f19c0966bd38ba5c75e4471ef11b771dfe7551afab7fcbd300fdc4418f2\
613             b07a028fcd99e7b6446a566f2d9bcd7c604a1ea801",
614         )];
615 
616         for test in tests.iter() {
617             hash_test(MessageDigest::sha512(), test);
618         }
619 
620         assert_eq!(MessageDigest::sha512().block_size(), 128);
621         assert_eq!(MessageDigest::sha512().size(), 64);
622         assert_eq!(
623             MessageDigest::sha512().type_().as_raw(),
624             Nid::SHA512.as_raw()
625         );
626     }
627 
628     #[cfg(any(ossl111, libressl380))]
629     #[test]
test_sha3_224()630     fn test_sha3_224() {
631         let tests = [(
632             "416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
633             "1de092dd9fbcbbf450f26264f4778abd48af851f2832924554c56913",
634         )];
635 
636         for test in tests.iter() {
637             hash_test(MessageDigest::sha3_224(), test);
638         }
639 
640         assert_eq!(MessageDigest::sha3_224().block_size(), 144);
641         assert_eq!(MessageDigest::sha3_224().size(), 28);
642         assert_eq!(
643             MessageDigest::sha3_224().type_().as_raw(),
644             Nid::SHA3_224.as_raw()
645         );
646     }
647 
648     #[cfg(any(ossl111, libressl380))]
649     #[test]
test_sha3_256()650     fn test_sha3_256() {
651         let tests = [(
652             "416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
653             "b38e38f08bc1c0091ed4b5f060fe13e86aa4179578513ad11a6e3abba0062f61",
654         )];
655 
656         for test in tests.iter() {
657             hash_test(MessageDigest::sha3_256(), test);
658         }
659 
660         assert_eq!(MessageDigest::sha3_256().block_size(), 136);
661         assert_eq!(MessageDigest::sha3_256().size(), 32);
662         assert_eq!(
663             MessageDigest::sha3_256().type_().as_raw(),
664             Nid::SHA3_256.as_raw()
665         );
666     }
667 
668     #[cfg(any(ossl111, libressl380))]
669     #[test]
test_sha3_384()670     fn test_sha3_384() {
671         let tests = [("416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
672             "966ee786ab3482dd811bf7c8fa8db79aa1f52f6c3c369942ef14240ebd857c6ff626ec35d9e131ff64d328\
673             ef2008ff16"
674         )];
675 
676         for test in tests.iter() {
677             hash_test(MessageDigest::sha3_384(), test);
678         }
679 
680         assert_eq!(MessageDigest::sha3_384().block_size(), 104);
681         assert_eq!(MessageDigest::sha3_384().size(), 48);
682         assert_eq!(
683             MessageDigest::sha3_384().type_().as_raw(),
684             Nid::SHA3_384.as_raw()
685         );
686     }
687 
688     #[cfg(any(ossl111, libressl380))]
689     #[test]
test_sha3_512()690     fn test_sha3_512() {
691         let tests = [("416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
692             "c072288ef728cd53a029c47687960b9225893532f42b923156e37020bdc1eda753aafbf30af859d4f4c3a1\
693             807caee3a79f8eb02dcd61589fbbdf5f40c8787a72"
694         )];
695 
696         for test in tests.iter() {
697             hash_test(MessageDigest::sha3_512(), test);
698         }
699 
700         assert_eq!(MessageDigest::sha3_512().block_size(), 72);
701         assert_eq!(MessageDigest::sha3_512().size(), 64);
702         assert_eq!(
703             MessageDigest::sha3_512().type_().as_raw(),
704             Nid::SHA3_512.as_raw()
705         );
706     }
707 
708     #[cfg(ossl111)]
709     #[test]
test_shake_128()710     fn test_shake_128() {
711         let tests = [(
712             "416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
713             "49d0697ff508111d8b84f15e46daf135",
714         )];
715 
716         for test in tests.iter() {
717             hash_xof_test(MessageDigest::shake_128(), test);
718         }
719 
720         assert_eq!(MessageDigest::shake_128().block_size(), 168);
721         assert_eq!(MessageDigest::shake_128().size(), 16);
722         assert_eq!(
723             MessageDigest::shake_128().type_().as_raw(),
724             Nid::SHAKE128.as_raw()
725         );
726     }
727 
728     #[cfg(ossl111)]
729     #[test]
test_shake_256()730     fn test_shake_256() {
731         let tests = [(
732             "416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
733             "4e2dfdaa75d1e049d0eaeffe28e76b17cea47b650fb8826fe48b94664326a697",
734         )];
735 
736         for test in tests.iter() {
737             hash_xof_test(MessageDigest::shake_256(), test);
738         }
739 
740         assert_eq!(MessageDigest::shake_256().block_size(), 136);
741         assert_eq!(MessageDigest::shake_256().size(), 32);
742         assert_eq!(
743             MessageDigest::shake_256().type_().as_raw(),
744             Nid::SHAKE256.as_raw()
745         );
746     }
747 
748     #[test]
749     #[cfg(not(osslconf = "OPENSSL_NO_RMD160"))]
750     #[cfg_attr(ossl300, ignore)]
test_ripemd160()751     fn test_ripemd160() {
752         #[cfg(ossl300)]
753         let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap();
754 
755         let tests = [("616263", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc")];
756 
757         for test in tests.iter() {
758             hash_test(MessageDigest::ripemd160(), test);
759         }
760 
761         assert_eq!(MessageDigest::ripemd160().block_size(), 64);
762         assert_eq!(MessageDigest::ripemd160().size(), 20);
763         assert_eq!(
764             MessageDigest::ripemd160().type_().as_raw(),
765             Nid::RIPEMD160.as_raw()
766         );
767     }
768 
769     #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM3")))]
770     #[test]
test_sm3()771     fn test_sm3() {
772         let tests = [(
773             "616263",
774             "66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0",
775         )];
776 
777         for test in tests.iter() {
778             hash_test(MessageDigest::sm3(), test);
779         }
780 
781         assert_eq!(MessageDigest::sm3().block_size(), 64);
782         assert_eq!(MessageDigest::sm3().size(), 32);
783         assert_eq!(MessageDigest::sm3().type_().as_raw(), Nid::SM3.as_raw());
784     }
785 
786     #[test]
from_nid()787     fn from_nid() {
788         assert_eq!(
789             MessageDigest::from_nid(Nid::SHA256).unwrap().as_ptr(),
790             MessageDigest::sha256().as_ptr()
791         );
792     }
793 
794     #[test]
from_name()795     fn from_name() {
796         assert_eq!(
797             MessageDigest::from_name("SHA256").unwrap().as_ptr(),
798             MessageDigest::sha256().as_ptr()
799         )
800     }
801 }
802