192f3ab15Sopenharmony_ci//! The message digest context. 292f3ab15Sopenharmony_ci//! 392f3ab15Sopenharmony_ci//! # Examples 492f3ab15Sopenharmony_ci//! 592f3ab15Sopenharmony_ci//! Compute the SHA256 checksum of data 692f3ab15Sopenharmony_ci//! 792f3ab15Sopenharmony_ci//! ``` 892f3ab15Sopenharmony_ci//! use openssl::md::Md; 992f3ab15Sopenharmony_ci//! use openssl::md_ctx::MdCtx; 1092f3ab15Sopenharmony_ci//! 1192f3ab15Sopenharmony_ci//! let mut ctx = MdCtx::new().unwrap(); 1292f3ab15Sopenharmony_ci//! ctx.digest_init(Md::sha256()).unwrap(); 1392f3ab15Sopenharmony_ci//! ctx.digest_update(b"Some Crypto Text").unwrap(); 1492f3ab15Sopenharmony_ci//! let mut digest = [0; 32]; 1592f3ab15Sopenharmony_ci//! ctx.digest_final(&mut digest).unwrap(); 1692f3ab15Sopenharmony_ci//! 1792f3ab15Sopenharmony_ci//! assert_eq!( 1892f3ab15Sopenharmony_ci//! digest, 1992f3ab15Sopenharmony_ci//! *b"\x60\x78\x56\x38\x8a\xca\x5c\x51\x83\xc4\xd1\x4d\xc8\xf9\xcc\xf2\ 2092f3ab15Sopenharmony_ci//! \xa5\x21\xb3\x10\x93\x72\xfa\xd6\x7c\x55\xf5\xc9\xe3\xd1\x83\x19", 2192f3ab15Sopenharmony_ci//! ); 2292f3ab15Sopenharmony_ci//! ``` 2392f3ab15Sopenharmony_ci//! 2492f3ab15Sopenharmony_ci//! Sign and verify data with RSA and SHA256 2592f3ab15Sopenharmony_ci//! 2692f3ab15Sopenharmony_ci//! ``` 2792f3ab15Sopenharmony_ci//! use openssl::md::Md; 2892f3ab15Sopenharmony_ci//! use openssl::md_ctx::MdCtx; 2992f3ab15Sopenharmony_ci//! use openssl::pkey::PKey; 3092f3ab15Sopenharmony_ci//! use openssl::rsa::Rsa; 3192f3ab15Sopenharmony_ci//! 3292f3ab15Sopenharmony_ci//! // Generate a random RSA key. 3392f3ab15Sopenharmony_ci//! let key = Rsa::generate(4096).unwrap(); 3492f3ab15Sopenharmony_ci//! let key = PKey::from_rsa(key).unwrap(); 3592f3ab15Sopenharmony_ci//! 3692f3ab15Sopenharmony_ci//! let text = b"Some Crypto Text"; 3792f3ab15Sopenharmony_ci//! 3892f3ab15Sopenharmony_ci//! // Create the signature. 3992f3ab15Sopenharmony_ci//! let mut ctx = MdCtx::new().unwrap(); 4092f3ab15Sopenharmony_ci//! ctx.digest_sign_init(Some(Md::sha256()), &key).unwrap(); 4192f3ab15Sopenharmony_ci//! ctx.digest_sign_update(text).unwrap(); 4292f3ab15Sopenharmony_ci//! let mut signature = vec![]; 4392f3ab15Sopenharmony_ci//! ctx.digest_sign_final_to_vec(&mut signature).unwrap(); 4492f3ab15Sopenharmony_ci//! 4592f3ab15Sopenharmony_ci//! // Verify the signature. 4692f3ab15Sopenharmony_ci//! let mut ctx = MdCtx::new().unwrap(); 4792f3ab15Sopenharmony_ci//! ctx.digest_verify_init(Some(Md::sha256()), &key).unwrap(); 4892f3ab15Sopenharmony_ci//! ctx.digest_verify_update(text).unwrap(); 4992f3ab15Sopenharmony_ci//! let valid = ctx.digest_verify_final(&signature).unwrap(); 5092f3ab15Sopenharmony_ci//! assert!(valid); 5192f3ab15Sopenharmony_ci//! ``` 5292f3ab15Sopenharmony_ci//! 5392f3ab15Sopenharmony_ci 5492f3ab15Sopenharmony_ci#![cfg_attr( 5592f3ab15Sopenharmony_ci not(boringssl), 5692f3ab15Sopenharmony_ci doc = r#"\ 5792f3ab15Sopenharmony_ciCompute and verify an HMAC-SHA256 5892f3ab15Sopenharmony_ci 5992f3ab15Sopenharmony_ci``` 6092f3ab15Sopenharmony_ciuse openssl::md::Md; 6192f3ab15Sopenharmony_ciuse openssl::md_ctx::MdCtx; 6292f3ab15Sopenharmony_ciuse openssl::memcmp; 6392f3ab15Sopenharmony_ciuse openssl::pkey::PKey; 6492f3ab15Sopenharmony_ci 6592f3ab15Sopenharmony_ci// Create a key with the HMAC secret. 6692f3ab15Sopenharmony_cilet key = PKey::hmac(b"my secret").unwrap(); 6792f3ab15Sopenharmony_ci 6892f3ab15Sopenharmony_cilet text = b"Some Crypto Text"; 6992f3ab15Sopenharmony_ci 7092f3ab15Sopenharmony_ci// Compute the HMAC. 7192f3ab15Sopenharmony_cilet mut ctx = MdCtx::new().unwrap(); 7292f3ab15Sopenharmony_cictx.digest_sign_init(Some(Md::sha256()), &key).unwrap(); 7392f3ab15Sopenharmony_cictx.digest_sign_update(text).unwrap(); 7492f3ab15Sopenharmony_cilet mut hmac = vec![]; 7592f3ab15Sopenharmony_cictx.digest_sign_final_to_vec(&mut hmac).unwrap(); 7692f3ab15Sopenharmony_ci 7792f3ab15Sopenharmony_ci// Verify the HMAC. You can't use MdCtx to do this; instead use a constant time equality check. 7892f3ab15Sopenharmony_ci# let target = hmac.clone(); 7992f3ab15Sopenharmony_cilet valid = memcmp::eq(&hmac, &target); 8092f3ab15Sopenharmony_ciassert!(valid); 8192f3ab15Sopenharmony_ci```"# 8292f3ab15Sopenharmony_ci)] 8392f3ab15Sopenharmony_ci 8492f3ab15Sopenharmony_ciuse crate::error::ErrorStack; 8592f3ab15Sopenharmony_ciuse crate::md::MdRef; 8692f3ab15Sopenharmony_ciuse crate::pkey::{HasPrivate, HasPublic, PKeyRef}; 8792f3ab15Sopenharmony_ciuse crate::pkey_ctx::PkeyCtxRef; 8892f3ab15Sopenharmony_ciuse crate::{cvt, cvt_n, cvt_p}; 8992f3ab15Sopenharmony_ciuse cfg_if::cfg_if; 9092f3ab15Sopenharmony_ciuse foreign_types::{ForeignType, ForeignTypeRef}; 9192f3ab15Sopenharmony_ciuse openssl_macros::corresponds; 9292f3ab15Sopenharmony_ciuse std::convert::TryFrom; 9392f3ab15Sopenharmony_ciuse std::ptr; 9492f3ab15Sopenharmony_ci 9592f3ab15Sopenharmony_cicfg_if! { 9692f3ab15Sopenharmony_ci if #[cfg(any(ossl110, boringssl))] { 9792f3ab15Sopenharmony_ci use ffi::{EVP_MD_CTX_free, EVP_MD_CTX_new}; 9892f3ab15Sopenharmony_ci } else { 9992f3ab15Sopenharmony_ci use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free}; 10092f3ab15Sopenharmony_ci } 10192f3ab15Sopenharmony_ci} 10292f3ab15Sopenharmony_ci 10392f3ab15Sopenharmony_ciforeign_type_and_impl_send_sync! { 10492f3ab15Sopenharmony_ci type CType = ffi::EVP_MD_CTX; 10592f3ab15Sopenharmony_ci fn drop = EVP_MD_CTX_free; 10692f3ab15Sopenharmony_ci 10792f3ab15Sopenharmony_ci pub struct MdCtx; 10892f3ab15Sopenharmony_ci /// A reference to an [`MdCtx`]. 10992f3ab15Sopenharmony_ci pub struct MdCtxRef; 11092f3ab15Sopenharmony_ci} 11192f3ab15Sopenharmony_ci 11292f3ab15Sopenharmony_ciimpl MdCtx { 11392f3ab15Sopenharmony_ci /// Creates a new context. 11492f3ab15Sopenharmony_ci #[corresponds(EVP_MD_CTX_new)] 11592f3ab15Sopenharmony_ci #[inline] 11692f3ab15Sopenharmony_ci pub fn new() -> Result<Self, ErrorStack> { 11792f3ab15Sopenharmony_ci ffi::init(); 11892f3ab15Sopenharmony_ci 11992f3ab15Sopenharmony_ci unsafe { 12092f3ab15Sopenharmony_ci let ptr = cvt_p(EVP_MD_CTX_new())?; 12192f3ab15Sopenharmony_ci Ok(MdCtx::from_ptr(ptr)) 12292f3ab15Sopenharmony_ci } 12392f3ab15Sopenharmony_ci } 12492f3ab15Sopenharmony_ci} 12592f3ab15Sopenharmony_ci 12692f3ab15Sopenharmony_ciimpl MdCtxRef { 12792f3ab15Sopenharmony_ci /// Initializes the context to compute the digest of data. 12892f3ab15Sopenharmony_ci #[corresponds(EVP_DigestInit_ex)] 12992f3ab15Sopenharmony_ci #[inline] 13092f3ab15Sopenharmony_ci pub fn digest_init(&mut self, digest: &MdRef) -> Result<(), ErrorStack> { 13192f3ab15Sopenharmony_ci unsafe { 13292f3ab15Sopenharmony_ci cvt(ffi::EVP_DigestInit_ex( 13392f3ab15Sopenharmony_ci self.as_ptr(), 13492f3ab15Sopenharmony_ci digest.as_ptr(), 13592f3ab15Sopenharmony_ci ptr::null_mut(), 13692f3ab15Sopenharmony_ci ))?; 13792f3ab15Sopenharmony_ci } 13892f3ab15Sopenharmony_ci 13992f3ab15Sopenharmony_ci Ok(()) 14092f3ab15Sopenharmony_ci } 14192f3ab15Sopenharmony_ci 14292f3ab15Sopenharmony_ci /// Initializes the context to compute the signature of data. 14392f3ab15Sopenharmony_ci /// 14492f3ab15Sopenharmony_ci /// A reference to the context's inner `PkeyCtx` is returned, allowing signature settings to be configured. 14592f3ab15Sopenharmony_ci #[corresponds(EVP_DigestSignInit)] 14692f3ab15Sopenharmony_ci #[inline] 14792f3ab15Sopenharmony_ci pub fn digest_sign_init<'a, T>( 14892f3ab15Sopenharmony_ci &'a mut self, 14992f3ab15Sopenharmony_ci digest: Option<&MdRef>, 15092f3ab15Sopenharmony_ci pkey: &PKeyRef<T>, 15192f3ab15Sopenharmony_ci ) -> Result<&'a mut PkeyCtxRef<T>, ErrorStack> 15292f3ab15Sopenharmony_ci where 15392f3ab15Sopenharmony_ci T: HasPrivate, 15492f3ab15Sopenharmony_ci { 15592f3ab15Sopenharmony_ci unsafe { 15692f3ab15Sopenharmony_ci let mut p = ptr::null_mut(); 15792f3ab15Sopenharmony_ci cvt(ffi::EVP_DigestSignInit( 15892f3ab15Sopenharmony_ci self.as_ptr(), 15992f3ab15Sopenharmony_ci &mut p, 16092f3ab15Sopenharmony_ci digest.map_or(ptr::null(), |p| p.as_ptr()), 16192f3ab15Sopenharmony_ci ptr::null_mut(), 16292f3ab15Sopenharmony_ci pkey.as_ptr(), 16392f3ab15Sopenharmony_ci ))?; 16492f3ab15Sopenharmony_ci Ok(PkeyCtxRef::from_ptr_mut(p)) 16592f3ab15Sopenharmony_ci } 16692f3ab15Sopenharmony_ci } 16792f3ab15Sopenharmony_ci 16892f3ab15Sopenharmony_ci /// Initializes the context to verify the signature of data. 16992f3ab15Sopenharmony_ci /// 17092f3ab15Sopenharmony_ci /// A reference to the context's inner `PkeyCtx` is returned, allowing signature settings to be configured. 17192f3ab15Sopenharmony_ci #[corresponds(EVP_DigestVerifyInit)] 17292f3ab15Sopenharmony_ci #[inline] 17392f3ab15Sopenharmony_ci pub fn digest_verify_init<'a, T>( 17492f3ab15Sopenharmony_ci &'a mut self, 17592f3ab15Sopenharmony_ci digest: Option<&MdRef>, 17692f3ab15Sopenharmony_ci pkey: &PKeyRef<T>, 17792f3ab15Sopenharmony_ci ) -> Result<&'a mut PkeyCtxRef<T>, ErrorStack> 17892f3ab15Sopenharmony_ci where 17992f3ab15Sopenharmony_ci T: HasPublic, 18092f3ab15Sopenharmony_ci { 18192f3ab15Sopenharmony_ci unsafe { 18292f3ab15Sopenharmony_ci let mut p = ptr::null_mut(); 18392f3ab15Sopenharmony_ci cvt(ffi::EVP_DigestVerifyInit( 18492f3ab15Sopenharmony_ci self.as_ptr(), 18592f3ab15Sopenharmony_ci &mut p, 18692f3ab15Sopenharmony_ci digest.map_or(ptr::null(), |p| p.as_ptr()), 18792f3ab15Sopenharmony_ci ptr::null_mut(), 18892f3ab15Sopenharmony_ci pkey.as_ptr(), 18992f3ab15Sopenharmony_ci ))?; 19092f3ab15Sopenharmony_ci Ok(PkeyCtxRef::from_ptr_mut(p)) 19192f3ab15Sopenharmony_ci } 19292f3ab15Sopenharmony_ci } 19392f3ab15Sopenharmony_ci 19492f3ab15Sopenharmony_ci /// Updates the context with more data. 19592f3ab15Sopenharmony_ci #[corresponds(EVP_DigestUpdate)] 19692f3ab15Sopenharmony_ci #[inline] 19792f3ab15Sopenharmony_ci pub fn digest_update(&mut self, data: &[u8]) -> Result<(), ErrorStack> { 19892f3ab15Sopenharmony_ci unsafe { 19992f3ab15Sopenharmony_ci cvt(ffi::EVP_DigestUpdate( 20092f3ab15Sopenharmony_ci self.as_ptr(), 20192f3ab15Sopenharmony_ci data.as_ptr() as *const _, 20292f3ab15Sopenharmony_ci data.len(), 20392f3ab15Sopenharmony_ci ))?; 20492f3ab15Sopenharmony_ci } 20592f3ab15Sopenharmony_ci 20692f3ab15Sopenharmony_ci Ok(()) 20792f3ab15Sopenharmony_ci } 20892f3ab15Sopenharmony_ci 20992f3ab15Sopenharmony_ci /// Updates the context with more data. 21092f3ab15Sopenharmony_ci #[corresponds(EVP_DigestSignUpdate)] 21192f3ab15Sopenharmony_ci #[inline] 21292f3ab15Sopenharmony_ci pub fn digest_sign_update(&mut self, data: &[u8]) -> Result<(), ErrorStack> { 21392f3ab15Sopenharmony_ci unsafe { 21492f3ab15Sopenharmony_ci cvt(ffi::EVP_DigestSignUpdate( 21592f3ab15Sopenharmony_ci self.as_ptr(), 21692f3ab15Sopenharmony_ci data.as_ptr() as *const _, 21792f3ab15Sopenharmony_ci data.len(), 21892f3ab15Sopenharmony_ci ))?; 21992f3ab15Sopenharmony_ci } 22092f3ab15Sopenharmony_ci 22192f3ab15Sopenharmony_ci Ok(()) 22292f3ab15Sopenharmony_ci } 22392f3ab15Sopenharmony_ci 22492f3ab15Sopenharmony_ci /// Updates the context with more data. 22592f3ab15Sopenharmony_ci #[corresponds(EVP_DigestVerifyUpdate)] 22692f3ab15Sopenharmony_ci #[inline] 22792f3ab15Sopenharmony_ci pub fn digest_verify_update(&mut self, data: &[u8]) -> Result<(), ErrorStack> { 22892f3ab15Sopenharmony_ci unsafe { 22992f3ab15Sopenharmony_ci cvt(ffi::EVP_DigestVerifyUpdate( 23092f3ab15Sopenharmony_ci self.as_ptr(), 23192f3ab15Sopenharmony_ci data.as_ptr() as *const _, 23292f3ab15Sopenharmony_ci data.len(), 23392f3ab15Sopenharmony_ci ))?; 23492f3ab15Sopenharmony_ci } 23592f3ab15Sopenharmony_ci 23692f3ab15Sopenharmony_ci Ok(()) 23792f3ab15Sopenharmony_ci } 23892f3ab15Sopenharmony_ci 23992f3ab15Sopenharmony_ci /// Copies the computed digest into the buffer, returning the number of bytes written. 24092f3ab15Sopenharmony_ci #[corresponds(EVP_DigestFinal)] 24192f3ab15Sopenharmony_ci #[inline] 24292f3ab15Sopenharmony_ci pub fn digest_final(&mut self, out: &mut [u8]) -> Result<usize, ErrorStack> { 24392f3ab15Sopenharmony_ci let mut len = u32::try_from(out.len()).unwrap_or(u32::MAX); 24492f3ab15Sopenharmony_ci 24592f3ab15Sopenharmony_ci unsafe { 24692f3ab15Sopenharmony_ci cvt(ffi::EVP_DigestFinal( 24792f3ab15Sopenharmony_ci self.as_ptr(), 24892f3ab15Sopenharmony_ci out.as_mut_ptr(), 24992f3ab15Sopenharmony_ci &mut len, 25092f3ab15Sopenharmony_ci ))?; 25192f3ab15Sopenharmony_ci } 25292f3ab15Sopenharmony_ci 25392f3ab15Sopenharmony_ci Ok(len as usize) 25492f3ab15Sopenharmony_ci } 25592f3ab15Sopenharmony_ci 25692f3ab15Sopenharmony_ci /// Copies the computed digest into the buffer. 25792f3ab15Sopenharmony_ci /// 25892f3ab15Sopenharmony_ci /// Requires OpenSSL 1.1.1 or newer. 25992f3ab15Sopenharmony_ci #[corresponds(EVP_DigestFinalXOF)] 26092f3ab15Sopenharmony_ci #[inline] 26192f3ab15Sopenharmony_ci #[cfg(ossl111)] 26292f3ab15Sopenharmony_ci pub fn digest_final_xof(&mut self, out: &mut [u8]) -> Result<(), ErrorStack> { 26392f3ab15Sopenharmony_ci unsafe { 26492f3ab15Sopenharmony_ci cvt(ffi::EVP_DigestFinalXOF( 26592f3ab15Sopenharmony_ci self.as_ptr(), 26692f3ab15Sopenharmony_ci out.as_mut_ptr(), 26792f3ab15Sopenharmony_ci out.len(), 26892f3ab15Sopenharmony_ci ))?; 26992f3ab15Sopenharmony_ci } 27092f3ab15Sopenharmony_ci 27192f3ab15Sopenharmony_ci Ok(()) 27292f3ab15Sopenharmony_ci } 27392f3ab15Sopenharmony_ci 27492f3ab15Sopenharmony_ci /// Signs the computed digest. 27592f3ab15Sopenharmony_ci /// 27692f3ab15Sopenharmony_ci /// If `out` is set to `None`, an upper bound on the number of bytes required for the output buffer will be 27792f3ab15Sopenharmony_ci /// returned. 27892f3ab15Sopenharmony_ci #[corresponds(EVP_DigestSignFinal)] 27992f3ab15Sopenharmony_ci #[inline] 28092f3ab15Sopenharmony_ci pub fn digest_sign_final(&mut self, out: Option<&mut [u8]>) -> Result<usize, ErrorStack> { 28192f3ab15Sopenharmony_ci let mut len = out.as_ref().map_or(0, |b| b.len()); 28292f3ab15Sopenharmony_ci 28392f3ab15Sopenharmony_ci unsafe { 28492f3ab15Sopenharmony_ci cvt(ffi::EVP_DigestSignFinal( 28592f3ab15Sopenharmony_ci self.as_ptr(), 28692f3ab15Sopenharmony_ci out.map_or(ptr::null_mut(), |b| b.as_mut_ptr()), 28792f3ab15Sopenharmony_ci &mut len, 28892f3ab15Sopenharmony_ci ))?; 28992f3ab15Sopenharmony_ci } 29092f3ab15Sopenharmony_ci 29192f3ab15Sopenharmony_ci Ok(len) 29292f3ab15Sopenharmony_ci } 29392f3ab15Sopenharmony_ci 29492f3ab15Sopenharmony_ci /// Like [`Self::digest_sign_final`] but appends the signature to a [`Vec`]. 29592f3ab15Sopenharmony_ci pub fn digest_sign_final_to_vec(&mut self, out: &mut Vec<u8>) -> Result<usize, ErrorStack> { 29692f3ab15Sopenharmony_ci let base = out.len(); 29792f3ab15Sopenharmony_ci let len = self.digest_sign_final(None)?; 29892f3ab15Sopenharmony_ci out.resize(base + len, 0); 29992f3ab15Sopenharmony_ci let len = self.digest_sign_final(Some(&mut out[base..]))?; 30092f3ab15Sopenharmony_ci out.truncate(base + len); 30192f3ab15Sopenharmony_ci Ok(len) 30292f3ab15Sopenharmony_ci } 30392f3ab15Sopenharmony_ci 30492f3ab15Sopenharmony_ci /// Verifies the provided signature. 30592f3ab15Sopenharmony_ci /// 30692f3ab15Sopenharmony_ci /// Returns `Ok(true)` if the signature is valid, `Ok(false)` if the signature is invalid, and `Err` if an error 30792f3ab15Sopenharmony_ci /// occurred. 30892f3ab15Sopenharmony_ci #[corresponds(EVP_DigestVerifyFinal)] 30992f3ab15Sopenharmony_ci #[inline] 31092f3ab15Sopenharmony_ci pub fn digest_verify_final(&mut self, signature: &[u8]) -> Result<bool, ErrorStack> { 31192f3ab15Sopenharmony_ci unsafe { 31292f3ab15Sopenharmony_ci let r = cvt_n(ffi::EVP_DigestVerifyFinal( 31392f3ab15Sopenharmony_ci self.as_ptr(), 31492f3ab15Sopenharmony_ci signature.as_ptr() as *mut _, 31592f3ab15Sopenharmony_ci signature.len(), 31692f3ab15Sopenharmony_ci ))?; 31792f3ab15Sopenharmony_ci Ok(r == 1) 31892f3ab15Sopenharmony_ci } 31992f3ab15Sopenharmony_ci } 32092f3ab15Sopenharmony_ci 32192f3ab15Sopenharmony_ci /// Computes the signature of the data in `from`. 32292f3ab15Sopenharmony_ci /// 32392f3ab15Sopenharmony_ci /// If `to` is set to `None`, an upper bound on the number of bytes required for the output buffer will be 32492f3ab15Sopenharmony_ci /// returned. 32592f3ab15Sopenharmony_ci /// 32692f3ab15Sopenharmony_ci /// Requires OpenSSL 1.1.1 or newer. 32792f3ab15Sopenharmony_ci #[corresponds(EVP_DigestSign)] 32892f3ab15Sopenharmony_ci #[cfg(ossl111)] 32992f3ab15Sopenharmony_ci #[inline] 33092f3ab15Sopenharmony_ci pub fn digest_sign(&mut self, from: &[u8], to: Option<&mut [u8]>) -> Result<usize, ErrorStack> { 33192f3ab15Sopenharmony_ci let mut len = to.as_ref().map_or(0, |b| b.len()); 33292f3ab15Sopenharmony_ci 33392f3ab15Sopenharmony_ci unsafe { 33492f3ab15Sopenharmony_ci cvt(ffi::EVP_DigestSign( 33592f3ab15Sopenharmony_ci self.as_ptr(), 33692f3ab15Sopenharmony_ci to.map_or(ptr::null_mut(), |b| b.as_mut_ptr()), 33792f3ab15Sopenharmony_ci &mut len, 33892f3ab15Sopenharmony_ci from.as_ptr(), 33992f3ab15Sopenharmony_ci from.len(), 34092f3ab15Sopenharmony_ci ))?; 34192f3ab15Sopenharmony_ci } 34292f3ab15Sopenharmony_ci 34392f3ab15Sopenharmony_ci Ok(len) 34492f3ab15Sopenharmony_ci } 34592f3ab15Sopenharmony_ci 34692f3ab15Sopenharmony_ci /// Like [`Self::digest_sign`] but appends the signature to a [`Vec`]. 34792f3ab15Sopenharmony_ci #[cfg(ossl111)] 34892f3ab15Sopenharmony_ci pub fn digest_sign_to_vec( 34992f3ab15Sopenharmony_ci &mut self, 35092f3ab15Sopenharmony_ci from: &[u8], 35192f3ab15Sopenharmony_ci to: &mut Vec<u8>, 35292f3ab15Sopenharmony_ci ) -> Result<usize, ErrorStack> { 35392f3ab15Sopenharmony_ci let base = to.len(); 35492f3ab15Sopenharmony_ci let len = self.digest_sign(from, None)?; 35592f3ab15Sopenharmony_ci to.resize(base + len, 0); 35692f3ab15Sopenharmony_ci let len = self.digest_sign(from, Some(&mut to[base..]))?; 35792f3ab15Sopenharmony_ci to.truncate(base + len); 35892f3ab15Sopenharmony_ci Ok(len) 35992f3ab15Sopenharmony_ci } 36092f3ab15Sopenharmony_ci 36192f3ab15Sopenharmony_ci /// Verifies the signature of the data in `data`. 36292f3ab15Sopenharmony_ci /// 36392f3ab15Sopenharmony_ci /// Returns `Ok(true)` if the signature is valid, `Ok(false)` if the signature is invalid, and `Err` if an error 36492f3ab15Sopenharmony_ci /// occurred. 36592f3ab15Sopenharmony_ci /// 36692f3ab15Sopenharmony_ci /// Requires OpenSSL 1.1.1 or newer. 36792f3ab15Sopenharmony_ci #[corresponds(EVP_DigestVerify)] 36892f3ab15Sopenharmony_ci #[cfg(ossl111)] 36992f3ab15Sopenharmony_ci #[inline] 37092f3ab15Sopenharmony_ci pub fn digest_verify(&mut self, data: &[u8], signature: &[u8]) -> Result<bool, ErrorStack> { 37192f3ab15Sopenharmony_ci unsafe { 37292f3ab15Sopenharmony_ci let r = cvt(ffi::EVP_DigestVerify( 37392f3ab15Sopenharmony_ci self.as_ptr(), 37492f3ab15Sopenharmony_ci signature.as_ptr(), 37592f3ab15Sopenharmony_ci signature.len(), 37692f3ab15Sopenharmony_ci data.as_ptr(), 37792f3ab15Sopenharmony_ci data.len(), 37892f3ab15Sopenharmony_ci ))?; 37992f3ab15Sopenharmony_ci Ok(r == 1) 38092f3ab15Sopenharmony_ci } 38192f3ab15Sopenharmony_ci } 38292f3ab15Sopenharmony_ci 38392f3ab15Sopenharmony_ci /// Returns the size of the message digest, i.e. the size of the hash 38492f3ab15Sopenharmony_ci #[corresponds(EVP_MD_CTX_size)] 38592f3ab15Sopenharmony_ci #[inline] 38692f3ab15Sopenharmony_ci pub fn size(&self) -> usize { 38792f3ab15Sopenharmony_ci unsafe { ffi::EVP_MD_CTX_size(self.as_ptr()) as usize } 38892f3ab15Sopenharmony_ci } 38992f3ab15Sopenharmony_ci 39092f3ab15Sopenharmony_ci /// Resets the underlying EVP_MD_CTX instance 39192f3ab15Sopenharmony_ci #[corresponds(EVP_MD_CTX_reset)] 39292f3ab15Sopenharmony_ci #[cfg(ossl111)] 39392f3ab15Sopenharmony_ci #[inline] 39492f3ab15Sopenharmony_ci pub fn reset(&mut self) -> Result<(), ErrorStack> { 39592f3ab15Sopenharmony_ci unsafe { 39692f3ab15Sopenharmony_ci let _ = cvt(ffi::EVP_MD_CTX_reset(self.as_ptr()))?; 39792f3ab15Sopenharmony_ci Ok(()) 39892f3ab15Sopenharmony_ci } 39992f3ab15Sopenharmony_ci } 40092f3ab15Sopenharmony_ci} 40192f3ab15Sopenharmony_ci 40292f3ab15Sopenharmony_ci#[cfg(test)] 40392f3ab15Sopenharmony_cimod test { 40492f3ab15Sopenharmony_ci use super::*; 40592f3ab15Sopenharmony_ci use crate::md::Md; 40692f3ab15Sopenharmony_ci use crate::pkey::PKey; 40792f3ab15Sopenharmony_ci use crate::rsa::Rsa; 40892f3ab15Sopenharmony_ci 40992f3ab15Sopenharmony_ci #[test] 41092f3ab15Sopenharmony_ci fn verify_fail() { 41192f3ab15Sopenharmony_ci let key1 = Rsa::generate(4096).unwrap(); 41292f3ab15Sopenharmony_ci let key1 = PKey::from_rsa(key1).unwrap(); 41392f3ab15Sopenharmony_ci 41492f3ab15Sopenharmony_ci let md = Md::sha256(); 41592f3ab15Sopenharmony_ci let data = b"Some Crypto Text"; 41692f3ab15Sopenharmony_ci 41792f3ab15Sopenharmony_ci let mut ctx = MdCtx::new().unwrap(); 41892f3ab15Sopenharmony_ci ctx.digest_sign_init(Some(md), &key1).unwrap(); 41992f3ab15Sopenharmony_ci ctx.digest_sign_update(data).unwrap(); 42092f3ab15Sopenharmony_ci let mut signature = vec![]; 42192f3ab15Sopenharmony_ci ctx.digest_sign_final_to_vec(&mut signature).unwrap(); 42292f3ab15Sopenharmony_ci 42392f3ab15Sopenharmony_ci let bad_data = b"Some Crypto text"; 42492f3ab15Sopenharmony_ci 42592f3ab15Sopenharmony_ci ctx.digest_verify_init(Some(md), &key1).unwrap(); 42692f3ab15Sopenharmony_ci ctx.digest_verify_update(bad_data).unwrap(); 42792f3ab15Sopenharmony_ci let valid = ctx.digest_verify_final(&signature).unwrap(); 42892f3ab15Sopenharmony_ci assert!(!valid); 42992f3ab15Sopenharmony_ci } 43092f3ab15Sopenharmony_ci 43192f3ab15Sopenharmony_ci #[test] 43292f3ab15Sopenharmony_ci fn verify_success() { 43392f3ab15Sopenharmony_ci let key1 = Rsa::generate(2048).unwrap(); 43492f3ab15Sopenharmony_ci let key1 = PKey::from_rsa(key1).unwrap(); 43592f3ab15Sopenharmony_ci 43692f3ab15Sopenharmony_ci let md = Md::sha256(); 43792f3ab15Sopenharmony_ci let data = b"Some Crypto Text"; 43892f3ab15Sopenharmony_ci 43992f3ab15Sopenharmony_ci let mut ctx = MdCtx::new().unwrap(); 44092f3ab15Sopenharmony_ci ctx.digest_sign_init(Some(md), &key1).unwrap(); 44192f3ab15Sopenharmony_ci ctx.digest_sign_update(data).unwrap(); 44292f3ab15Sopenharmony_ci let mut signature = vec![]; 44392f3ab15Sopenharmony_ci ctx.digest_sign_final_to_vec(&mut signature).unwrap(); 44492f3ab15Sopenharmony_ci 44592f3ab15Sopenharmony_ci let good_data = b"Some Crypto Text"; 44692f3ab15Sopenharmony_ci 44792f3ab15Sopenharmony_ci ctx.digest_verify_init(Some(md), &key1).unwrap(); 44892f3ab15Sopenharmony_ci ctx.digest_verify_update(good_data).unwrap(); 44992f3ab15Sopenharmony_ci let valid = ctx.digest_verify_final(&signature).unwrap(); 45092f3ab15Sopenharmony_ci assert!(valid); 45192f3ab15Sopenharmony_ci } 45292f3ab15Sopenharmony_ci 45392f3ab15Sopenharmony_ci #[test] 45492f3ab15Sopenharmony_ci fn verify_with_public_success() { 45592f3ab15Sopenharmony_ci let rsa = Rsa::generate(2048).unwrap(); 45692f3ab15Sopenharmony_ci let key1 = PKey::from_rsa(rsa.clone()).unwrap(); 45792f3ab15Sopenharmony_ci 45892f3ab15Sopenharmony_ci let md = Md::sha256(); 45992f3ab15Sopenharmony_ci let data = b"Some Crypto Text"; 46092f3ab15Sopenharmony_ci 46192f3ab15Sopenharmony_ci let mut ctx = MdCtx::new().unwrap(); 46292f3ab15Sopenharmony_ci ctx.digest_sign_init(Some(md), &key1).unwrap(); 46392f3ab15Sopenharmony_ci ctx.digest_sign_update(data).unwrap(); 46492f3ab15Sopenharmony_ci let mut signature = vec![]; 46592f3ab15Sopenharmony_ci ctx.digest_sign_final_to_vec(&mut signature).unwrap(); 46692f3ab15Sopenharmony_ci 46792f3ab15Sopenharmony_ci let good_data = b"Some Crypto Text"; 46892f3ab15Sopenharmony_ci 46992f3ab15Sopenharmony_ci // try to verify using only public components of the key 47092f3ab15Sopenharmony_ci let n = rsa.n().to_owned().unwrap(); 47192f3ab15Sopenharmony_ci let e = rsa.e().to_owned().unwrap(); 47292f3ab15Sopenharmony_ci 47392f3ab15Sopenharmony_ci let rsa = Rsa::from_public_components(n, e).unwrap(); 47492f3ab15Sopenharmony_ci let key1 = PKey::from_rsa(rsa).unwrap(); 47592f3ab15Sopenharmony_ci 47692f3ab15Sopenharmony_ci ctx.digest_verify_init(Some(md), &key1).unwrap(); 47792f3ab15Sopenharmony_ci ctx.digest_verify_update(good_data).unwrap(); 47892f3ab15Sopenharmony_ci let valid = ctx.digest_verify_final(&signature).unwrap(); 47992f3ab15Sopenharmony_ci assert!(valid); 48092f3ab15Sopenharmony_ci } 48192f3ab15Sopenharmony_ci 48292f3ab15Sopenharmony_ci #[test] 48392f3ab15Sopenharmony_ci fn verify_md_ctx_size() { 48492f3ab15Sopenharmony_ci let mut ctx = MdCtx::new().unwrap(); 48592f3ab15Sopenharmony_ci ctx.digest_init(Md::sha224()).unwrap(); 48692f3ab15Sopenharmony_ci assert_eq!(Md::sha224().size(), ctx.size()); 48792f3ab15Sopenharmony_ci assert_eq!(Md::sha224().size(), 28); 48892f3ab15Sopenharmony_ci 48992f3ab15Sopenharmony_ci let mut ctx = MdCtx::new().unwrap(); 49092f3ab15Sopenharmony_ci ctx.digest_init(Md::sha256()).unwrap(); 49192f3ab15Sopenharmony_ci assert_eq!(Md::sha256().size(), ctx.size()); 49292f3ab15Sopenharmony_ci assert_eq!(Md::sha256().size(), 32); 49392f3ab15Sopenharmony_ci 49492f3ab15Sopenharmony_ci let mut ctx = MdCtx::new().unwrap(); 49592f3ab15Sopenharmony_ci ctx.digest_init(Md::sha384()).unwrap(); 49692f3ab15Sopenharmony_ci assert_eq!(Md::sha384().size(), ctx.size()); 49792f3ab15Sopenharmony_ci assert_eq!(Md::sha384().size(), 48); 49892f3ab15Sopenharmony_ci 49992f3ab15Sopenharmony_ci let mut ctx = MdCtx::new().unwrap(); 50092f3ab15Sopenharmony_ci ctx.digest_init(Md::sha512()).unwrap(); 50192f3ab15Sopenharmony_ci assert_eq!(Md::sha512().size(), ctx.size()); 50292f3ab15Sopenharmony_ci assert_eq!(Md::sha512().size(), 64); 50392f3ab15Sopenharmony_ci } 50492f3ab15Sopenharmony_ci 50592f3ab15Sopenharmony_ci #[test] 50692f3ab15Sopenharmony_ci #[cfg(ossl111)] 50792f3ab15Sopenharmony_ci fn verify_md_ctx_reset() { 50892f3ab15Sopenharmony_ci let hello_expected = 50992f3ab15Sopenharmony_ci hex::decode("185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969") 51092f3ab15Sopenharmony_ci .unwrap(); 51192f3ab15Sopenharmony_ci let world_expected = 51292f3ab15Sopenharmony_ci hex::decode("78ae647dc5544d227130a0682a51e30bc7777fbb6d8a8f17007463a3ecd1d524") 51392f3ab15Sopenharmony_ci .unwrap(); 51492f3ab15Sopenharmony_ci // Calculate SHA-256 digest of "Hello" 51592f3ab15Sopenharmony_ci let mut ctx = MdCtx::new().unwrap(); 51692f3ab15Sopenharmony_ci ctx.digest_init(Md::sha256()).unwrap(); 51792f3ab15Sopenharmony_ci ctx.digest_update(b"Hello").unwrap(); 51892f3ab15Sopenharmony_ci let mut result = vec![0; 32]; 51992f3ab15Sopenharmony_ci let result_len = ctx.digest_final(result.as_mut_slice()).unwrap(); 52092f3ab15Sopenharmony_ci assert_eq!(result_len, result.len()); 52192f3ab15Sopenharmony_ci // Validate result of "Hello" 52292f3ab15Sopenharmony_ci assert_eq!(result, hello_expected); 52392f3ab15Sopenharmony_ci 52492f3ab15Sopenharmony_ci // Create new context 52592f3ab15Sopenharmony_ci let mut ctx = MdCtx::new().unwrap(); 52692f3ab15Sopenharmony_ci // Initialize and update to "Hello" 52792f3ab15Sopenharmony_ci ctx.digest_init(Md::sha256()).unwrap(); 52892f3ab15Sopenharmony_ci ctx.digest_update(b"Hello").unwrap(); 52992f3ab15Sopenharmony_ci // Now reset, init to SHA-256 and use "World" 53092f3ab15Sopenharmony_ci ctx.reset().unwrap(); 53192f3ab15Sopenharmony_ci ctx.digest_init(Md::sha256()).unwrap(); 53292f3ab15Sopenharmony_ci ctx.digest_update(b"World").unwrap(); 53392f3ab15Sopenharmony_ci 53492f3ab15Sopenharmony_ci let mut reset_result = vec![0; 32]; 53592f3ab15Sopenharmony_ci let result_len = ctx.digest_final(reset_result.as_mut_slice()).unwrap(); 53692f3ab15Sopenharmony_ci assert_eq!(result_len, reset_result.len()); 53792f3ab15Sopenharmony_ci // Validate result of digest of "World" 53892f3ab15Sopenharmony_ci assert_eq!(reset_result, world_expected); 53992f3ab15Sopenharmony_ci } 54092f3ab15Sopenharmony_ci} 541