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(any(boringssl, awslc)),
56 doc = r#"\
57Compute and verify an HMAC-SHA256
58
59```
60use openssl::md::Md;
61use openssl::md_ctx::MdCtx;
62use openssl::memcmp;
63use openssl::pkey::PKey;
64
65// Create a key with the HMAC secret.
66let key = PKey::hmac(b"my secret").unwrap();
67
68let text = b"Some Crypto Text";
69
70// Compute the HMAC.
71let mut ctx = MdCtx::new().unwrap();
72ctx.digest_sign_init(Some(Md::sha256()), &key).unwrap();
73ctx.digest_sign_update(text).unwrap();
74let mut hmac = vec![];
75ctx.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();
79let valid = memcmp::eq(&hmac, &target);
80assert!(valid);
81```"#
82)]
83
84use crate::error::ErrorStack;
85use crate::md::MdRef;
86use crate::pkey::{HasPrivate, HasPublic, PKeyRef};
87use crate::pkey_ctx::PkeyCtxRef;
88use crate::{cvt, cvt_p};
89use cfg_if::cfg_if;
90use foreign_types::{ForeignType, ForeignTypeRef};
91use openssl_macros::corresponds;
92use std::convert::TryFrom;
93use std::ptr;
94
95cfg_if! {
96 if #[cfg(any(ossl110, boringssl, libressl382, awslc))] {
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
103foreign_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
112impl MdCtx {
113 /// Creates a new context.
114 #[corresponds(EVP_MD_CTX_new)]
115 #[inline]
116 pub fn new() -> Result<Self, ErrorStack> {
117 ffi::init();
118
119 unsafe {
120 let ptr: *mut EVP_MD_CTX = cvt_p(EVP_MD_CTX_new())?;
121 Ok(MdCtx::from_ptr(ptr))
122 }
123 }
124}
125
126impl MdCtxRef {
127 /// Initializes the context to compute the digest of data.
128 #[corresponds(EVP_DigestInit_ex)]
129 #[inline]
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]
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]
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]
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]
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]
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]
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(any(ossl111, awslc))]
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]
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`].
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]
310 pub fn digest_verify_final(&mut self, signature: &[u8]) -> Result<bool, ErrorStack> {
311 unsafe {
312 let r = ffi::EVP_DigestVerifyFinal(
313 self.as_ptr(),
314 signature.as_ptr() as *mut _,
315 signature.len(),
316 );
317 if r == 1 {
318 Ok(true)
319 } else {
320 let errors = ErrorStack::get();
321 if errors.errors().is_empty() {
322 Ok(false)
323 } else {
324 Err(errors)
325 }
326 }
327 }
328 }
329
330 /// Computes the signature of the data in `from`.
331 ///
332 /// If `to` is set to `None`, an upper bound on the number of bytes required for the output buffer will be
333 /// returned.
334 ///
335 /// Requires OpenSSL 1.1.1 or newer.
336 #[corresponds(EVP_DigestSign)]
337 #[cfg(ossl111)]
338 #[inline]
339 pub fn digest_sign(&mut self, from: &[u8], to: Option<&mut [u8]>) -> Result<usize, ErrorStack> {
340 let mut len = to.as_ref().map_or(0, |b| b.len());
341
342 unsafe {
343 cvt(ffi::EVP_DigestSign(
344 self.as_ptr(),
345 to.map_or(ptr::null_mut(), |b| b.as_mut_ptr()),
346 &mut len,
347 from.as_ptr(),
348 from.len(),
349 ))?;
350 }
351
352 Ok(len)
353 }
354
355 /// Like [`Self::digest_sign`] but appends the signature to a [`Vec`].
356 #[cfg(ossl111)]
357 pub fn digest_sign_to_vec(
358 &mut self,
359 from: &[u8],
360 to: &mut Vec<u8>,
361 ) -> Result<usize, ErrorStack> {
362 let base = to.len();
363 let len = self.digest_sign(from, None)?;
364 to.resize(base + len, 0);
365 let len = self.digest_sign(from, Some(&mut to[base..]))?;
366 to.truncate(base + len);
367 Ok(len)
368 }
369
370 /// Verifies the signature of the data in `data`.
371 ///
372 /// Returns `Ok(true)` if the signature is valid, `Ok(false)` if the signature is invalid, and `Err` if an error
373 /// occurred.
374 ///
375 /// Requires OpenSSL 1.1.1 or newer.
376 #[corresponds(EVP_DigestVerify)]
377 #[cfg(ossl111)]
378 #[inline]
379 pub fn digest_verify(&mut self, data: &[u8], signature: &[u8]) -> Result<bool, ErrorStack> {
380 unsafe {
381 let r = cvt(ffi::EVP_DigestVerify(
382 self.as_ptr(),
383 signature.as_ptr(),
384 signature.len(),
385 data.as_ptr(),
386 data.len(),
387 ))?;
388 Ok(r == 1)
389 }
390 }
391
392 /// Returns the size of the message digest, i.e. the size of the hash
393 #[corresponds(EVP_MD_CTX_size)]
394 #[inline]
395 pub fn size(&self) -> usize {
396 unsafe { ffi::EVP_MD_CTX_size(self.as_ptr()) as usize }
397 }
398
399 /// Resets the underlying EVP_MD_CTX instance
400 #[corresponds(EVP_MD_CTX_reset)]
401 #[cfg(ossl111)]
402 #[inline]
403 pub fn reset(&mut self) -> Result<(), ErrorStack> {
404 unsafe {
405 let _ = cvt(ffi::EVP_MD_CTX_reset(self.as_ptr()))?;
406 Ok(())
407 }
408 }
409}
410
411#[cfg(test)]
412mod test {
413 use super::*;
414 use crate::md::Md;
415 use crate::pkey::PKey;
416 use crate::rsa::Rsa;
417
418 #[test]
419 fn verify_fail() {
420 let key1 = Rsa::generate(4096).unwrap();
421 let key1 = PKey::from_rsa(key1).unwrap();
422
423 let md = Md::sha256();
424 let data = b"Some Crypto Text";
425
426 let mut ctx = MdCtx::new().unwrap();
427 ctx.digest_sign_init(Some(md), &key1).unwrap();
428 ctx.digest_sign_update(data).unwrap();
429 let mut signature = vec![];
430 ctx.digest_sign_final_to_vec(&mut signature).unwrap();
431
432 let bad_data = b"Some Crypto text";
433
434 ctx.digest_verify_init(Some(md), &key1).unwrap();
435 ctx.digest_verify_update(bad_data).unwrap();
436 assert!(matches!(
437 ctx.digest_verify_final(&signature),
438 Ok(false) | Err(_)
439 ));
440 assert!(ErrorStack::get().errors().is_empty());
441 }
442
443 #[test]
444 fn verify_success() {
445 let key1 = Rsa::generate(2048).unwrap();
446 let key1 = PKey::from_rsa(key1).unwrap();
447
448 let md = Md::sha256();
449 let data = b"Some Crypto Text";
450
451 let mut ctx = MdCtx::new().unwrap();
452 ctx.digest_sign_init(Some(md), &key1).unwrap();
453 ctx.digest_sign_update(data).unwrap();
454 let mut signature = vec![];
455 ctx.digest_sign_final_to_vec(&mut signature).unwrap();
456
457 let good_data = b"Some Crypto Text";
458
459 ctx.digest_verify_init(Some(md), &key1).unwrap();
460 ctx.digest_verify_update(good_data).unwrap();
461 let valid = ctx.digest_verify_final(&signature).unwrap();
462 assert!(valid);
463 }
464
465 #[test]
466 fn verify_with_public_success() {
467 let rsa = Rsa::generate(2048).unwrap();
468 let key1 = PKey::from_rsa(rsa.clone()).unwrap();
469
470 let md = Md::sha256();
471 let data = b"Some Crypto Text";
472
473 let mut ctx = MdCtx::new().unwrap();
474 ctx.digest_sign_init(Some(md), &key1).unwrap();
475 ctx.digest_sign_update(data).unwrap();
476 let mut signature = vec![];
477 ctx.digest_sign_final_to_vec(&mut signature).unwrap();
478
479 let good_data = b"Some Crypto Text";
480
481 // try to verify using only public components of the key
482 let n = rsa.n().to_owned().unwrap();
483 let e = rsa.e().to_owned().unwrap();
484
485 let rsa = Rsa::from_public_components(n, e).unwrap();
486 let key1 = PKey::from_rsa(rsa).unwrap();
487
488 ctx.digest_verify_init(Some(md), &key1).unwrap();
489 ctx.digest_verify_update(good_data).unwrap();
490 let valid = ctx.digest_verify_final(&signature).unwrap();
491 assert!(valid);
492 }
493
494 #[test]
495 fn verify_md_ctx_size() {
496 let mut ctx = MdCtx::new().unwrap();
497 ctx.digest_init(Md::sha224()).unwrap();
498 assert_eq!(Md::sha224().size(), ctx.size());
499 assert_eq!(Md::sha224().size(), 28);
500
501 let mut ctx = MdCtx::new().unwrap();
502 ctx.digest_init(Md::sha256()).unwrap();
503 assert_eq!(Md::sha256().size(), ctx.size());
504 assert_eq!(Md::sha256().size(), 32);
505
506 let mut ctx = MdCtx::new().unwrap();
507 ctx.digest_init(Md::sha384()).unwrap();
508 assert_eq!(Md::sha384().size(), ctx.size());
509 assert_eq!(Md::sha384().size(), 48);
510
511 let mut ctx = MdCtx::new().unwrap();
512 ctx.digest_init(Md::sha512()).unwrap();
513 assert_eq!(Md::sha512().size(), ctx.size());
514 assert_eq!(Md::sha512().size(), 64);
515 }
516
517 #[test]
518 #[cfg(ossl111)]
519 fn verify_md_ctx_reset() {
520 let hello_expected =
521 hex::decode("185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969")
522 .unwrap();
523 let world_expected =
524 hex::decode("78ae647dc5544d227130a0682a51e30bc7777fbb6d8a8f17007463a3ecd1d524")
525 .unwrap();
526 // Calculate SHA-256 digest of "Hello"
527 let mut ctx = MdCtx::new().unwrap();
528 ctx.digest_init(Md::sha256()).unwrap();
529 ctx.digest_update(b"Hello").unwrap();
530 let mut result = vec![0; 32];
531 let result_len = ctx.digest_final(result.as_mut_slice()).unwrap();
532 assert_eq!(result_len, result.len());
533 // Validate result of "Hello"
534 assert_eq!(result, hello_expected);
535
536 // Create new context
537 let mut ctx = MdCtx::new().unwrap();
538 // Initialize and update to "Hello"
539 ctx.digest_init(Md::sha256()).unwrap();
540 ctx.digest_update(b"Hello").unwrap();
541 // Now reset, init to SHA-256 and use "World"
542 ctx.reset().unwrap();
543 ctx.digest_init(Md::sha256()).unwrap();
544 ctx.digest_update(b"World").unwrap();
545
546 let mut reset_result = vec![0; 32];
547 let result_len = ctx.digest_final(reset_result.as_mut_slice()).unwrap();
548 assert_eq!(result_len, reset_result.len());
549 // Validate result of digest of "World"
550 assert_eq!(reset_result, world_expected);
551 }
552}
553