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, 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    #[cfg(ossl330)]
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(ossl330)]
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(ossl330)]
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(ossl330)]
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(ossl330)]
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(ossl330)]
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(ossl330)]
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(ossl330)]
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        h.finish_xof(&mut buf)
618            .expect_err("finalize after squeeze should fail");
619    }
620
621    #[test]
622    #[allow(clippy::redundant_clone)]
623    fn test_clone() {
624        let i = 7;
625        let inp = Vec::from_hex(MD5_TESTS[i].0).unwrap();
626        assert!(inp.len() > 2);
627        let p = inp.len() / 2;
628        let h0 = Hasher::new(MessageDigest::md5()).unwrap();
629
630        println!("Clone a new hasher");
631        let mut h1 = h0.clone();
632        h1.write_all(&inp[..p]).unwrap();
633        {
634            println!("Clone an updated hasher");
635            let mut h2 = h1.clone();
636            h2.write_all(&inp[p..]).unwrap();
637            let res = h2.finish().unwrap();
638            assert_eq!(hex::encode(res), MD5_TESTS[i].1);
639        }
640        h1.write_all(&inp[p..]).unwrap();
641        let res = h1.finish().unwrap();
642        assert_eq!(hex::encode(res), MD5_TESTS[i].1);
643
644        println!("Clone a finished hasher");
645        let mut h3 = h1.clone();
646        h3.write_all(&Vec::from_hex(MD5_TESTS[i + 1].0).unwrap())
647            .unwrap();
648        let res = h3.finish().unwrap();
649        assert_eq!(hex::encode(res), MD5_TESTS[i + 1].1);
650    }
651
652    #[test]
653    fn test_sha1() {
654        let tests = [("616263", "a9993e364706816aba3e25717850c26c9cd0d89d")];
655
656        for test in tests.iter() {
657            hash_test(MessageDigest::sha1(), test);
658        }
659
660        assert_eq!(MessageDigest::sha1().block_size(), 64);
661        assert_eq!(MessageDigest::sha1().size(), 20);
662        assert_eq!(MessageDigest::sha1().type_().as_raw(), Nid::SHA1.as_raw());
663    }
664
665    #[test]
666    fn test_sha256() {
667        let tests = [(
668            "616263",
669            "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
670        )];
671
672        for test in tests.iter() {
673            hash_test(MessageDigest::sha256(), test);
674        }
675
676        assert_eq!(MessageDigest::sha256().block_size(), 64);
677        assert_eq!(MessageDigest::sha256().size(), 32);
678        assert_eq!(
679            MessageDigest::sha256().type_().as_raw(),
680            Nid::SHA256.as_raw()
681        );
682    }
683
684    #[test]
685    fn test_sha512() {
686        let tests = [(
687            "737465766566696e647365766572797468696e67",
688            "ba61d1f1af0f2dd80729f6cc900f19c0966bd38ba5c75e4471ef11b771dfe7551afab7fcbd300fdc4418f2\
689            b07a028fcd99e7b6446a566f2d9bcd7c604a1ea801",
690        )];
691
692        for test in tests.iter() {
693            hash_test(MessageDigest::sha512(), test);
694        }
695
696        assert_eq!(MessageDigest::sha512().block_size(), 128);
697        assert_eq!(MessageDigest::sha512().size(), 64);
698        assert_eq!(
699            MessageDigest::sha512().type_().as_raw(),
700            Nid::SHA512.as_raw()
701        );
702    }
703
704    #[cfg(any(ossl111, libressl380, awslc))]
705    #[test]
706    fn test_sha3_224() {
707        let tests = [(
708            "416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
709            "1de092dd9fbcbbf450f26264f4778abd48af851f2832924554c56913",
710        )];
711
712        for test in tests.iter() {
713            hash_test(MessageDigest::sha3_224(), test);
714        }
715
716        assert_eq!(MessageDigest::sha3_224().block_size(), 144);
717        assert_eq!(MessageDigest::sha3_224().size(), 28);
718        assert_eq!(
719            MessageDigest::sha3_224().type_().as_raw(),
720            Nid::SHA3_224.as_raw()
721        );
722    }
723
724    #[cfg(any(ossl111, libressl380, awslc))]
725    #[test]
726    fn test_sha3_256() {
727        let tests = [(
728            "416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
729            "b38e38f08bc1c0091ed4b5f060fe13e86aa4179578513ad11a6e3abba0062f61",
730        )];
731
732        for test in tests.iter() {
733            hash_test(MessageDigest::sha3_256(), test);
734        }
735
736        assert_eq!(MessageDigest::sha3_256().block_size(), 136);
737        assert_eq!(MessageDigest::sha3_256().size(), 32);
738        assert_eq!(
739            MessageDigest::sha3_256().type_().as_raw(),
740            Nid::SHA3_256.as_raw()
741        );
742    }
743
744    #[cfg(any(ossl111, libressl380, awslc))]
745    #[test]
746    fn test_sha3_384() {
747        let tests = [("416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
748            "966ee786ab3482dd811bf7c8fa8db79aa1f52f6c3c369942ef14240ebd857c6ff626ec35d9e131ff64d328\
749            ef2008ff16"
750        )];
751
752        for test in tests.iter() {
753            hash_test(MessageDigest::sha3_384(), test);
754        }
755
756        assert_eq!(MessageDigest::sha3_384().block_size(), 104);
757        assert_eq!(MessageDigest::sha3_384().size(), 48);
758        assert_eq!(
759            MessageDigest::sha3_384().type_().as_raw(),
760            Nid::SHA3_384.as_raw()
761        );
762    }
763
764    #[cfg(any(ossl111, libressl380, awslc))]
765    #[test]
766    fn test_sha3_512() {
767        let tests = [("416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
768            "c072288ef728cd53a029c47687960b9225893532f42b923156e37020bdc1eda753aafbf30af859d4f4c3a1\
769            807caee3a79f8eb02dcd61589fbbdf5f40c8787a72"
770        )];
771
772        for test in tests.iter() {
773            hash_test(MessageDigest::sha3_512(), test);
774        }
775
776        assert_eq!(MessageDigest::sha3_512().block_size(), 72);
777        assert_eq!(MessageDigest::sha3_512().size(), 64);
778        assert_eq!(
779            MessageDigest::sha3_512().type_().as_raw(),
780            Nid::SHA3_512.as_raw()
781        );
782    }
783
784    #[cfg(any(ossl111, awslc))]
785    #[test]
786    fn test_shake_128() {
787        let tests = [(
788            "416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
789            "49d0697ff508111d8b84f15e46daf135",
790        )];
791
792        for test in tests.iter() {
793            hash_xof_test(MessageDigest::shake_128(), test);
794            #[cfg(ossl330)]
795            hash_xof_squeeze_test(MessageDigest::shake_128(), test);
796        }
797
798        assert_eq!(MessageDigest::shake_128().block_size(), 168);
799        #[cfg(ossl111)]
800        assert_eq!(MessageDigest::shake_128().size(), 16);
801        #[cfg(awslc)]
802        assert_eq!(MessageDigest::shake_128().size(), 0);
803        assert_eq!(
804            MessageDigest::shake_128().type_().as_raw(),
805            Nid::SHAKE128.as_raw()
806        );
807    }
808
809    #[cfg(any(ossl111, awslc))]
810    #[test]
811    fn test_shake_256() {
812        let tests = [(
813            "416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
814            "4e2dfdaa75d1e049d0eaeffe28e76b17cea47b650fb8826fe48b94664326a697",
815        )];
816
817        for test in tests.iter() {
818            hash_xof_test(MessageDigest::shake_256(), test);
819            #[cfg(ossl330)]
820            hash_xof_squeeze_test(MessageDigest::shake_256(), test);
821        }
822
823        assert_eq!(MessageDigest::shake_256().block_size(), 136);
824        #[cfg(ossl111)]
825        assert_eq!(MessageDigest::shake_256().size(), 32);
826        #[cfg(awslc)]
827        assert_eq!(MessageDigest::shake_256().size(), 0);
828        assert_eq!(
829            MessageDigest::shake_256().type_().as_raw(),
830            Nid::SHAKE256.as_raw()
831        );
832    }
833
834    #[test]
835    #[cfg(not(osslconf = "OPENSSL_NO_RMD160"))]
836    #[cfg_attr(ossl300, ignore)]
837    fn test_ripemd160() {
838        #[cfg(ossl300)]
839        let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap();
840
841        let tests = [("616263", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc")];
842
843        for test in tests.iter() {
844            hash_test(MessageDigest::ripemd160(), test);
845        }
846
847        assert_eq!(MessageDigest::ripemd160().block_size(), 64);
848        assert_eq!(MessageDigest::ripemd160().size(), 20);
849        assert_eq!(
850            MessageDigest::ripemd160().type_().as_raw(),
851            Nid::RIPEMD160.as_raw()
852        );
853    }
854
855    #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM3")))]
856    #[test]
857    fn test_sm3() {
858        let tests = [(
859            "616263",
860            "66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0",
861        )];
862
863        for test in tests.iter() {
864            hash_test(MessageDigest::sm3(), test);
865        }
866
867        assert_eq!(MessageDigest::sm3().block_size(), 64);
868        assert_eq!(MessageDigest::sm3().size(), 32);
869        assert_eq!(MessageDigest::sm3().type_().as_raw(), Nid::SM3.as_raw());
870    }
871
872    #[test]
873    fn from_nid() {
874        assert_eq!(
875            MessageDigest::from_nid(Nid::SHA256).unwrap().as_ptr(),
876            MessageDigest::sha256().as_ptr()
877        );
878    }
879
880    #[test]
881    fn from_name() {
882        assert_eq!(
883            MessageDigest::from_name("SHA256").unwrap().as_ptr(),
884            MessageDigest::sha256().as_ptr()
885        )
886    }
887}