• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! The message digest context.
2 //!
3 //! # Examples
4 //!
5 //! Compute the SHA256 checksum of data
6 //!
7 //! ```
8 //! use openssl::md::Md;
9 //! use openssl::md_ctx::MdCtx;
10 //!
11 //! let mut ctx = MdCtx::new().unwrap();
12 //! ctx.digest_init(Md::sha256()).unwrap();
13 //! ctx.digest_update(b"Some Crypto Text").unwrap();
14 //! let mut digest = [0; 32];
15 //! ctx.digest_final(&mut digest).unwrap();
16 //!
17 //! assert_eq!(
18 //!     digest,
19 //!     *b"\x60\x78\x56\x38\x8a\xca\x5c\x51\x83\xc4\xd1\x4d\xc8\xf9\xcc\xf2\
20 //!        \xa5\x21\xb3\x10\x93\x72\xfa\xd6\x7c\x55\xf5\xc9\xe3\xd1\x83\x19",
21 //! );
22 //! ```
23 //!
24 //! Sign and verify data with RSA and SHA256
25 //!
26 //! ```
27 //! use openssl::md::Md;
28 //! use openssl::md_ctx::MdCtx;
29 //! use openssl::pkey::PKey;
30 //! use openssl::rsa::Rsa;
31 //!
32 //! // Generate a random RSA key.
33 //! let key = Rsa::generate(4096).unwrap();
34 //! let key = PKey::from_rsa(key).unwrap();
35 //!
36 //! let text = b"Some Crypto Text";
37 //!
38 //! // Create the signature.
39 //! let mut ctx = MdCtx::new().unwrap();
40 //! ctx.digest_sign_init(Some(Md::sha256()), &key).unwrap();
41 //! ctx.digest_sign_update(text).unwrap();
42 //! let mut signature = vec![];
43 //! ctx.digest_sign_final_to_vec(&mut signature).unwrap();
44 //!
45 //! // Verify the signature.
46 //! let mut ctx = MdCtx::new().unwrap();
47 //! ctx.digest_verify_init(Some(Md::sha256()), &key).unwrap();
48 //! ctx.digest_verify_update(text).unwrap();
49 //! let valid = ctx.digest_verify_final(&signature).unwrap();
50 //! assert!(valid);
51 //! ```
52 //!
53 
54 #![cfg_attr(
55     not(boringssl),
56     doc = r#"\
57 Compute and verify an HMAC-SHA256
58 
59 ```
60 use openssl::md::Md;
61 use openssl::md_ctx::MdCtx;
62 use openssl::memcmp;
63 use openssl::pkey::PKey;
64 
65 // Create a key with the HMAC secret.
66 let key = PKey::hmac(b"my secret").unwrap();
67 
68 let text = b"Some Crypto Text";
69 
70 // Compute the HMAC.
71 let mut ctx = MdCtx::new().unwrap();
72 ctx.digest_sign_init(Some(Md::sha256()), &key).unwrap();
73 ctx.digest_sign_update(text).unwrap();
74 let mut hmac = vec![];
75 ctx.digest_sign_final_to_vec(&mut hmac).unwrap();
76 
77 // Verify the HMAC. You can't use MdCtx to do this; instead use a constant time equality check.
78 # let target = hmac.clone();
79 let valid = memcmp::eq(&hmac, &target);
80 assert!(valid);
81 ```"#
82 )]
83 
84 use crate::error::ErrorStack;
85 use crate::md::MdRef;
86 use crate::pkey::{HasPrivate, HasPublic, PKeyRef};
87 use crate::pkey_ctx::PkeyCtxRef;
88 use crate::{cvt, cvt_n, cvt_p};
89 use cfg_if::cfg_if;
90 use foreign_types::{ForeignType, ForeignTypeRef};
91 use openssl_macros::corresponds;
92 use std::convert::TryFrom;
93 use std::ptr;
94 
95 cfg_if! {
96     if #[cfg(any(ossl110, boringssl))] {
97         use ffi::{EVP_MD_CTX_free, EVP_MD_CTX_new};
98     } else {
99         use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free};
100     }
101 }
102 
103 foreign_type_and_impl_send_sync! {
104     type CType = ffi::EVP_MD_CTX;
105     fn drop = EVP_MD_CTX_free;
106 
107     pub struct MdCtx;
108     /// A reference to an [`MdCtx`].
109     pub struct MdCtxRef;
110 }
111 
112 impl MdCtx {
113     /// Creates a new context.
114     #[corresponds(EVP_MD_CTX_new)]
115     #[inline]
new() -> Result<Self, ErrorStack>116     pub fn new() -> Result<Self, ErrorStack> {
117         ffi::init();
118 
119         unsafe {
120             let ptr = cvt_p(EVP_MD_CTX_new())?;
121             Ok(MdCtx::from_ptr(ptr))
122         }
123     }
124 }
125 
126 impl MdCtxRef {
127     /// Initializes the context to compute the digest of data.
128     #[corresponds(EVP_DigestInit_ex)]
129     #[inline]
digest_init(&mut self, digest: &MdRef) -> Result<(), ErrorStack>130     pub fn digest_init(&mut self, digest: &MdRef) -> Result<(), ErrorStack> {
131         unsafe {
132             cvt(ffi::EVP_DigestInit_ex(
133                 self.as_ptr(),
134                 digest.as_ptr(),
135                 ptr::null_mut(),
136             ))?;
137         }
138 
139         Ok(())
140     }
141 
142     /// Initializes the context to compute the signature of data.
143     ///
144     /// A reference to the context's inner `PkeyCtx` is returned, allowing signature settings to be configured.
145     #[corresponds(EVP_DigestSignInit)]
146     #[inline]
digest_sign_init<'a, T>( &'a mut self, digest: Option<&MdRef>, pkey: &PKeyRef<T>, ) -> Result<&'a mut PkeyCtxRef<T>, ErrorStack> where T: HasPrivate,147     pub fn digest_sign_init<'a, T>(
148         &'a mut self,
149         digest: Option<&MdRef>,
150         pkey: &PKeyRef<T>,
151     ) -> Result<&'a mut PkeyCtxRef<T>, ErrorStack>
152     where
153         T: HasPrivate,
154     {
155         unsafe {
156             let mut p = ptr::null_mut();
157             cvt(ffi::EVP_DigestSignInit(
158                 self.as_ptr(),
159                 &mut p,
160                 digest.map_or(ptr::null(), |p| p.as_ptr()),
161                 ptr::null_mut(),
162                 pkey.as_ptr(),
163             ))?;
164             Ok(PkeyCtxRef::from_ptr_mut(p))
165         }
166     }
167 
168     /// Initializes the context to verify the signature of data.
169     ///
170     /// A reference to the context's inner `PkeyCtx` is returned, allowing signature settings to be configured.
171     #[corresponds(EVP_DigestVerifyInit)]
172     #[inline]
digest_verify_init<'a, T>( &'a mut self, digest: Option<&MdRef>, pkey: &PKeyRef<T>, ) -> Result<&'a mut PkeyCtxRef<T>, ErrorStack> where T: HasPublic,173     pub fn digest_verify_init<'a, T>(
174         &'a mut self,
175         digest: Option<&MdRef>,
176         pkey: &PKeyRef<T>,
177     ) -> Result<&'a mut PkeyCtxRef<T>, ErrorStack>
178     where
179         T: HasPublic,
180     {
181         unsafe {
182             let mut p = ptr::null_mut();
183             cvt(ffi::EVP_DigestVerifyInit(
184                 self.as_ptr(),
185                 &mut p,
186                 digest.map_or(ptr::null(), |p| p.as_ptr()),
187                 ptr::null_mut(),
188                 pkey.as_ptr(),
189             ))?;
190             Ok(PkeyCtxRef::from_ptr_mut(p))
191         }
192     }
193 
194     /// Updates the context with more data.
195     #[corresponds(EVP_DigestUpdate)]
196     #[inline]
digest_update(&mut self, data: &[u8]) -> Result<(), ErrorStack>197     pub fn digest_update(&mut self, data: &[u8]) -> Result<(), ErrorStack> {
198         unsafe {
199             cvt(ffi::EVP_DigestUpdate(
200                 self.as_ptr(),
201                 data.as_ptr() as *const _,
202                 data.len(),
203             ))?;
204         }
205 
206         Ok(())
207     }
208 
209     /// Updates the context with more data.
210     #[corresponds(EVP_DigestSignUpdate)]
211     #[inline]
digest_sign_update(&mut self, data: &[u8]) -> Result<(), ErrorStack>212     pub fn digest_sign_update(&mut self, data: &[u8]) -> Result<(), ErrorStack> {
213         unsafe {
214             cvt(ffi::EVP_DigestSignUpdate(
215                 self.as_ptr(),
216                 data.as_ptr() as *const _,
217                 data.len(),
218             ))?;
219         }
220 
221         Ok(())
222     }
223 
224     /// Updates the context with more data.
225     #[corresponds(EVP_DigestVerifyUpdate)]
226     #[inline]
digest_verify_update(&mut self, data: &[u8]) -> Result<(), ErrorStack>227     pub fn digest_verify_update(&mut self, data: &[u8]) -> Result<(), ErrorStack> {
228         unsafe {
229             cvt(ffi::EVP_DigestVerifyUpdate(
230                 self.as_ptr(),
231                 data.as_ptr() as *const _,
232                 data.len(),
233             ))?;
234         }
235 
236         Ok(())
237     }
238 
239     /// Copies the computed digest into the buffer, returning the number of bytes written.
240     #[corresponds(EVP_DigestFinal)]
241     #[inline]
digest_final(&mut self, out: &mut [u8]) -> Result<usize, ErrorStack>242     pub fn digest_final(&mut self, out: &mut [u8]) -> Result<usize, ErrorStack> {
243         let mut len = u32::try_from(out.len()).unwrap_or(u32::MAX);
244 
245         unsafe {
246             cvt(ffi::EVP_DigestFinal(
247                 self.as_ptr(),
248                 out.as_mut_ptr(),
249                 &mut len,
250             ))?;
251         }
252 
253         Ok(len as usize)
254     }
255 
256     /// Copies the computed digest into the buffer.
257     ///
258     /// Requires OpenSSL 1.1.1 or newer.
259     #[corresponds(EVP_DigestFinalXOF)]
260     #[inline]
261     #[cfg(ossl111)]
digest_final_xof(&mut self, out: &mut [u8]) -> Result<(), ErrorStack>262     pub fn digest_final_xof(&mut self, out: &mut [u8]) -> Result<(), ErrorStack> {
263         unsafe {
264             cvt(ffi::EVP_DigestFinalXOF(
265                 self.as_ptr(),
266                 out.as_mut_ptr(),
267                 out.len(),
268             ))?;
269         }
270 
271         Ok(())
272     }
273 
274     /// Signs the computed digest.
275     ///
276     /// If `out` is set to `None`, an upper bound on the number of bytes required for the output buffer will be
277     /// returned.
278     #[corresponds(EVP_DigestSignFinal)]
279     #[inline]
digest_sign_final(&mut self, out: Option<&mut [u8]>) -> Result<usize, ErrorStack>280     pub fn digest_sign_final(&mut self, out: Option<&mut [u8]>) -> Result<usize, ErrorStack> {
281         let mut len = out.as_ref().map_or(0, |b| b.len());
282 
283         unsafe {
284             cvt(ffi::EVP_DigestSignFinal(
285                 self.as_ptr(),
286                 out.map_or(ptr::null_mut(), |b| b.as_mut_ptr()),
287                 &mut len,
288             ))?;
289         }
290 
291         Ok(len)
292     }
293 
294     /// Like [`Self::digest_sign_final`] but appends the signature to a [`Vec`].
digest_sign_final_to_vec(&mut self, out: &mut Vec<u8>) -> Result<usize, ErrorStack>295     pub fn digest_sign_final_to_vec(&mut self, out: &mut Vec<u8>) -> Result<usize, ErrorStack> {
296         let base = out.len();
297         let len = self.digest_sign_final(None)?;
298         out.resize(base + len, 0);
299         let len = self.digest_sign_final(Some(&mut out[base..]))?;
300         out.truncate(base + len);
301         Ok(len)
302     }
303 
304     /// Verifies the provided signature.
305     ///
306     /// Returns `Ok(true)` if the signature is valid, `Ok(false)` if the signature is invalid, and `Err` if an error
307     /// occurred.
308     #[corresponds(EVP_DigestVerifyFinal)]
309     #[inline]
digest_verify_final(&mut self, signature: &[u8]) -> Result<bool, ErrorStack>310     pub fn digest_verify_final(&mut self, signature: &[u8]) -> Result<bool, ErrorStack> {
311         unsafe {
312             let r = cvt_n(ffi::EVP_DigestVerifyFinal(
313                 self.as_ptr(),
314                 signature.as_ptr() as *mut _,
315                 signature.len(),
316             ))?;
317             Ok(r == 1)
318         }
319     }
320 
321     /// Computes the signature of the data in `from`.
322     ///
323     /// If `to` is set to `None`, an upper bound on the number of bytes required for the output buffer will be
324     /// returned.
325     ///
326     /// Requires OpenSSL 1.1.1 or newer.
327     #[corresponds(EVP_DigestSign)]
328     #[cfg(ossl111)]
329     #[inline]
digest_sign(&mut self, from: &[u8], to: Option<&mut [u8]>) -> Result<usize, ErrorStack>330     pub fn digest_sign(&mut self, from: &[u8], to: Option<&mut [u8]>) -> Result<usize, ErrorStack> {
331         let mut len = to.as_ref().map_or(0, |b| b.len());
332 
333         unsafe {
334             cvt(ffi::EVP_DigestSign(
335                 self.as_ptr(),
336                 to.map_or(ptr::null_mut(), |b| b.as_mut_ptr()),
337                 &mut len,
338                 from.as_ptr(),
339                 from.len(),
340             ))?;
341         }
342 
343         Ok(len)
344     }
345 
346     /// Like [`Self::digest_sign`] but appends the signature to a [`Vec`].
347     #[cfg(ossl111)]
digest_sign_to_vec( &mut self, from: &[u8], to: &mut Vec<u8>, ) -> Result<usize, ErrorStack>348     pub fn digest_sign_to_vec(
349         &mut self,
350         from: &[u8],
351         to: &mut Vec<u8>,
352     ) -> Result<usize, ErrorStack> {
353         let base = to.len();
354         let len = self.digest_sign(from, None)?;
355         to.resize(base + len, 0);
356         let len = self.digest_sign(from, Some(&mut to[base..]))?;
357         to.truncate(base + len);
358         Ok(len)
359     }
360 
361     /// Verifies the signature of the data in `data`.
362     ///
363     /// Returns `Ok(true)` if the signature is valid, `Ok(false)` if the signature is invalid, and `Err` if an error
364     /// occurred.
365     ///
366     /// Requires OpenSSL 1.1.1 or newer.
367     #[corresponds(EVP_DigestVerify)]
368     #[cfg(ossl111)]
369     #[inline]
digest_verify(&mut self, data: &[u8], signature: &[u8]) -> Result<bool, ErrorStack>370     pub fn digest_verify(&mut self, data: &[u8], signature: &[u8]) -> Result<bool, ErrorStack> {
371         unsafe {
372             let r = cvt(ffi::EVP_DigestVerify(
373                 self.as_ptr(),
374                 signature.as_ptr(),
375                 signature.len(),
376                 data.as_ptr(),
377                 data.len(),
378             ))?;
379             Ok(r == 1)
380         }
381     }
382 
383     /// Returns the size of the message digest, i.e. the size of the hash
384     #[corresponds(EVP_MD_CTX_size)]
385     #[inline]
size(&self) -> usize386     pub fn size(&self) -> usize {
387         unsafe { ffi::EVP_MD_CTX_size(self.as_ptr()) as usize }
388     }
389 
390     /// Resets the underlying EVP_MD_CTX instance
391     #[corresponds(EVP_MD_CTX_reset)]
392     #[cfg(ossl111)]
393     #[inline]
reset(&mut self) -> Result<(), ErrorStack>394     pub fn reset(&mut self) -> Result<(), ErrorStack> {
395         unsafe {
396             let _ = cvt(ffi::EVP_MD_CTX_reset(self.as_ptr()))?;
397             Ok(())
398         }
399     }
400 }
401 
402 #[cfg(test)]
403 mod test {
404     use super::*;
405     use crate::md::Md;
406     use crate::pkey::PKey;
407     use crate::rsa::Rsa;
408 
409     #[test]
verify_fail()410     fn verify_fail() {
411         let key1 = Rsa::generate(4096).unwrap();
412         let key1 = PKey::from_rsa(key1).unwrap();
413 
414         let md = Md::sha256();
415         let data = b"Some Crypto Text";
416 
417         let mut ctx = MdCtx::new().unwrap();
418         ctx.digest_sign_init(Some(md), &key1).unwrap();
419         ctx.digest_sign_update(data).unwrap();
420         let mut signature = vec![];
421         ctx.digest_sign_final_to_vec(&mut signature).unwrap();
422 
423         let bad_data = b"Some Crypto text";
424 
425         ctx.digest_verify_init(Some(md), &key1).unwrap();
426         ctx.digest_verify_update(bad_data).unwrap();
427         let valid = ctx.digest_verify_final(&signature).unwrap();
428         assert!(!valid);
429     }
430 
431     #[test]
verify_success()432     fn verify_success() {
433         let key1 = Rsa::generate(2048).unwrap();
434         let key1 = PKey::from_rsa(key1).unwrap();
435 
436         let md = Md::sha256();
437         let data = b"Some Crypto Text";
438 
439         let mut ctx = MdCtx::new().unwrap();
440         ctx.digest_sign_init(Some(md), &key1).unwrap();
441         ctx.digest_sign_update(data).unwrap();
442         let mut signature = vec![];
443         ctx.digest_sign_final_to_vec(&mut signature).unwrap();
444 
445         let good_data = b"Some Crypto Text";
446 
447         ctx.digest_verify_init(Some(md), &key1).unwrap();
448         ctx.digest_verify_update(good_data).unwrap();
449         let valid = ctx.digest_verify_final(&signature).unwrap();
450         assert!(valid);
451     }
452 
453     #[test]
verify_with_public_success()454     fn verify_with_public_success() {
455         let rsa = Rsa::generate(2048).unwrap();
456         let key1 = PKey::from_rsa(rsa.clone()).unwrap();
457 
458         let md = Md::sha256();
459         let data = b"Some Crypto Text";
460 
461         let mut ctx = MdCtx::new().unwrap();
462         ctx.digest_sign_init(Some(md), &key1).unwrap();
463         ctx.digest_sign_update(data).unwrap();
464         let mut signature = vec![];
465         ctx.digest_sign_final_to_vec(&mut signature).unwrap();
466 
467         let good_data = b"Some Crypto Text";
468 
469         // try to verify using only public components of the key
470         let n = rsa.n().to_owned().unwrap();
471         let e = rsa.e().to_owned().unwrap();
472 
473         let rsa = Rsa::from_public_components(n, e).unwrap();
474         let key1 = PKey::from_rsa(rsa).unwrap();
475 
476         ctx.digest_verify_init(Some(md), &key1).unwrap();
477         ctx.digest_verify_update(good_data).unwrap();
478         let valid = ctx.digest_verify_final(&signature).unwrap();
479         assert!(valid);
480     }
481 
482     #[test]
verify_md_ctx_size()483     fn verify_md_ctx_size() {
484         let mut ctx = MdCtx::new().unwrap();
485         ctx.digest_init(Md::sha224()).unwrap();
486         assert_eq!(Md::sha224().size(), ctx.size());
487         assert_eq!(Md::sha224().size(), 28);
488 
489         let mut ctx = MdCtx::new().unwrap();
490         ctx.digest_init(Md::sha256()).unwrap();
491         assert_eq!(Md::sha256().size(), ctx.size());
492         assert_eq!(Md::sha256().size(), 32);
493 
494         let mut ctx = MdCtx::new().unwrap();
495         ctx.digest_init(Md::sha384()).unwrap();
496         assert_eq!(Md::sha384().size(), ctx.size());
497         assert_eq!(Md::sha384().size(), 48);
498 
499         let mut ctx = MdCtx::new().unwrap();
500         ctx.digest_init(Md::sha512()).unwrap();
501         assert_eq!(Md::sha512().size(), ctx.size());
502         assert_eq!(Md::sha512().size(), 64);
503     }
504 
505     #[test]
506     #[cfg(ossl111)]
verify_md_ctx_reset()507     fn verify_md_ctx_reset() {
508         let hello_expected =
509             hex::decode("185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969")
510                 .unwrap();
511         let world_expected =
512             hex::decode("78ae647dc5544d227130a0682a51e30bc7777fbb6d8a8f17007463a3ecd1d524")
513                 .unwrap();
514         // Calculate SHA-256 digest of "Hello"
515         let mut ctx = MdCtx::new().unwrap();
516         ctx.digest_init(Md::sha256()).unwrap();
517         ctx.digest_update(b"Hello").unwrap();
518         let mut result = vec![0; 32];
519         let result_len = ctx.digest_final(result.as_mut_slice()).unwrap();
520         assert_eq!(result_len, result.len());
521         // Validate result of "Hello"
522         assert_eq!(result, hello_expected);
523 
524         // Create new context
525         let mut ctx = MdCtx::new().unwrap();
526         // Initialize and update to "Hello"
527         ctx.digest_init(Md::sha256()).unwrap();
528         ctx.digest_update(b"Hello").unwrap();
529         // Now reset, init to SHA-256 and use "World"
530         ctx.reset().unwrap();
531         ctx.digest_init(Md::sha256()).unwrap();
532         ctx.digest_update(b"World").unwrap();
533 
534         let mut reset_result = vec![0; 32];
535         let result_len = ctx.digest_final(reset_result.as_mut_slice()).unwrap();
536         assert_eq!(result_len, reset_result.len());
537         // Validate result of digest of "World"
538         assert_eq!(reset_result, world_expected);
539     }
540 }
541