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