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