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