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