1 use ffi;
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 error::ErrorStack;
10 use nid::Nid;
11 use {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     #[allow(clippy::trivially_copy_pass_by_ref)]
as_ptr(&self) -> *const ffi::EVP_MD132     pub fn as_ptr(&self) -> *const ffi::EVP_MD {
133         self.0
134     }
135 
136     /// The size of the digest in bytes.
137     #[allow(clippy::trivially_copy_pass_by_ref)]
size(&self) -> usize138     pub fn size(&self) -> usize {
139         unsafe { ffi::EVP_MD_size(self.0) as usize }
140     }
141 
142     /// The name of the digest.
143     #[allow(clippy::trivially_copy_pass_by_ref)]
type_(&self) -> Nid144     pub fn type_(&self) -> Nid {
145         Nid::from_raw(unsafe { ffi::EVP_MD_type(self.0) })
146     }
147 }
148 
149 unsafe impl Sync for MessageDigest {}
150 unsafe impl Send for MessageDigest {}
151 
152 #[derive(PartialEq, Copy, Clone)]
153 enum State {
154     Reset,
155     Updated,
156     Finalized,
157 }
158 
159 use self::State::*;
160 
161 /// Provides message digest (hash) computation.
162 ///
163 /// # Examples
164 ///
165 /// Calculate a hash in one go:
166 ///
167 /// ```
168 /// use openssl::hash::{hash, MessageDigest};
169 ///
170 /// let data = b"\x42\xF4\x97\xE0";
171 /// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2";
172 /// let res = hash(MessageDigest::md5(), data).unwrap();
173 /// assert_eq!(&*res, spec);
174 /// ```
175 ///
176 /// Supply the input in chunks:
177 ///
178 /// ```
179 /// use openssl::hash::{Hasher, MessageDigest};
180 ///
181 /// let data = [b"\x42\xF4", b"\x97\xE0"];
182 /// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2";
183 /// let mut h = Hasher::new(MessageDigest::md5()).unwrap();
184 /// h.update(data[0]).unwrap();
185 /// h.update(data[1]).unwrap();
186 /// let res = h.finish().unwrap();
187 /// assert_eq!(&*res, spec);
188 /// ```
189 ///
190 /// Use an XOF hasher (OpenSSL 1.1.1+):
191 ///
192 /// ```
193 /// #[cfg(ossl111)]
194 /// {
195 ///     use openssl::hash::{hash_xof, MessageDigest};
196 ///
197 ///     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";
198 ///     let spec = b"\x49\xd0\x69\x7f\xf5\x08\x11\x1d\x8b\x84\xf1\x5e\x46\xda\xf1\x35";
199 ///     let mut buf = vec![0; 16];
200 ///     hash_xof(MessageDigest::shake_128(), data, buf.as_mut_slice()).unwrap();
201 ///     assert_eq!(buf, spec);
202 /// }
203 /// ```
204 ///
205 /// # Warning
206 ///
207 /// Don't actually use MD5 and SHA-1 hashes, they're not secure anymore.
208 ///
209 /// Don't ever hash passwords, use the functions in the `pkcs5` module or bcrypt/scrypt instead.
210 ///
211 /// For extendable output functions (XOFs, i.e. SHAKE128/SHAKE256), you must use finish_xof instead
212 /// of finish and provide a buf to store the hash. The hash will be as long as the buf.
213 pub struct Hasher {
214     ctx: *mut ffi::EVP_MD_CTX,
215     md: *const ffi::EVP_MD,
216     type_: MessageDigest,
217     state: State,
218 }
219 
220 unsafe impl Sync for Hasher {}
221 unsafe impl Send for Hasher {}
222 
223 impl Hasher {
224     /// Creates a new `Hasher` with the specified hash type.
new(ty: MessageDigest) -> Result<Hasher, ErrorStack>225     pub fn new(ty: MessageDigest) -> Result<Hasher, ErrorStack> {
226         ffi::init();
227 
228         let ctx = unsafe { cvt_p(EVP_MD_CTX_new())? };
229 
230         let mut h = Hasher {
231             ctx,
232             md: ty.as_ptr(),
233             type_: ty,
234             state: Finalized,
235         };
236         h.init()?;
237         Ok(h)
238     }
239 
init(&mut self) -> Result<(), ErrorStack>240     fn init(&mut self) -> Result<(), ErrorStack> {
241         match self.state {
242             Reset => return Ok(()),
243             Updated => {
244                 self.finish()?;
245             }
246             Finalized => (),
247         }
248         unsafe {
249             cvt(ffi::EVP_DigestInit_ex(self.ctx, self.md, ptr::null_mut()))?;
250         }
251         self.state = Reset;
252         Ok(())
253     }
254 
255     /// Feeds data into the hasher.
update(&mut self, data: &[u8]) -> Result<(), ErrorStack>256     pub fn update(&mut self, data: &[u8]) -> Result<(), ErrorStack> {
257         if self.state == Finalized {
258             self.init()?;
259         }
260         unsafe {
261             cvt(ffi::EVP_DigestUpdate(
262                 self.ctx,
263                 data.as_ptr() as *mut _,
264                 data.len(),
265             ))?;
266         }
267         self.state = Updated;
268         Ok(())
269     }
270 
271     /// Returns the hash of the data written and resets the non-XOF hasher.
finish(&mut self) -> Result<DigestBytes, ErrorStack>272     pub fn finish(&mut self) -> Result<DigestBytes, ErrorStack> {
273         if self.state == Finalized {
274             self.init()?;
275         }
276         unsafe {
277             let mut len = ffi::EVP_MAX_MD_SIZE;
278             let mut buf = [0; ffi::EVP_MAX_MD_SIZE as usize];
279             cvt(ffi::EVP_DigestFinal_ex(
280                 self.ctx,
281                 buf.as_mut_ptr(),
282                 &mut len,
283             ))?;
284             self.state = Finalized;
285             Ok(DigestBytes {
286                 buf,
287                 len: len as usize,
288             })
289         }
290     }
291 
292     /// Writes the hash of the data into the supplied buf and resets the XOF hasher.
293     /// The hash will be as long as the buf.
294     #[cfg(ossl111)]
finish_xof(&mut self, buf: &mut [u8]) -> Result<(), ErrorStack>295     pub fn finish_xof(&mut self, buf: &mut [u8]) -> Result<(), ErrorStack> {
296         if self.state == Finalized {
297             self.init()?;
298         }
299         unsafe {
300             cvt(ffi::EVP_DigestFinalXOF(
301                 self.ctx,
302                 buf.as_mut_ptr(),
303                 buf.len(),
304             ))?;
305             self.state = Finalized;
306             Ok(())
307         }
308     }
309 }
310 
311 impl Write for Hasher {
312     #[inline]
write(&mut self, buf: &[u8]) -> io::Result<usize>313     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
314         self.update(buf)?;
315         Ok(buf.len())
316     }
317 
flush(&mut self) -> io::Result<()>318     fn flush(&mut self) -> io::Result<()> {
319         Ok(())
320     }
321 }
322 
323 impl Clone for Hasher {
clone(&self) -> Hasher324     fn clone(&self) -> Hasher {
325         let ctx = unsafe {
326             let ctx = EVP_MD_CTX_new();
327             assert!(!ctx.is_null());
328             let r = ffi::EVP_MD_CTX_copy_ex(ctx, self.ctx);
329             assert_eq!(r, 1);
330             ctx
331         };
332         Hasher {
333             ctx,
334             md: self.md,
335             type_: self.type_,
336             state: self.state,
337         }
338     }
339 }
340 
341 impl Drop for Hasher {
drop(&mut self)342     fn drop(&mut self) {
343         unsafe {
344             if self.state != Finalized {
345                 drop(self.finish());
346             }
347             EVP_MD_CTX_free(self.ctx);
348         }
349     }
350 }
351 
352 /// The resulting bytes of a digest.
353 ///
354 /// This type derefs to a byte slice - it exists to avoid allocating memory to
355 /// store the digest data.
356 #[derive(Copy)]
357 pub struct DigestBytes {
358     pub(crate) buf: [u8; ffi::EVP_MAX_MD_SIZE as usize],
359     pub(crate) len: usize,
360 }
361 
362 impl Clone for DigestBytes {
363     #[inline]
clone(&self) -> DigestBytes364     fn clone(&self) -> DigestBytes {
365         *self
366     }
367 }
368 
369 impl Deref for DigestBytes {
370     type Target = [u8];
371 
372     #[inline]
deref(&self) -> &[u8]373     fn deref(&self) -> &[u8] {
374         &self.buf[..self.len]
375     }
376 }
377 
378 impl DerefMut for DigestBytes {
379     #[inline]
deref_mut(&mut self) -> &mut [u8]380     fn deref_mut(&mut self) -> &mut [u8] {
381         &mut self.buf[..self.len]
382     }
383 }
384 
385 impl AsRef<[u8]> for DigestBytes {
386     #[inline]
as_ref(&self) -> &[u8]387     fn as_ref(&self) -> &[u8] {
388         self.deref()
389     }
390 }
391 
392 impl fmt::Debug for DigestBytes {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result393     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
394         fmt::Debug::fmt(&**self, fmt)
395     }
396 }
397 
398 /// Computes the hash of the `data` with the non-XOF hasher `t`.
hash(t: MessageDigest, data: &[u8]) -> Result<DigestBytes, ErrorStack>399 pub fn hash(t: MessageDigest, data: &[u8]) -> Result<DigestBytes, ErrorStack> {
400     let mut h = Hasher::new(t)?;
401     h.update(data)?;
402     h.finish()
403 }
404 
405 /// Computes the hash of the `data` with the XOF hasher `t` and stores it in `buf`.
406 #[cfg(ossl111)]
hash_xof(t: MessageDigest, data: &[u8], buf: &mut [u8]) -> Result<(), ErrorStack>407 pub fn hash_xof(t: MessageDigest, data: &[u8], buf: &mut [u8]) -> Result<(), ErrorStack> {
408     let mut h = Hasher::new(t)?;
409     h.update(data)?;
410     h.finish_xof(buf)
411 }
412 
413 #[cfg(test)]
414 mod tests {
415     use hex::{self, FromHex};
416     use std::io::prelude::*;
417 
418     use super::*;
419 
hash_test(hashtype: MessageDigest, hashtest: &(&str, &str))420     fn hash_test(hashtype: MessageDigest, hashtest: &(&str, &str)) {
421         let res = hash(hashtype, &Vec::from_hex(hashtest.0).unwrap()).unwrap();
422         assert_eq!(hex::encode(res), hashtest.1);
423     }
424 
425     #[cfg(ossl111)]
hash_xof_test(hashtype: MessageDigest, hashtest: &(&str, &str))426     fn hash_xof_test(hashtype: MessageDigest, hashtest: &(&str, &str)) {
427         let expected = Vec::from_hex(hashtest.1).unwrap();
428         let mut buf = vec![0; expected.len()];
429         hash_xof(
430             hashtype,
431             &Vec::from_hex(hashtest.0).unwrap(),
432             buf.as_mut_slice(),
433         )
434         .unwrap();
435         assert_eq!(buf, expected);
436     }
437 
hash_recycle_test(h: &mut Hasher, hashtest: &(&str, &str))438     fn hash_recycle_test(h: &mut Hasher, hashtest: &(&str, &str)) {
439         h.write_all(&Vec::from_hex(hashtest.0).unwrap()).unwrap();
440         let res = h.finish().unwrap();
441         assert_eq!(hex::encode(res), hashtest.1);
442     }
443 
444     // Test vectors from http://www.nsrl.nist.gov/testdata/
445     const MD5_TESTS: [(&str, &str); 13] = [
446         ("", "d41d8cd98f00b204e9800998ecf8427e"),
447         ("7F", "83acb6e67e50e31db6ed341dd2de1595"),
448         ("EC9C", "0b07f0d4ca797d8ac58874f887cb0b68"),
449         ("FEE57A", "e0d583171eb06d56198fc0ef22173907"),
450         ("42F497E0", "7c430f178aefdf1487fee7144e9641e2"),
451         ("C53B777F1C", "75ef141d64cb37ec423da2d9d440c925"),
452         ("89D5B576327B", "ebbaf15eb0ed784c6faa9dc32831bf33"),
453         ("5D4CCE781EB190", "ce175c4b08172019f05e6b5279889f2c"),
454         ("81901FE94932D7B9", "cd4d2f62b8cdb3a0cf968a735a239281"),
455         ("C9FFDEE7788EFB4EC9", "e0841a231ab698db30c6c0f3f246c014"),
456         ("66AC4B7EBA95E53DC10B", "a3b3cea71910d9af56742aa0bb2fe329"),
457         ("A510CD18F7A56852EB0319", "577e216843dd11573574d3fb209b97d8"),
458         (
459             "AAED18DBE8938C19ED734A8D",
460             "6f80fb775f27e0a4ce5c2f42fc72c5f1",
461         ),
462     ];
463 
464     #[test]
test_md5()465     fn test_md5() {
466         for test in MD5_TESTS.iter() {
467             hash_test(MessageDigest::md5(), test);
468         }
469     }
470 
471     #[test]
test_md5_recycle()472     fn test_md5_recycle() {
473         let mut h = Hasher::new(MessageDigest::md5()).unwrap();
474         for test in MD5_TESTS.iter() {
475             hash_recycle_test(&mut h, test);
476         }
477     }
478 
479     #[test]
test_finish_twice()480     fn test_finish_twice() {
481         let mut h = Hasher::new(MessageDigest::md5()).unwrap();
482         h.write_all(&Vec::from_hex(MD5_TESTS[6].0).unwrap())
483             .unwrap();
484         h.finish().unwrap();
485         let res = h.finish().unwrap();
486         let null = hash(MessageDigest::md5(), &[]).unwrap();
487         assert_eq!(&*res, &*null);
488     }
489 
490     #[test]
491     #[allow(clippy::redundant_clone)]
test_clone()492     fn test_clone() {
493         let i = 7;
494         let inp = Vec::from_hex(MD5_TESTS[i].0).unwrap();
495         assert!(inp.len() > 2);
496         let p = inp.len() / 2;
497         let h0 = Hasher::new(MessageDigest::md5()).unwrap();
498 
499         println!("Clone a new hasher");
500         let mut h1 = h0.clone();
501         h1.write_all(&inp[..p]).unwrap();
502         {
503             println!("Clone an updated hasher");
504             let mut h2 = h1.clone();
505             h2.write_all(&inp[p..]).unwrap();
506             let res = h2.finish().unwrap();
507             assert_eq!(hex::encode(res), MD5_TESTS[i].1);
508         }
509         h1.write_all(&inp[p..]).unwrap();
510         let res = h1.finish().unwrap();
511         assert_eq!(hex::encode(res), MD5_TESTS[i].1);
512 
513         println!("Clone a finished hasher");
514         let mut h3 = h1.clone();
515         h3.write_all(&Vec::from_hex(MD5_TESTS[i + 1].0).unwrap())
516             .unwrap();
517         let res = h3.finish().unwrap();
518         assert_eq!(hex::encode(res), MD5_TESTS[i + 1].1);
519     }
520 
521     #[test]
test_sha1()522     fn test_sha1() {
523         let tests = [("616263", "a9993e364706816aba3e25717850c26c9cd0d89d")];
524 
525         for test in tests.iter() {
526             hash_test(MessageDigest::sha1(), test);
527         }
528     }
529 
530     #[test]
test_sha256()531     fn test_sha256() {
532         let tests = [(
533             "616263",
534             "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
535         )];
536 
537         for test in tests.iter() {
538             hash_test(MessageDigest::sha256(), test);
539         }
540     }
541 
542     #[cfg(ossl111)]
543     #[test]
test_sha3_224()544     fn test_sha3_224() {
545         let tests = [(
546             "416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
547             "1de092dd9fbcbbf450f26264f4778abd48af851f2832924554c56913",
548         )];
549 
550         for test in tests.iter() {
551             hash_test(MessageDigest::sha3_224(), test);
552         }
553     }
554 
555     #[cfg(ossl111)]
556     #[test]
test_sha3_256()557     fn test_sha3_256() {
558         let tests = [(
559             "416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
560             "b38e38f08bc1c0091ed4b5f060fe13e86aa4179578513ad11a6e3abba0062f61",
561         )];
562 
563         for test in tests.iter() {
564             hash_test(MessageDigest::sha3_256(), test);
565         }
566     }
567 
568     #[cfg(ossl111)]
569     #[test]
test_sha3_384()570     fn test_sha3_384() {
571         let tests = [("416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
572             "966ee786ab3482dd811bf7c8fa8db79aa1f52f6c3c369942ef14240ebd857c6ff626ec35d9e131ff64d328\
573             ef2008ff16"
574         )];
575 
576         for test in tests.iter() {
577             hash_test(MessageDigest::sha3_384(), test);
578         }
579     }
580 
581     #[cfg(ossl111)]
582     #[test]
test_sha3_512()583     fn test_sha3_512() {
584         let tests = [("416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
585             "c072288ef728cd53a029c47687960b9225893532f42b923156e37020bdc1eda753aafbf30af859d4f4c3a1\
586             807caee3a79f8eb02dcd61589fbbdf5f40c8787a72"
587         )];
588 
589         for test in tests.iter() {
590             hash_test(MessageDigest::sha3_512(), test);
591         }
592     }
593 
594     #[cfg(ossl111)]
595     #[test]
test_shake_128()596     fn test_shake_128() {
597         let tests = [(
598             "416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
599             "49d0697ff508111d8b84f15e46daf135",
600         )];
601 
602         for test in tests.iter() {
603             hash_xof_test(MessageDigest::shake_128(), test);
604         }
605     }
606 
607     #[cfg(ossl111)]
608     #[test]
test_shake_256()609     fn test_shake_256() {
610         let tests = [(
611             "416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
612             "4e2dfdaa75d1e049d0eaeffe28e76b17cea47b650fb8826fe48b94664326a697",
613         )];
614 
615         for test in tests.iter() {
616             hash_xof_test(MessageDigest::shake_256(), test);
617         }
618     }
619 
620     #[test]
test_ripemd160()621     fn test_ripemd160() {
622         let tests = [("616263", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc")];
623 
624         for test in tests.iter() {
625             hash_test(MessageDigest::ripemd160(), test);
626         }
627     }
628 
629     #[test]
from_nid()630     fn from_nid() {
631         assert_eq!(
632             MessageDigest::from_nid(Nid::SHA256).unwrap().as_ptr(),
633             MessageDigest::sha256().as_ptr()
634         );
635     }
636 
637     #[test]
from_name()638     fn from_name() {
639         assert_eq!(
640             MessageDigest::from_name("SHA256").unwrap().as_ptr(),
641             MessageDigest::sha256().as_ptr()
642         )
643     }
644 }
645