Skip to content

Commit 25491d7

Browse files
Add copy to MdCtxRef
Add a copy method to MdCtxRef based on EVP_MD_CTX_copy_ex.
1 parent 9f29412 commit 25491d7

File tree

1 file changed

+45
-1
lines changed

1 file changed

+45
-1
lines changed

openssl/src/md_ctx.rs

+45-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ use std::ptr;
9494

9595
cfg_if! {
9696
if #[cfg(any(ossl110, boringssl, libressl382))] {
97-
use ffi::{EVP_MD_CTX_free, EVP_MD_CTX_new};
97+
use ffi::{EVP_MD_CTX_free, EVP_MD_CTX_new, EVP_MD_CTX_copy_ex};
9898
} else {
9999
use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free};
100100
}
@@ -397,6 +397,16 @@ impl MdCtxRef {
397397
Ok(())
398398
}
399399
}
400+
401+
/// Copies the EVP_MD_CTX if `in_` into `self`.
402+
///
403+
/// This can be used to efficiently digest different data with the same prefix.
404+
#[corresponds(EVP_MD_CTX_copy_ex)]
405+
#[inline]
406+
pub fn copy(&mut self, in_: &Self) -> Result<(), ErrorStack> {
407+
unsafe { cvt(EVP_MD_CTX_copy_ex(self.as_ptr(), in_.as_ptr()))? };
408+
Ok(())
409+
}
400410
}
401411

402412
#[cfg(test)]
@@ -502,6 +512,40 @@ mod test {
502512
assert_eq!(Md::sha512().size(), 64);
503513
}
504514

515+
#[test]
516+
fn verify_md_ctx_copy() {
517+
let hello_world_expected =
518+
hex::decode("872e4e50ce9990d8b041330c47c9ddd11bec6b503ae9386a99da8584e9bb12c4")
519+
.unwrap();
520+
let hello_there_expected =
521+
hex::decode("aeaef02301bb0fc74af5bb81cee93f086b1e39159fc41319b47db3e8d1998348")
522+
.unwrap();
523+
// Create context with initial shared data
524+
let mut ctx_world = MdCtx::new().unwrap();
525+
ctx_world.digest_init(Md::sha256()).unwrap();
526+
ctx_world.digest_update(b"Hello").unwrap();
527+
528+
// Copy the context into another
529+
let mut ctx_there = MdCtx::new().unwrap();
530+
ctx_there.copy(&ctx_world).unwrap();
531+
532+
// Update both contexts with different data
533+
ctx_world.digest_update(b"World").unwrap();
534+
ctx_there.digest_update(b"There").unwrap();
535+
536+
// Validate result of digest of "HelloWorld"
537+
let mut result_world = vec![0; 32];
538+
let result_len = ctx_world.digest_final(result_world.as_mut_slice()).unwrap();
539+
assert_eq!(result_len, hello_world_expected.len());
540+
assert_eq!(result_world, hello_world_expected);
541+
542+
// Validate result of digest of "HelloThere"
543+
let mut result_there = vec![0; 32];
544+
let result_len = ctx_there.digest_final(result_there.as_mut_slice()).unwrap();
545+
assert_eq!(result_len, hello_there_expected.len());
546+
assert_eq!(result_there, hello_there_expected);
547+
}
548+
505549
#[test]
506550
#[cfg(ossl111)]
507551
fn verify_md_ctx_reset() {

0 commit comments

Comments
 (0)