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