1use 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))] {
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#[derive(Copy, Clone, PartialEq, Eq)]
56pub struct MessageDigest(*const ffi::EVP_MD);
57
58impl MessageDigest {
59 pub unsafe fn from_ptr(x: *const ffi::EVP_MD) -> Self {
65 MessageDigest(x)
66 }
67
68 #[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 #[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))]
127 pub fn sha3_224() -> MessageDigest {
128 unsafe { MessageDigest(ffi::EVP_sha3_224()) }
129 }
130
131 #[cfg(any(ossl111, libressl380))]
132 pub fn sha3_256() -> MessageDigest {
133 unsafe { MessageDigest(ffi::EVP_sha3_256()) }
134 }
135
136 #[cfg(any(ossl111, libressl380))]
137 pub fn sha3_384() -> MessageDigest {
138 unsafe { MessageDigest(ffi::EVP_sha3_384()) }
139 }
140
141 #[cfg(any(ossl111, libressl380))]
142 pub fn sha3_512() -> MessageDigest {
143 unsafe { MessageDigest(ffi::EVP_sha3_512()) }
144 }
145
146 #[cfg(ossl111)]
147 pub fn shake_128() -> MessageDigest {
148 unsafe { MessageDigest(ffi::EVP_shake128()) }
149 }
150
151 #[cfg(ossl111)]
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 #[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 #[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 #[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 Finalized,
198}
199
200use self::State::*;
201
202pub struct Hasher {
231 ctx: *mut ffi::EVP_MD_CTX,
232 md: *const ffi::EVP_MD,
233 type_: MessageDigest,
234 state: State,
235}
236
237unsafe impl Sync for Hasher {}
238unsafe impl Send for Hasher {}
239
240impl Hasher {
241 pub fn new(ty: MessageDigest) -> Result<Hasher, ErrorStack> {
243 ffi::init();
244
245 let ctx = unsafe { cvt_p(EVP_MD_CTX_new())? };
246
247 let mut h = Hasher {
248 ctx,
249 md: ty.as_ptr(),
250 type_: ty,
251 state: Finalized,
252 };
253 h.init()?;
254 Ok(h)
255 }
256
257 fn init(&mut self) -> Result<(), ErrorStack> {
258 match self.state {
259 Reset => return Ok(()),
260 Updated => {
261 self.finish()?;
262 }
263 Finalized => (),
264 }
265 unsafe {
266 cvt(ffi::EVP_DigestInit_ex(self.ctx, self.md, ptr::null_mut()))?;
267 }
268 self.state = Reset;
269 Ok(())
270 }
271
272 pub fn update(&mut self, data: &[u8]) -> Result<(), ErrorStack> {
274 if self.state == Finalized {
275 self.init()?;
276 }
277 unsafe {
278 cvt(ffi::EVP_DigestUpdate(
279 self.ctx,
280 data.as_ptr() as *mut _,
281 data.len(),
282 ))?;
283 }
284 self.state = Updated;
285 Ok(())
286 }
287
288 pub fn finish(&mut self) -> Result<DigestBytes, ErrorStack> {
290 if self.state == Finalized {
291 self.init()?;
292 }
293 unsafe {
294 #[cfg(not(boringssl))]
295 let mut len = ffi::EVP_MAX_MD_SIZE;
296 #[cfg(boringssl)]
297 let mut len = ffi::EVP_MAX_MD_SIZE as u32;
298 let mut buf = [0; ffi::EVP_MAX_MD_SIZE as usize];
299 cvt(ffi::EVP_DigestFinal_ex(
300 self.ctx,
301 buf.as_mut_ptr(),
302 &mut len,
303 ))?;
304 self.state = Finalized;
305 Ok(DigestBytes {
306 buf,
307 len: len as usize,
308 })
309 }
310 }
311
312 #[cfg(ossl111)]
315 pub fn finish_xof(&mut self, buf: &mut [u8]) -> Result<(), ErrorStack> {
316 if self.state == Finalized {
317 self.init()?;
318 }
319 unsafe {
320 cvt(ffi::EVP_DigestFinalXOF(
321 self.ctx,
322 buf.as_mut_ptr(),
323 buf.len(),
324 ))?;
325 self.state = Finalized;
326 Ok(())
327 }
328 }
329}
330
331impl Write for Hasher {
332 #[inline]
333 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
334 self.update(buf)?;
335 Ok(buf.len())
336 }
337
338 fn flush(&mut self) -> io::Result<()> {
339 Ok(())
340 }
341}
342
343impl Clone for Hasher {
344 fn clone(&self) -> Hasher {
345 let ctx = unsafe {
346 let ctx = EVP_MD_CTX_new();
347 assert!(!ctx.is_null());
348 let r = ffi::EVP_MD_CTX_copy_ex(ctx, self.ctx);
349 assert_eq!(r, 1);
350 ctx
351 };
352 Hasher {
353 ctx,
354 md: self.md,
355 type_: self.type_,
356 state: self.state,
357 }
358 }
359}
360
361impl Drop for Hasher {
362 fn drop(&mut self) {
363 unsafe {
364 if self.state != Finalized {
365 drop(self.finish());
366 }
367 EVP_MD_CTX_free(self.ctx);
368 }
369 }
370}
371
372#[derive(Copy)]
377pub struct DigestBytes {
378 pub(crate) buf: [u8; ffi::EVP_MAX_MD_SIZE as usize],
379 pub(crate) len: usize,
380}
381
382impl Clone for DigestBytes {
383 #[inline]
384 fn clone(&self) -> DigestBytes {
385 *self
386 }
387}
388
389impl Deref for DigestBytes {
390 type Target = [u8];
391
392 #[inline]
393 fn deref(&self) -> &[u8] {
394 &self.buf[..self.len]
395 }
396}
397
398impl DerefMut for DigestBytes {
399 #[inline]
400 fn deref_mut(&mut self) -> &mut [u8] {
401 &mut self.buf[..self.len]
402 }
403}
404
405impl AsRef<[u8]> for DigestBytes {
406 #[inline]
407 fn as_ref(&self) -> &[u8] {
408 self.deref()
409 }
410}
411
412impl fmt::Debug for DigestBytes {
413 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
414 fmt::Debug::fmt(&**self, fmt)
415 }
416}
417
418pub fn hash(t: MessageDigest, data: &[u8]) -> Result<DigestBytes, ErrorStack> {
433 let mut h = Hasher::new(t)?;
434 h.update(data)?;
435 h.finish()
436}
437
438#[cfg(ossl111)]
453pub fn hash_xof(t: MessageDigest, data: &[u8], buf: &mut [u8]) -> Result<(), ErrorStack> {
454 let mut h = Hasher::new(t)?;
455 h.update(data)?;
456 h.finish_xof(buf)
457}
458
459#[cfg(test)]
460mod tests {
461 use hex::{self, FromHex};
462 use std::io::prelude::*;
463
464 use super::*;
465
466 fn hash_test(hashtype: MessageDigest, hashtest: &(&str, &str)) {
467 let res = hash(hashtype, &Vec::from_hex(hashtest.0).unwrap()).unwrap();
468 assert_eq!(hex::encode(res), hashtest.1);
469 }
470
471 #[cfg(ossl111)]
472 fn hash_xof_test(hashtype: MessageDigest, hashtest: &(&str, &str)) {
473 let expected = Vec::from_hex(hashtest.1).unwrap();
474 let mut buf = vec![0; expected.len()];
475 hash_xof(
476 hashtype,
477 &Vec::from_hex(hashtest.0).unwrap(),
478 buf.as_mut_slice(),
479 )
480 .unwrap();
481 assert_eq!(buf, expected);
482 }
483
484 fn hash_recycle_test(h: &mut Hasher, hashtest: &(&str, &str)) {
485 h.write_all(&Vec::from_hex(hashtest.0).unwrap()).unwrap();
486 let res = h.finish().unwrap();
487 assert_eq!(hex::encode(res), hashtest.1);
488 }
489
490 const MD5_TESTS: [(&str, &str); 13] = [
492 ("", "d41d8cd98f00b204e9800998ecf8427e"),
493 ("7F", "83acb6e67e50e31db6ed341dd2de1595"),
494 ("EC9C", "0b07f0d4ca797d8ac58874f887cb0b68"),
495 ("FEE57A", "e0d583171eb06d56198fc0ef22173907"),
496 ("42F497E0", "7c430f178aefdf1487fee7144e9641e2"),
497 ("C53B777F1C", "75ef141d64cb37ec423da2d9d440c925"),
498 ("89D5B576327B", "ebbaf15eb0ed784c6faa9dc32831bf33"),
499 ("5D4CCE781EB190", "ce175c4b08172019f05e6b5279889f2c"),
500 ("81901FE94932D7B9", "cd4d2f62b8cdb3a0cf968a735a239281"),
501 ("C9FFDEE7788EFB4EC9", "e0841a231ab698db30c6c0f3f246c014"),
502 ("66AC4B7EBA95E53DC10B", "a3b3cea71910d9af56742aa0bb2fe329"),
503 ("A510CD18F7A56852EB0319", "577e216843dd11573574d3fb209b97d8"),
504 (
505 "AAED18DBE8938C19ED734A8D",
506 "6f80fb775f27e0a4ce5c2f42fc72c5f1",
507 ),
508 ];
509
510 #[test]
511 fn test_md5() {
512 for test in MD5_TESTS.iter() {
513 hash_test(MessageDigest::md5(), test);
514 }
515
516 assert_eq!(MessageDigest::md5().block_size(), 64);
517 assert_eq!(MessageDigest::md5().size(), 16);
518 assert_eq!(MessageDigest::md5().type_().as_raw(), Nid::MD5.as_raw());
519 }
520
521 #[test]
522 fn test_md5_recycle() {
523 let mut h = Hasher::new(MessageDigest::md5()).unwrap();
524 for test in MD5_TESTS.iter() {
525 hash_recycle_test(&mut h, test);
526 }
527 }
528
529 #[test]
530 fn test_finish_twice() {
531 let mut h = Hasher::new(MessageDigest::md5()).unwrap();
532 h.write_all(&Vec::from_hex(MD5_TESTS[6].0).unwrap())
533 .unwrap();
534 h.finish().unwrap();
535 let res = h.finish().unwrap();
536 let null = hash(MessageDigest::md5(), &[]).unwrap();
537 assert_eq!(&*res, &*null);
538 }
539
540 #[test]
541 #[allow(clippy::redundant_clone)]
542 fn test_clone() {
543 let i = 7;
544 let inp = Vec::from_hex(MD5_TESTS[i].0).unwrap();
545 assert!(inp.len() > 2);
546 let p = inp.len() / 2;
547 let h0 = Hasher::new(MessageDigest::md5()).unwrap();
548
549 println!("Clone a new hasher");
550 let mut h1 = h0.clone();
551 h1.write_all(&inp[..p]).unwrap();
552 {
553 println!("Clone an updated hasher");
554 let mut h2 = h1.clone();
555 h2.write_all(&inp[p..]).unwrap();
556 let res = h2.finish().unwrap();
557 assert_eq!(hex::encode(res), MD5_TESTS[i].1);
558 }
559 h1.write_all(&inp[p..]).unwrap();
560 let res = h1.finish().unwrap();
561 assert_eq!(hex::encode(res), MD5_TESTS[i].1);
562
563 println!("Clone a finished hasher");
564 let mut h3 = h1.clone();
565 h3.write_all(&Vec::from_hex(MD5_TESTS[i + 1].0).unwrap())
566 .unwrap();
567 let res = h3.finish().unwrap();
568 assert_eq!(hex::encode(res), MD5_TESTS[i + 1].1);
569 }
570
571 #[test]
572 fn test_sha1() {
573 let tests = [("616263", "a9993e364706816aba3e25717850c26c9cd0d89d")];
574
575 for test in tests.iter() {
576 hash_test(MessageDigest::sha1(), test);
577 }
578
579 assert_eq!(MessageDigest::sha1().block_size(), 64);
580 assert_eq!(MessageDigest::sha1().size(), 20);
581 assert_eq!(MessageDigest::sha1().type_().as_raw(), Nid::SHA1.as_raw());
582 }
583
584 #[test]
585 fn test_sha256() {
586 let tests = [(
587 "616263",
588 "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
589 )];
590
591 for test in tests.iter() {
592 hash_test(MessageDigest::sha256(), test);
593 }
594
595 assert_eq!(MessageDigest::sha256().block_size(), 64);
596 assert_eq!(MessageDigest::sha256().size(), 32);
597 assert_eq!(
598 MessageDigest::sha256().type_().as_raw(),
599 Nid::SHA256.as_raw()
600 );
601 }
602
603 #[test]
604 fn test_sha512() {
605 let tests = [(
606 "737465766566696e647365766572797468696e67",
607 "ba61d1f1af0f2dd80729f6cc900f19c0966bd38ba5c75e4471ef11b771dfe7551afab7fcbd300fdc4418f2\
608 b07a028fcd99e7b6446a566f2d9bcd7c604a1ea801",
609 )];
610
611 for test in tests.iter() {
612 hash_test(MessageDigest::sha512(), test);
613 }
614
615 assert_eq!(MessageDigest::sha512().block_size(), 128);
616 assert_eq!(MessageDigest::sha512().size(), 64);
617 assert_eq!(
618 MessageDigest::sha512().type_().as_raw(),
619 Nid::SHA512.as_raw()
620 );
621 }
622
623 #[cfg(any(ossl111, libressl380))]
624 #[test]
625 fn test_sha3_224() {
626 let tests = [(
627 "416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
628 "1de092dd9fbcbbf450f26264f4778abd48af851f2832924554c56913",
629 )];
630
631 for test in tests.iter() {
632 hash_test(MessageDigest::sha3_224(), test);
633 }
634
635 assert_eq!(MessageDigest::sha3_224().block_size(), 144);
636 assert_eq!(MessageDigest::sha3_224().size(), 28);
637 assert_eq!(
638 MessageDigest::sha3_224().type_().as_raw(),
639 Nid::SHA3_224.as_raw()
640 );
641 }
642
643 #[cfg(any(ossl111, libressl380))]
644 #[test]
645 fn test_sha3_256() {
646 let tests = [(
647 "416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
648 "b38e38f08bc1c0091ed4b5f060fe13e86aa4179578513ad11a6e3abba0062f61",
649 )];
650
651 for test in tests.iter() {
652 hash_test(MessageDigest::sha3_256(), test);
653 }
654
655 assert_eq!(MessageDigest::sha3_256().block_size(), 136);
656 assert_eq!(MessageDigest::sha3_256().size(), 32);
657 assert_eq!(
658 MessageDigest::sha3_256().type_().as_raw(),
659 Nid::SHA3_256.as_raw()
660 );
661 }
662
663 #[cfg(any(ossl111, libressl380))]
664 #[test]
665 fn test_sha3_384() {
666 let tests = [("416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
667 "966ee786ab3482dd811bf7c8fa8db79aa1f52f6c3c369942ef14240ebd857c6ff626ec35d9e131ff64d328\
668 ef2008ff16"
669 )];
670
671 for test in tests.iter() {
672 hash_test(MessageDigest::sha3_384(), test);
673 }
674
675 assert_eq!(MessageDigest::sha3_384().block_size(), 104);
676 assert_eq!(MessageDigest::sha3_384().size(), 48);
677 assert_eq!(
678 MessageDigest::sha3_384().type_().as_raw(),
679 Nid::SHA3_384.as_raw()
680 );
681 }
682
683 #[cfg(any(ossl111, libressl380))]
684 #[test]
685 fn test_sha3_512() {
686 let tests = [("416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
687 "c072288ef728cd53a029c47687960b9225893532f42b923156e37020bdc1eda753aafbf30af859d4f4c3a1\
688 807caee3a79f8eb02dcd61589fbbdf5f40c8787a72"
689 )];
690
691 for test in tests.iter() {
692 hash_test(MessageDigest::sha3_512(), test);
693 }
694
695 assert_eq!(MessageDigest::sha3_512().block_size(), 72);
696 assert_eq!(MessageDigest::sha3_512().size(), 64);
697 assert_eq!(
698 MessageDigest::sha3_512().type_().as_raw(),
699 Nid::SHA3_512.as_raw()
700 );
701 }
702
703 #[cfg(ossl111)]
704 #[test]
705 fn test_shake_128() {
706 let tests = [(
707 "416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
708 "49d0697ff508111d8b84f15e46daf135",
709 )];
710
711 for test in tests.iter() {
712 hash_xof_test(MessageDigest::shake_128(), test);
713 }
714
715 assert_eq!(MessageDigest::shake_128().block_size(), 168);
716 assert_eq!(MessageDigest::shake_128().size(), 16);
717 assert_eq!(
718 MessageDigest::shake_128().type_().as_raw(),
719 Nid::SHAKE128.as_raw()
720 );
721 }
722
723 #[cfg(ossl111)]
724 #[test]
725 fn test_shake_256() {
726 let tests = [(
727 "416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
728 "4e2dfdaa75d1e049d0eaeffe28e76b17cea47b650fb8826fe48b94664326a697",
729 )];
730
731 for test in tests.iter() {
732 hash_xof_test(MessageDigest::shake_256(), test);
733 }
734
735 assert_eq!(MessageDigest::shake_256().block_size(), 136);
736 assert_eq!(MessageDigest::shake_256().size(), 32);
737 assert_eq!(
738 MessageDigest::shake_256().type_().as_raw(),
739 Nid::SHAKE256.as_raw()
740 );
741 }
742
743 #[test]
744 #[cfg(not(osslconf = "OPENSSL_NO_RMD160"))]
745 #[cfg_attr(ossl300, ignore)]
746 fn test_ripemd160() {
747 #[cfg(ossl300)]
748 let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap();
749
750 let tests = [("616263", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc")];
751
752 for test in tests.iter() {
753 hash_test(MessageDigest::ripemd160(), test);
754 }
755
756 assert_eq!(MessageDigest::ripemd160().block_size(), 64);
757 assert_eq!(MessageDigest::ripemd160().size(), 20);
758 assert_eq!(
759 MessageDigest::ripemd160().type_().as_raw(),
760 Nid::RIPEMD160.as_raw()
761 );
762 }
763
764 #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM3")))]
765 #[test]
766 fn test_sm3() {
767 let tests = [(
768 "616263",
769 "66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0",
770 )];
771
772 for test in tests.iter() {
773 hash_test(MessageDigest::sm3(), test);
774 }
775
776 assert_eq!(MessageDigest::sm3().block_size(), 64);
777 assert_eq!(MessageDigest::sm3().size(), 32);
778 assert_eq!(MessageDigest::sm3().type_().as_raw(), Nid::SM3.as_raw());
779 }
780
781 #[test]
782 fn from_nid() {
783 assert_eq!(
784 MessageDigest::from_nid(Nid::SHA256).unwrap().as_ptr(),
785 MessageDigest::sha256().as_ptr()
786 );
787 }
788
789 #[test]
790 fn from_name() {
791 assert_eq!(
792 MessageDigest::from_name("SHA256").unwrap().as_ptr(),
793 MessageDigest::sha256().as_ptr()
794 )
795 }
796}