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