@@ -94,7 +94,7 @@ use std::ptr;
94
94
95
95
cfg_if ! {
96
96
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 } ;
98
98
} else {
99
99
use ffi:: { EVP_MD_CTX_create as EVP_MD_CTX_new , EVP_MD_CTX_destroy as EVP_MD_CTX_free } ;
100
100
}
@@ -397,6 +397,16 @@ impl MdCtxRef {
397
397
Ok ( ( ) )
398
398
}
399
399
}
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
+ }
400
410
}
401
411
402
412
#[ cfg( test) ]
@@ -502,6 +512,40 @@ mod test {
502
512
assert_eq ! ( Md :: sha512( ) . size( ) , 64 ) ;
503
513
}
504
514
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
+
505
549
#[ test]
506
550
#[ cfg( ossl111) ]
507
551
fn verify_md_ctx_reset ( ) {
0 commit comments