Skip to main content

variant_ssl/
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`] implementation 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, all(awslc, not(awslc_fips))))]
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
495    use super::*;
496
497    fn hash_test(hashtype: MessageDigest, hashtest: &(&str, &str)) {
498        let res = hash(hashtype, &Vec::from_hex(hashtest.0).unwrap()).unwrap();
499        assert_eq!(hex::encode(res), hashtest.1);
500    }
501
502    #[cfg(any(ossl111, awslc))]
503    fn hash_xof_test(hashtype: MessageDigest, hashtest: &(&str, &str)) {
504        let expected = Vec::from_hex(hashtest.1).unwrap();
505        let mut buf = vec![0; expected.len()];
506        hash_xof(
507            hashtype,
508            &Vec::from_hex(hashtest.0).unwrap(),
509            buf.as_mut_slice(),
510        )
511        .unwrap();
512        assert_eq!(buf, expected);
513    }
514
515    /// Squeezes the expected length by doing two squeezes.
516    #[cfg(any(ossl330, all(awslc, not(awslc_fips))))]
517    fn hash_xof_squeeze_test(hashtype: MessageDigest, hashtest: &(&str, &str)) {
518        let data = Vec::from_hex(hashtest.0).unwrap();
519        let mut h = Hasher::new(hashtype).unwrap();
520        h.update(&data).unwrap();
521
522        let expected = Vec::from_hex(hashtest.1).unwrap();
523        let mut buf = vec![0; expected.len()];
524        assert!(expected.len() > 10);
525        h.squeeze_xof(&mut buf[..10]).unwrap();
526        h.squeeze_xof(&mut buf[10..]).unwrap();
527        assert_eq!(buf, expected);
528    }
529
530    fn hash_recycle_test(h: &mut Hasher, hashtest: &(&str, &str)) {
531        h.write_all(&Vec::from_hex(hashtest.0).unwrap()).unwrap();
532        let res = h.finish().unwrap();
533        assert_eq!(hex::encode(res), hashtest.1);
534    }
535
536    // Test vectors from http://www.nsrl.nist.gov/testdata/
537    const MD5_TESTS: [(&str, &str); 13] = [
538        ("", "d41d8cd98f00b204e9800998ecf8427e"),
539        ("7F", "83acb6e67e50e31db6ed341dd2de1595"),
540        ("EC9C", "0b07f0d4ca797d8ac58874f887cb0b68"),
541        ("FEE57A", "e0d583171eb06d56198fc0ef22173907"),
542        ("42F497E0", "7c430f178aefdf1487fee7144e9641e2"),
543        ("C53B777F1C", "75ef141d64cb37ec423da2d9d440c925"),
544        ("89D5B576327B", "ebbaf15eb0ed784c6faa9dc32831bf33"),
545        ("5D4CCE781EB190", "ce175c4b08172019f05e6b5279889f2c"),
546        ("81901FE94932D7B9", "cd4d2f62b8cdb3a0cf968a735a239281"),
547        ("C9FFDEE7788EFB4EC9", "e0841a231ab698db30c6c0f3f246c014"),
548        ("66AC4B7EBA95E53DC10B", "a3b3cea71910d9af56742aa0bb2fe329"),
549        ("A510CD18F7A56852EB0319", "577e216843dd11573574d3fb209b97d8"),
550        (
551            "AAED18DBE8938C19ED734A8D",
552            "6f80fb775f27e0a4ce5c2f42fc72c5f1",
553        ),
554    ];
555
556    #[test]
557    fn test_md5() {
558        for test in MD5_TESTS.iter() {
559            hash_test(MessageDigest::md5(), test);
560        }
561
562        assert_eq!(MessageDigest::md5().block_size(), 64);
563        assert_eq!(MessageDigest::md5().size(), 16);
564        assert_eq!(MessageDigest::md5().type_().as_raw(), Nid::MD5.as_raw());
565    }
566
567    #[test]
568    fn test_md5_recycle() {
569        let mut h = Hasher::new(MessageDigest::md5()).unwrap();
570        for test in MD5_TESTS.iter() {
571            hash_recycle_test(&mut h, test);
572        }
573    }
574
575    #[test]
576    fn test_finish_twice() {
577        let mut h = Hasher::new(MessageDigest::md5()).unwrap();
578        h.write_all(&Vec::from_hex(MD5_TESTS[6].0).unwrap())
579            .unwrap();
580        h.finish().unwrap();
581        let res = h.finish().unwrap();
582        let null = hash(MessageDigest::md5(), &[]).unwrap();
583        assert_eq!(&*res, &*null);
584    }
585
586    #[cfg(any(ossl330, all(awslc, not(awslc_fips))))]
587    #[test]
588    fn test_finish_then_squeeze() {
589        let digest = MessageDigest::shake_128();
590        let mut h = Hasher::new(digest).unwrap();
591        let mut buf = vec![0; digest.size()];
592        h.finish_xof(&mut buf).unwrap();
593        h.squeeze_xof(&mut buf)
594            .expect_err("squeezing after finalize should fail");
595    }
596
597    #[cfg(any(ossl330, all(awslc, not(awslc_fips))))]
598    #[test]
599    fn test_squeeze_then_update() {
600        let digest = MessageDigest::shake_128();
601        let data = Vec::from_hex(MD5_TESTS[6].0).unwrap();
602        let mut h = Hasher::new(digest).unwrap();
603        let mut buf = vec![0; digest.size()];
604        h.squeeze_xof(&mut buf).unwrap();
605        h.update(&data)
606            .expect_err("updating after squeeze should fail");
607    }
608
609    #[cfg(any(ossl330, all(awslc, not(awslc_fips))))]
610    #[test]
611    fn test_squeeze_then_finalize() {
612        let digest = MessageDigest::shake_128();
613        let mut h = Hasher::new(digest).unwrap();
614        let mut buf = vec![0; digest.size()];
615        h.squeeze_xof(&mut buf).unwrap();
616        if cfg!(ossl330) {
617            h.finish_xof(&mut buf)
618                .expect_err("finalize after squeeze should fail");
619        } else if cfg!(awslc) {
620            h.finish_xof(&mut buf).unwrap();
621        }
622    }
623
624    #[test]
625    #[allow(clippy::redundant_clone)]
626    fn test_clone() {
627        let i = 7;
628        let inp = Vec::from_hex(MD5_TESTS[i].0).unwrap();
629        assert!(inp.len() > 2);
630        let p = inp.len() / 2;
631        let h0 = Hasher::new(MessageDigest::md5()).unwrap();
632
633        println!("Clone a new hasher");
634        let mut h1 = h0.clone();
635        h1.write_all(&inp[..p]).unwrap();
636        {
637            println!("Clone an updated hasher");
638            let mut h2 = h1.clone();
639            h2.write_all(&inp[p..]).unwrap();
640            let res = h2.finish().unwrap();
641            assert_eq!(hex::encode(res), MD5_TESTS[i].1);
642        }
643        h1.write_all(&inp[p..]).unwrap();
644        let res = h1.finish().unwrap();
645        assert_eq!(hex::encode(res), MD5_TESTS[i].1);
646
647        println!("Clone a finished hasher");
648        let mut h3 = h1.clone();
649        h3.write_all(&Vec::from_hex(MD5_TESTS[i + 1].0).unwrap())
650            .unwrap();
651        let res = h3.finish().unwrap();
652        assert_eq!(hex::encode(res), MD5_TESTS[i + 1].1);
653    }
654
655    #[test]
656    fn test_sha1() {
657        let tests = [("616263", "a9993e364706816aba3e25717850c26c9cd0d89d")];
658
659        for test in tests.iter() {
660            hash_test(MessageDigest::sha1(), test);
661        }
662
663        assert_eq!(MessageDigest::sha1().block_size(), 64);
664        assert_eq!(MessageDigest::sha1().size(), 20);
665        assert_eq!(MessageDigest::sha1().type_().as_raw(), Nid::SHA1.as_raw());
666    }
667
668    #[test]
669    fn test_sha256() {
670        let tests = [(
671            "616263",
672            "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
673        )];
674
675        for test in tests.iter() {
676            hash_test(MessageDigest::sha256(), test);
677        }
678
679        assert_eq!(MessageDigest::sha256().block_size(), 64);
680        assert_eq!(MessageDigest::sha256().size(), 32);
681        assert_eq!(
682            MessageDigest::sha256().type_().as_raw(),
683            Nid::SHA256.as_raw()
684        );
685    }
686
687    #[test]
688    fn test_sha512() {
689        let tests = [(
690            "737465766566696e647365766572797468696e67",
691            "ba61d1f1af0f2dd80729f6cc900f19c0966bd38ba5c75e4471ef11b771dfe7551afab7fcbd300fdc4418f2\
692            b07a028fcd99e7b6446a566f2d9bcd7c604a1ea801",
693        )];
694
695        for test in tests.iter() {
696            hash_test(MessageDigest::sha512(), test);
697        }
698
699        assert_eq!(MessageDigest::sha512().block_size(), 128);
700        assert_eq!(MessageDigest::sha512().size(), 64);
701        assert_eq!(
702            MessageDigest::sha512().type_().as_raw(),
703            Nid::SHA512.as_raw()
704        );
705    }
706
707    #[cfg(any(ossl111, libressl380, awslc))]
708    #[test]
709    fn test_sha3_224() {
710        let tests = [(
711            "416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
712            "1de092dd9fbcbbf450f26264f4778abd48af851f2832924554c56913",
713        )];
714
715        for test in tests.iter() {
716            hash_test(MessageDigest::sha3_224(), test);
717        }
718
719        assert_eq!(MessageDigest::sha3_224().block_size(), 144);
720        assert_eq!(MessageDigest::sha3_224().size(), 28);
721        assert_eq!(
722            MessageDigest::sha3_224().type_().as_raw(),
723            Nid::SHA3_224.as_raw()
724        );
725    }
726
727    #[cfg(any(ossl111, libressl380, awslc))]
728    #[test]
729    fn test_sha3_256() {
730        let tests = [(
731            "416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
732            "b38e38f08bc1c0091ed4b5f060fe13e86aa4179578513ad11a6e3abba0062f61",
733        )];
734
735        for test in tests.iter() {
736            hash_test(MessageDigest::sha3_256(), test);
737        }
738
739        assert_eq!(MessageDigest::sha3_256().block_size(), 136);
740        assert_eq!(MessageDigest::sha3_256().size(), 32);
741        assert_eq!(
742            MessageDigest::sha3_256().type_().as_raw(),
743            Nid::SHA3_256.as_raw()
744        );
745    }
746
747    #[cfg(any(ossl111, libressl380, awslc))]
748    #[test]
749    fn test_sha3_384() {
750        let tests = [("416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
751            "966ee786ab3482dd811bf7c8fa8db79aa1f52f6c3c369942ef14240ebd857c6ff626ec35d9e131ff64d328\
752            ef2008ff16"
753        )];
754
755        for test in tests.iter() {
756            hash_test(MessageDigest::sha3_384(), test);
757        }
758
759        assert_eq!(MessageDigest::sha3_384().block_size(), 104);
760        assert_eq!(MessageDigest::sha3_384().size(), 48);
761        assert_eq!(
762            MessageDigest::sha3_384().type_().as_raw(),
763            Nid::SHA3_384.as_raw()
764        );
765    }
766
767    #[cfg(any(ossl111, libressl380, awslc))]
768    #[test]
769    fn test_sha3_512() {
770        let tests = [("416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
771            "c072288ef728cd53a029c47687960b9225893532f42b923156e37020bdc1eda753aafbf30af859d4f4c3a1\
772            807caee3a79f8eb02dcd61589fbbdf5f40c8787a72"
773        )];
774
775        for test in tests.iter() {
776            hash_test(MessageDigest::sha3_512(), test);
777        }
778
779        assert_eq!(MessageDigest::sha3_512().block_size(), 72);
780        assert_eq!(MessageDigest::sha3_512().size(), 64);
781        assert_eq!(
782            MessageDigest::sha3_512().type_().as_raw(),
783            Nid::SHA3_512.as_raw()
784        );
785    }
786
787    #[cfg(any(ossl111, awslc))]
788    #[test]
789    fn test_shake_128() {
790        let tests = [(
791            "416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
792            "49d0697ff508111d8b84f15e46daf135",
793        )];
794
795        for test in tests.iter() {
796            hash_xof_test(MessageDigest::shake_128(), test);
797            #[cfg(any(ossl330, all(awslc, not(awslc_fips))))]
798            hash_xof_squeeze_test(MessageDigest::shake_128(), test);
799        }
800
801        assert_eq!(MessageDigest::shake_128().block_size(), 168);
802        #[cfg(ossl111)]
803        assert_eq!(MessageDigest::shake_128().size(), 16);
804        #[cfg(awslc)]
805        assert_eq!(MessageDigest::shake_128().size(), 0);
806        assert_eq!(
807            MessageDigest::shake_128().type_().as_raw(),
808            Nid::SHAKE128.as_raw()
809        );
810    }
811
812    #[cfg(any(ossl111, awslc))]
813    #[test]
814    fn test_shake_256() {
815        let tests = [(
816            "416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
817            "4e2dfdaa75d1e049d0eaeffe28e76b17cea47b650fb8826fe48b94664326a697",
818        )];
819
820        for test in tests.iter() {
821            hash_xof_test(MessageDigest::shake_256(), test);
822            #[cfg(any(ossl330, all(awslc, not(awslc_fips))))]
823            hash_xof_squeeze_test(MessageDigest::shake_256(), test);
824        }
825
826        assert_eq!(MessageDigest::shake_256().block_size(), 136);
827        #[cfg(ossl111)]
828        assert_eq!(MessageDigest::shake_256().size(), 32);
829        #[cfg(awslc)]
830        assert_eq!(MessageDigest::shake_256().size(), 0);
831        assert_eq!(
832            MessageDigest::shake_256().type_().as_raw(),
833            Nid::SHAKE256.as_raw()
834        );
835    }
836
837    #[test]
838    #[cfg(not(osslconf = "OPENSSL_NO_RMD160"))]
839    #[cfg_attr(ossl300, ignore)]
840    fn test_ripemd160() {
841        #[cfg(ossl300)]
842        let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap();
843
844        let tests = [("616263", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc")];
845
846        for test in tests.iter() {
847            hash_test(MessageDigest::ripemd160(), test);
848        }
849
850        assert_eq!(MessageDigest::ripemd160().block_size(), 64);
851        assert_eq!(MessageDigest::ripemd160().size(), 20);
852        assert_eq!(
853            MessageDigest::ripemd160().type_().as_raw(),
854            Nid::RIPEMD160.as_raw()
855        );
856    }
857
858    #[cfg(all(any(ossl111, libressl), not(osslconf = "OPENSSL_NO_SM3")))]
859    #[test]
860    fn test_sm3() {
861        let tests = [(
862            "616263",
863            "66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0",
864        )];
865
866        for test in tests.iter() {
867            hash_test(MessageDigest::sm3(), test);
868        }
869
870        assert_eq!(MessageDigest::sm3().block_size(), 64);
871        assert_eq!(MessageDigest::sm3().size(), 32);
872        assert_eq!(MessageDigest::sm3().type_().as_raw(), Nid::SM3.as_raw());
873    }
874
875    #[test]
876    fn from_nid() {
877        assert_eq!(
878            MessageDigest::from_nid(Nid::SHA256).unwrap().as_ptr(),
879            MessageDigest::sha256().as_ptr()
880        );
881    }
882
883    #[test]
884    fn from_name() {
885        assert_eq!(
886            MessageDigest::from_name("SHA256").unwrap().as_ptr(),
887            MessageDigest::sha256().as_ptr()
888        )
889    }
890}