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