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, awslc))] {
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, awslc))]
127    pub fn sha3_224() -> MessageDigest {
128        unsafe { MessageDigest(ffi::EVP_sha3_224()) }
129    }
130
131    #[cfg(any(ossl111, libressl380, awslc))]
132    pub fn sha3_256() -> MessageDigest {
133        unsafe { MessageDigest(ffi::EVP_sha3_256()) }
134    }
135
136    #[cfg(any(ossl111, libressl380, awslc))]
137    pub fn sha3_384() -> MessageDigest {
138        unsafe { MessageDigest(ffi::EVP_sha3_384()) }
139    }
140
141    #[cfg(any(ossl111, libressl380, awslc))]
142    pub fn sha3_512() -> MessageDigest {
143        unsafe { MessageDigest(ffi::EVP_sha3_512()) }
144    }
145
146    #[cfg(any(ossl111, awslc))]
147    pub fn shake_128() -> MessageDigest {
148        unsafe { MessageDigest(ffi::EVP_shake128()) }
149    }
150
151    #[cfg(any(ossl111, awslc))]
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, libressl), 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    #[cfg(any(ossl330, awslc))]
198    Squeeze,
199    Finalized,
200}
201
202use self::State::*;
203
204/// Provides message digest (hash) computation.
205///
206/// # Examples
207///
208/// ```
209/// use openssl::hash::{Hasher, MessageDigest};
210///
211/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
212/// let data = [b"\x42\xF4", b"\x97\xE0"];
213/// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2";
214/// let mut h = Hasher::new(MessageDigest::md5())?;
215/// h.update(data[0])?;
216/// h.update(data[1])?;
217/// let res = h.finish()?;
218/// assert_eq!(&*res, spec);
219/// # Ok(()) }
220/// ```
221///
222/// # Warning
223///
224/// Don't actually use MD5 and SHA-1 hashes, they're not secure anymore.
225///
226/// Don't ever hash passwords, use the functions in the `pkcs5` module or bcrypt/scrypt instead.
227///
228/// For extendable output functions (XOFs, i.e. SHAKE128/SHAKE256),
229/// you must use [`Hasher::finish_xof`] instead of [`Hasher::finish`]
230/// and provide a `buf` to store the hash. The hash will be as long as
231/// the `buf`.
232pub struct Hasher {
233    ctx: *mut ffi::EVP_MD_CTX,
234    md: *const ffi::EVP_MD,
235    type_: MessageDigest,
236    state: State,
237}
238
239unsafe impl Sync for Hasher {}
240unsafe impl Send for Hasher {}
241
242impl Hasher {
243    /// Creates a new `Hasher` with the specified hash type.
244    pub fn new(ty: MessageDigest) -> Result<Hasher, ErrorStack> {
245        ffi::init();
246
247        let ctx = unsafe { cvt_p(EVP_MD_CTX_new())? };
248
249        let mut h = Hasher {
250            ctx,
251            md: ty.as_ptr(),
252            type_: ty,
253            state: Finalized,
254        };
255        h.init()?;
256        Ok(h)
257    }
258
259    fn init(&mut self) -> Result<(), ErrorStack> {
260        match self.state {
261            Reset => return Ok(()),
262            Updated => {
263                self.finish()?;
264            }
265            #[cfg(any(ossl330, awslc))]
266            Squeeze => (),
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        #[cfg(any(ossl330, awslc))]
282        if self.state == Squeeze {
283            // [`EVP_DigestUpdate`], depending on the implementation, may allow Updates after Squeezes.
284            // But, [FIPS 202], as shown in Figure 7, has a distinguished absorbing phase followed by a squeezing phase.
285            // Indeed, the [`sha3.c`] implmentation disallows Updates after Squeezes.
286            // For consistency, we always return an error when Update is called after Squeeze.
287            //
288            // [`EVP_DigestUpdate`]: https://github.com/openssl/openssl/blob/b3bb214720f20f3b126ae4b9c330e9a48b835415/crypto/evp/digest.c#L385-L393
289            // [FIPS 202]: https://dx.doi.org/10.6028/NIST.FIPS.202
290            // [`sha3.c`]: https://github.com/openssl/openssl/blob/b3bb214720f20f3b126ae4b9c330e9a48b835415/crypto/sha/sha3.c#L52-L63
291            let errors = ErrorStack::get();
292            return Err(errors);
293        }
294        unsafe {
295            cvt(ffi::EVP_DigestUpdate(
296                self.ctx,
297                data.as_ptr() as *mut _,
298                data.len(),
299            ))?;
300        }
301        self.state = Updated;
302        Ok(())
303    }
304
305    /// Squeezes buf out of the hasher. Can be called multiple times, unlike `finish_xof`.
306    /// The output will be as long as the buf.
307    #[cfg(any(ossl330, awslc))]
308    pub fn squeeze_xof(&mut self, buf: &mut [u8]) -> Result<(), ErrorStack> {
309        unsafe {
310            cvt(ffi::EVP_DigestSqueeze(
311                self.ctx,
312                buf.as_mut_ptr(),
313                buf.len(),
314            ))?;
315            self.state = Squeeze;
316            Ok(())
317        }
318    }
319
320    /// Returns the hash of the data written and resets the non-XOF hasher.
321    pub fn finish(&mut self) -> Result<DigestBytes, ErrorStack> {
322        if self.state == Finalized {
323            self.init()?;
324        }
325        unsafe {
326            #[cfg(not(any(boringssl, awslc)))]
327            let mut len = ffi::EVP_MAX_MD_SIZE;
328            #[cfg(any(boringssl, awslc))]
329            let mut len = ffi::EVP_MAX_MD_SIZE as u32;
330            let mut buf = [0; ffi::EVP_MAX_MD_SIZE as usize];
331            cvt(ffi::EVP_DigestFinal_ex(
332                self.ctx,
333                buf.as_mut_ptr(),
334                &mut len,
335            ))?;
336            self.state = Finalized;
337            Ok(DigestBytes {
338                buf,
339                len: len as usize,
340            })
341        }
342    }
343
344    /// Writes the hash of the data into the supplied buf and resets the XOF hasher.
345    /// The hash will be as long as the buf.
346    #[cfg(any(ossl111, awslc))]
347    pub fn finish_xof(&mut self, buf: &mut [u8]) -> Result<(), ErrorStack> {
348        if self.state == Finalized {
349            self.init()?;
350        }
351        unsafe {
352            cvt(ffi::EVP_DigestFinalXOF(
353                self.ctx,
354                buf.as_mut_ptr(),
355                buf.len(),
356            ))?;
357            self.state = Finalized;
358            Ok(())
359        }
360    }
361}
362
363impl Write for Hasher {
364    #[inline]
365    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
366        self.update(buf)?;
367        Ok(buf.len())
368    }
369
370    fn flush(&mut self) -> io::Result<()> {
371        Ok(())
372    }
373}
374
375impl Clone for Hasher {
376    fn clone(&self) -> Hasher {
377        let ctx = unsafe {
378            let ctx = EVP_MD_CTX_new();
379            assert!(!ctx.is_null());
380            let r = ffi::EVP_MD_CTX_copy_ex(ctx, self.ctx);
381            assert_eq!(r, 1);
382            ctx
383        };
384        Hasher {
385            ctx,
386            md: self.md,
387            type_: self.type_,
388            state: self.state,
389        }
390    }
391}
392
393impl Drop for Hasher {
394    fn drop(&mut self) {
395        unsafe {
396            if self.state != Finalized {
397                drop(self.finish());
398            }
399            EVP_MD_CTX_free(self.ctx);
400        }
401    }
402}
403
404/// The resulting bytes of a digest.
405///
406/// This type derefs to a byte slice - it exists to avoid allocating memory to
407/// store the digest data.
408#[derive(Copy)]
409pub struct DigestBytes {
410    pub(crate) buf: [u8; ffi::EVP_MAX_MD_SIZE as usize],
411    pub(crate) len: usize,
412}
413
414impl Clone for DigestBytes {
415    #[inline]
416    fn clone(&self) -> DigestBytes {
417        *self
418    }
419}
420
421impl Deref for DigestBytes {
422    type Target = [u8];
423
424    #[inline]
425    fn deref(&self) -> &[u8] {
426        &self.buf[..self.len]
427    }
428}
429
430impl DerefMut for DigestBytes {
431    #[inline]
432    fn deref_mut(&mut self) -> &mut [u8] {
433        &mut self.buf[..self.len]
434    }
435}
436
437impl AsRef<[u8]> for DigestBytes {
438    #[inline]
439    fn as_ref(&self) -> &[u8] {
440        self.deref()
441    }
442}
443
444impl fmt::Debug for DigestBytes {
445    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
446        fmt::Debug::fmt(&**self, fmt)
447    }
448}
449
450/// Computes the hash of the `data` with the non-XOF hasher `t`.
451///
452/// # Examples
453///
454/// ```
455/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
456/// use openssl::hash::{hash, MessageDigest};
457///
458/// let data = b"\x42\xF4\x97\xE0";
459/// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2";
460/// let res = hash(MessageDigest::md5(), data)?;
461/// assert_eq!(&*res, spec);
462/// # Ok(()) }
463/// ```
464pub fn hash(t: MessageDigest, data: &[u8]) -> Result<DigestBytes, ErrorStack> {
465    let mut h = Hasher::new(t)?;
466    h.update(data)?;
467    h.finish()
468}
469
470/// Computes the hash of the `data` with the XOF hasher `t` and stores it in `buf`.
471///
472/// # Examples
473///
474/// ```
475/// use openssl::hash::{hash_xof, MessageDigest};
476///
477/// 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";
478/// let spec = b"\x49\xd0\x69\x7f\xf5\x08\x11\x1d\x8b\x84\xf1\x5e\x46\xda\xf1\x35";
479/// let mut buf = vec![0; 16];
480/// hash_xof(MessageDigest::shake_128(), data, buf.as_mut_slice()).unwrap();
481/// assert_eq!(buf, spec);
482/// ```
483///
484#[cfg(any(ossl111, awslc))]
485pub fn hash_xof(t: MessageDigest, data: &[u8], buf: &mut [u8]) -> Result<(), ErrorStack> {
486    let mut h = Hasher::new(t)?;
487    h.update(data)?;
488    h.finish_xof(buf)
489}
490
491#[cfg(test)]
492mod tests {
493    use hex::{self, FromHex};
494    use std::io::prelude::*;
495
496    use super::*;
497
498    fn hash_test(hashtype: MessageDigest, hashtest: &(&str, &str)) {
499        let res = hash(hashtype, &Vec::from_hex(hashtest.0).unwrap()).unwrap();
500        assert_eq!(hex::encode(res), hashtest.1);
501    }
502
503    #[cfg(any(ossl111, awslc))]
504    fn hash_xof_test(hashtype: MessageDigest, hashtest: &(&str, &str)) {
505        let expected = Vec::from_hex(hashtest.1).unwrap();
506        let mut buf = vec![0; expected.len()];
507        hash_xof(
508            hashtype,
509            &Vec::from_hex(hashtest.0).unwrap(),
510            buf.as_mut_slice(),
511        )
512        .unwrap();
513        assert_eq!(buf, expected);
514    }
515
516    /// Squeezes the expected length by doing two squeezes.
517    #[cfg(any(ossl330, awslc))]
518    fn hash_xof_squeeze_test(hashtype: MessageDigest, hashtest: &(&str, &str)) {
519        let data = Vec::from_hex(hashtest.0).unwrap();
520        let mut h = Hasher::new(hashtype).unwrap();
521        h.update(&data).unwrap();
522
523        let expected = Vec::from_hex(hashtest.1).unwrap();
524        let mut buf = vec![0; expected.len()];
525        assert!(expected.len() > 10);
526        h.squeeze_xof(&mut buf[..10]).unwrap();
527        h.squeeze_xof(&mut buf[10..]).unwrap();
528        assert_eq!(buf, expected);
529    }
530
531    fn hash_recycle_test(h: &mut Hasher, hashtest: &(&str, &str)) {
532        h.write_all(&Vec::from_hex(hashtest.0).unwrap()).unwrap();
533        let res = h.finish().unwrap();
534        assert_eq!(hex::encode(res), hashtest.1);
535    }
536
537    // Test vectors from http://www.nsrl.nist.gov/testdata/
538    const MD5_TESTS: [(&str, &str); 13] = [
539        ("", "d41d8cd98f00b204e9800998ecf8427e"),
540        ("7F", "83acb6e67e50e31db6ed341dd2de1595"),
541        ("EC9C", "0b07f0d4ca797d8ac58874f887cb0b68"),
542        ("FEE57A", "e0d583171eb06d56198fc0ef22173907"),
543        ("42F497E0", "7c430f178aefdf1487fee7144e9641e2"),
544        ("C53B777F1C", "75ef141d64cb37ec423da2d9d440c925"),
545        ("89D5B576327B", "ebbaf15eb0ed784c6faa9dc32831bf33"),
546        ("5D4CCE781EB190", "ce175c4b08172019f05e6b5279889f2c"),
547        ("81901FE94932D7B9", "cd4d2f62b8cdb3a0cf968a735a239281"),
548        ("C9FFDEE7788EFB4EC9", "e0841a231ab698db30c6c0f3f246c014"),
549        ("66AC4B7EBA95E53DC10B", "a3b3cea71910d9af56742aa0bb2fe329"),
550        ("A510CD18F7A56852EB0319", "577e216843dd11573574d3fb209b97d8"),
551        (
552            "AAED18DBE8938C19ED734A8D",
553            "6f80fb775f27e0a4ce5c2f42fc72c5f1",
554        ),
555    ];
556
557    #[test]
558    fn test_md5() {
559        for test in MD5_TESTS.iter() {
560            hash_test(MessageDigest::md5(), test);
561        }
562
563        assert_eq!(MessageDigest::md5().block_size(), 64);
564        assert_eq!(MessageDigest::md5().size(), 16);
565        assert_eq!(MessageDigest::md5().type_().as_raw(), Nid::MD5.as_raw());
566    }
567
568    #[test]
569    fn test_md5_recycle() {
570        let mut h = Hasher::new(MessageDigest::md5()).unwrap();
571        for test in MD5_TESTS.iter() {
572            hash_recycle_test(&mut h, test);
573        }
574    }
575
576    #[test]
577    fn test_finish_twice() {
578        let mut h = Hasher::new(MessageDigest::md5()).unwrap();
579        h.write_all(&Vec::from_hex(MD5_TESTS[6].0).unwrap())
580            .unwrap();
581        h.finish().unwrap();
582        let res = h.finish().unwrap();
583        let null = hash(MessageDigest::md5(), &[]).unwrap();
584        assert_eq!(&*res, &*null);
585    }
586
587    #[cfg(any(ossl330, awslc))]
588    #[test]
589    fn test_finish_then_squeeze() {
590        let digest = MessageDigest::shake_128();
591        let mut h = Hasher::new(digest).unwrap();
592        let mut buf = vec![0; digest.size()];
593        h.finish_xof(&mut buf).unwrap();
594        h.squeeze_xof(&mut buf)
595            .expect_err("squeezing after finalize should fail");
596    }
597
598    #[cfg(any(ossl330, awslc))]
599    #[test]
600    fn test_squeeze_then_update() {
601        let digest = MessageDigest::shake_128();
602        let data = Vec::from_hex(MD5_TESTS[6].0).unwrap();
603        let mut h = Hasher::new(digest).unwrap();
604        let mut buf = vec![0; digest.size()];
605        h.squeeze_xof(&mut buf).unwrap();
606        h.update(&data)
607            .expect_err("updating after squeeze should fail");
608    }
609
610    #[cfg(any(ossl330, awslc))]
611    #[test]
612    fn test_squeeze_then_finalize() {
613        let digest = MessageDigest::shake_128();
614        let mut h = Hasher::new(digest).unwrap();
615        let mut buf = vec![0; digest.size()];
616        h.squeeze_xof(&mut buf).unwrap();
617        if cfg!(ossl330) {
618            h.finish_xof(&mut buf)
619                .expect_err("finalize after squeeze should fail");
620        } else if cfg!(awslc) {
621            h.finish_xof(&mut buf).unwrap();
622        }
623    }
624
625    #[test]
626    #[allow(clippy::redundant_clone)]
627    fn test_clone() {
628        let i = 7;
629        let inp = Vec::from_hex(MD5_TESTS[i].0).unwrap();
630        assert!(inp.len() > 2);
631        let p = inp.len() / 2;
632        let h0 = Hasher::new(MessageDigest::md5()).unwrap();
633
634        println!("Clone a new hasher");
635        let mut h1 = h0.clone();
636        h1.write_all(&inp[..p]).unwrap();
637        {
638            println!("Clone an updated hasher");
639            let mut h2 = h1.clone();
640            h2.write_all(&inp[p..]).unwrap();
641            let res = h2.finish().unwrap();
642            assert_eq!(hex::encode(res), MD5_TESTS[i].1);
643        }
644        h1.write_all(&inp[p..]).unwrap();
645        let res = h1.finish().unwrap();
646        assert_eq!(hex::encode(res), MD5_TESTS[i].1);
647
648        println!("Clone a finished hasher");
649        let mut h3 = h1.clone();
650        h3.write_all(&Vec::from_hex(MD5_TESTS[i + 1].0).unwrap())
651            .unwrap();
652        let res = h3.finish().unwrap();
653        assert_eq!(hex::encode(res), MD5_TESTS[i + 1].1);
654    }
655
656    #[test]
657    fn test_sha1() {
658        let tests = [("616263", "a9993e364706816aba3e25717850c26c9cd0d89d")];
659
660        for test in tests.iter() {
661            hash_test(MessageDigest::sha1(), test);
662        }
663
664        assert_eq!(MessageDigest::sha1().block_size(), 64);
665        assert_eq!(MessageDigest::sha1().size(), 20);
666        assert_eq!(MessageDigest::sha1().type_().as_raw(), Nid::SHA1.as_raw());
667    }
668
669    #[test]
670    fn test_sha256() {
671        let tests = [(
672            "616263",
673            "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
674        )];
675
676        for test in tests.iter() {
677            hash_test(MessageDigest::sha256(), test);
678        }
679
680        assert_eq!(MessageDigest::sha256().block_size(), 64);
681        assert_eq!(MessageDigest::sha256().size(), 32);
682        assert_eq!(
683            MessageDigest::sha256().type_().as_raw(),
684            Nid::SHA256.as_raw()
685        );
686    }
687
688    #[test]
689    fn test_sha512() {
690        let tests = [(
691            "737465766566696e647365766572797468696e67",
692            "ba61d1f1af0f2dd80729f6cc900f19c0966bd38ba5c75e4471ef11b771dfe7551afab7fcbd300fdc4418f2\
693            b07a028fcd99e7b6446a566f2d9bcd7c604a1ea801",
694        )];
695
696        for test in tests.iter() {
697            hash_test(MessageDigest::sha512(), test);
698        }
699
700        assert_eq!(MessageDigest::sha512().block_size(), 128);
701        assert_eq!(MessageDigest::sha512().size(), 64);
702        assert_eq!(
703            MessageDigest::sha512().type_().as_raw(),
704            Nid::SHA512.as_raw()
705        );
706    }
707
708    #[cfg(any(ossl111, libressl380, awslc))]
709    #[test]
710    fn test_sha3_224() {
711        let tests = [(
712            "416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
713            "1de092dd9fbcbbf450f26264f4778abd48af851f2832924554c56913",
714        )];
715
716        for test in tests.iter() {
717            hash_test(MessageDigest::sha3_224(), test);
718        }
719
720        assert_eq!(MessageDigest::sha3_224().block_size(), 144);
721        assert_eq!(MessageDigest::sha3_224().size(), 28);
722        assert_eq!(
723            MessageDigest::sha3_224().type_().as_raw(),
724            Nid::SHA3_224.as_raw()
725        );
726    }
727
728    #[cfg(any(ossl111, libressl380, awslc))]
729    #[test]
730    fn test_sha3_256() {
731        let tests = [(
732            "416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
733            "b38e38f08bc1c0091ed4b5f060fe13e86aa4179578513ad11a6e3abba0062f61",
734        )];
735
736        for test in tests.iter() {
737            hash_test(MessageDigest::sha3_256(), test);
738        }
739
740        assert_eq!(MessageDigest::sha3_256().block_size(), 136);
741        assert_eq!(MessageDigest::sha3_256().size(), 32);
742        assert_eq!(
743            MessageDigest::sha3_256().type_().as_raw(),
744            Nid::SHA3_256.as_raw()
745        );
746    }
747
748    #[cfg(any(ossl111, libressl380, awslc))]
749    #[test]
750    fn test_sha3_384() {
751        let tests = [("416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
752            "966ee786ab3482dd811bf7c8fa8db79aa1f52f6c3c369942ef14240ebd857c6ff626ec35d9e131ff64d328\
753            ef2008ff16"
754        )];
755
756        for test in tests.iter() {
757            hash_test(MessageDigest::sha3_384(), test);
758        }
759
760        assert_eq!(MessageDigest::sha3_384().block_size(), 104);
761        assert_eq!(MessageDigest::sha3_384().size(), 48);
762        assert_eq!(
763            MessageDigest::sha3_384().type_().as_raw(),
764            Nid::SHA3_384.as_raw()
765        );
766    }
767
768    #[cfg(any(ossl111, libressl380, awslc))]
769    #[test]
770    fn test_sha3_512() {
771        let tests = [("416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
772            "c072288ef728cd53a029c47687960b9225893532f42b923156e37020bdc1eda753aafbf30af859d4f4c3a1\
773            807caee3a79f8eb02dcd61589fbbdf5f40c8787a72"
774        )];
775
776        for test in tests.iter() {
777            hash_test(MessageDigest::sha3_512(), test);
778        }
779
780        assert_eq!(MessageDigest::sha3_512().block_size(), 72);
781        assert_eq!(MessageDigest::sha3_512().size(), 64);
782        assert_eq!(
783            MessageDigest::sha3_512().type_().as_raw(),
784            Nid::SHA3_512.as_raw()
785        );
786    }
787
788    #[cfg(any(ossl111, awslc))]
789    #[test]
790    fn test_shake_128() {
791        let tests = [(
792            "416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
793            "49d0697ff508111d8b84f15e46daf135",
794        )];
795
796        for test in tests.iter() {
797            hash_xof_test(MessageDigest::shake_128(), test);
798            #[cfg(any(ossl330, awslc))]
799            hash_xof_squeeze_test(MessageDigest::shake_128(), test);
800        }
801
802        assert_eq!(MessageDigest::shake_128().block_size(), 168);
803        #[cfg(ossl111)]
804        assert_eq!(MessageDigest::shake_128().size(), 16);
805        #[cfg(awslc)]
806        assert_eq!(MessageDigest::shake_128().size(), 0);
807        assert_eq!(
808            MessageDigest::shake_128().type_().as_raw(),
809            Nid::SHAKE128.as_raw()
810        );
811    }
812
813    #[cfg(any(ossl111, awslc))]
814    #[test]
815    fn test_shake_256() {
816        let tests = [(
817            "416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
818            "4e2dfdaa75d1e049d0eaeffe28e76b17cea47b650fb8826fe48b94664326a697",
819        )];
820
821        for test in tests.iter() {
822            hash_xof_test(MessageDigest::shake_256(), test);
823            #[cfg(any(ossl330, awslc))]
824            hash_xof_squeeze_test(MessageDigest::shake_256(), test);
825        }
826
827        assert_eq!(MessageDigest::shake_256().block_size(), 136);
828        #[cfg(ossl111)]
829        assert_eq!(MessageDigest::shake_256().size(), 32);
830        #[cfg(awslc)]
831        assert_eq!(MessageDigest::shake_256().size(), 0);
832        assert_eq!(
833            MessageDigest::shake_256().type_().as_raw(),
834            Nid::SHAKE256.as_raw()
835        );
836    }
837
838    #[test]
839    #[cfg(not(osslconf = "OPENSSL_NO_RMD160"))]
840    #[cfg_attr(ossl300, ignore)]
841    fn test_ripemd160() {
842        #[cfg(ossl300)]
843        let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap();
844
845        let tests = [("616263", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc")];
846
847        for test in tests.iter() {
848            hash_test(MessageDigest::ripemd160(), test);
849        }
850
851        assert_eq!(MessageDigest::ripemd160().block_size(), 64);
852        assert_eq!(MessageDigest::ripemd160().size(), 20);
853        assert_eq!(
854            MessageDigest::ripemd160().type_().as_raw(),
855            Nid::RIPEMD160.as_raw()
856        );
857    }
858
859    #[cfg(all(any(ossl111, libressl), not(osslconf = "OPENSSL_NO_SM3")))]
860    #[test]
861    fn test_sm3() {
862        let tests = [(
863            "616263",
864            "66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0",
865        )];
866
867        for test in tests.iter() {
868            hash_test(MessageDigest::sm3(), test);
869        }
870
871        assert_eq!(MessageDigest::sm3().block_size(), 64);
872        assert_eq!(MessageDigest::sm3().size(), 32);
873        assert_eq!(MessageDigest::sm3().type_().as_raw(), Nid::SM3.as_raw());
874    }
875
876    #[test]
877    fn from_nid() {
878        assert_eq!(
879            MessageDigest::from_nid(Nid::SHA256).unwrap().as_ptr(),
880            MessageDigest::sha256().as_ptr()
881        );
882    }
883
884    #[test]
885    fn from_name() {
886        assert_eq!(
887            MessageDigest::from_name("SHA256").unwrap().as_ptr(),
888            MessageDigest::sha256().as_ptr()
889        )
890    }
891}