diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/hmac.rs b/wrapper/rust/wolfssl-wolfcrypt/src/hmac.rs index b1d004006c..11a05adbbd 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/hmac.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/hmac.rs @@ -330,6 +330,24 @@ impl HMAC { } } +impl Clone for HMAC { + /// Deep-copy the HMAC state via `wc_HmacCopy()`. + /// + /// Panics if the underlying wolfSSL copy fails. + fn clone(&self) -> Self { + let mut wc_hmac: MaybeUninit = MaybeUninit::uninit(); + let rc = unsafe { + sys::wc_HmacCopy(&self.wc_hmac as *const _ as *mut _, + wc_hmac.as_mut_ptr()) + }; + if rc != 0 { + panic!("wc_HmacCopy() failed: {}", rc); + } + let wc_hmac = unsafe { wc_hmac.assume_init() }; + HMAC { wc_hmac } + } +} + impl Drop for HMAC { /// Safely free the underlying wolfSSL Hmac context. /// diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/hmac_mac.rs b/wrapper/rust/wolfssl-wolfcrypt/src/hmac_mac.rs index 452debaa22..e5060d6f8d 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/hmac_mac.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/hmac_mac.rs @@ -42,6 +42,7 @@ macro_rules! impl_hmac_mac { $name:ident, hmac_type = $hmac_type:expr, key = $key_size:ty, out = $out_size:ty ) => { $(#[$attr])* + #[derive(Clone)] pub struct $name { hmac: crate::hmac::HMAC, } diff --git a/wrapper/rust/wolfssl-wolfcrypt/tests/test_hmac_mac.rs b/wrapper/rust/wolfssl-wolfcrypt/tests/test_hmac_mac.rs index 6a7067b0ee..fab799bae6 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/tests/test_hmac_mac.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/tests/test_hmac_mac.rs @@ -40,6 +40,27 @@ fn test_hmac_sha256_mac_finalize() { assert_eq!(result.as_bytes().as_slice(), expected); } +#[test] +fn test_hmac_sha256_mac_clone() { + let key = b"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"; + let prefix = b"Hi "; + let suffix = b"There"; + let expected = b"\xb0\x34\x4c\x61\xd8\xdb\x38\x53\x5c\xa8\xaf\xce\xaf\x0b\xf1\x2b\x88\x1d\xc2\x00\xc9\x83\x3d\xa7\x26\xe9\x37\x6c\x2e\x32\xcf\xf7"; + + let mut mac = HmacSha256::new_from_slice(key) + .expect("HMAC init failed"); + mac.update(prefix); + + let mut forked = mac.clone(); + forked.update(suffix); + let forked_tag = forked.finalize(); + assert_eq!(forked_tag.as_bytes().as_slice(), expected); + + mac.update(suffix); + let original_tag = mac.finalize(); + assert_eq!(original_tag.as_bytes().as_slice(), expected); +} + #[test] fn test_hmac_sha256_mac_verify_fail() { let key = b"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b";