openssl/
hash.rs

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