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