Skip to content

Commit af04efe

Browse files
committed
feat(rust): add copy() to SHA256 and SHA384
Add copy(&mut self) methods backed by wc_Sha256Copy/wc_Sha384Copy for transcript snapshotting (e.g. TLS handshake hashing). Uses &mut self (not Clone trait) because wc_ShaCopy may mutate src on some platforms. Initializes dst before calling Copy to avoid passing uninitialized memory to wc_ShaFree inside the C function. Includes unit tests verifying independent copy semantics with externally computed SHA-256/SHA-384 test vectors.
1 parent fc51a38 commit af04efe

2 files changed

Lines changed: 84 additions & 0 deletions

File tree

wrapper/rust/wolfssl-wolfcrypt/src/sha.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,28 @@ impl SHA256 {
635635
}
636636
Ok(())
637637
}
638+
639+
}
640+
641+
#[cfg(sha256)]
642+
impl SHA256 {
643+
/// Copy the SHA-256 state into a new independent instance via `wc_Sha256Copy`.
644+
///
645+
/// Allows the same in-progress computation to be continued independently
646+
/// from the same point, e.g. for transcript snapshotting in TLS.
647+
///
648+
/// Takes `&mut self` because `wc_Sha256Copy` may mutate `src` on some
649+
/// platforms (e.g. MAXQ10XX).
650+
pub fn copy(&mut self) -> Result<Self, i32> {
651+
let mut dst = Self::new()?;
652+
let rc = unsafe {
653+
sys::wc_Sha256Copy(&mut self.wc_sha256, &mut dst.wc_sha256)
654+
};
655+
if rc != 0 {
656+
return Err(rc);
657+
}
658+
Ok(dst)
659+
}
638660
}
639661

640662
#[cfg(sha256)]
@@ -846,6 +868,28 @@ impl SHA384 {
846868
}
847869
Ok(())
848870
}
871+
872+
}
873+
874+
#[cfg(sha384)]
875+
impl SHA384 {
876+
/// Copy the SHA-384 state into a new independent instance via `wc_Sha384Copy`.
877+
///
878+
/// Allows the same in-progress computation to be continued independently
879+
/// from the same point, e.g. for transcript snapshotting in TLS.
880+
///
881+
/// Takes `&mut self` because `wc_Sha384Copy` may mutate `src` on some
882+
/// platforms (e.g. MAXQ10XX).
883+
pub fn copy(&mut self) -> Result<Self, i32> {
884+
let mut dst = Self::new()?;
885+
let rc = unsafe {
886+
sys::wc_Sha384Copy(&mut self.wc_sha384, &mut dst.wc_sha384)
887+
};
888+
if rc != 0 {
889+
return Err(rc);
890+
}
891+
Ok(dst)
892+
}
849893
}
850894

851895
#[cfg(sha384)]

wrapper/rust/wolfssl-wolfcrypt/tests/test_sha.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,26 @@ fn test_sha256() {
7272
b"\xFF\xE0\x54\xFE\x7A\xE0\xCB\x6D\xC6\x5C\x3A\xF9\xB6\x1D\x52\x09\xF4\x39\x85\x1D\xB4\x3D\x0B\xA5\x99\x73\x37\xDF\x15\x46\x68\xEB");
7373
}
7474

75+
#[test]
76+
#[cfg(sha256)]
77+
fn test_sha256_copy() {
78+
let mut sha = SHA256::new().expect("Error with new()");
79+
sha.update(b"abc").expect("Error with update()");
80+
81+
let mut copy = sha.copy().expect("Error with copy()");
82+
83+
// Finalize original: SHA-256("abc")
84+
let mut hash_orig = [0u8; SHA256::DIGEST_SIZE];
85+
sha.finalize(&mut hash_orig).expect("Error with finalize()");
86+
assert_eq!(hash_orig, *b"\xBA\x78\x16\xBF\x8F\x01\xCF\xEA\x41\x41\x40\xDE\x5D\xAE\x22\x23\xB0\x03\x61\xA3\x96\x17\x7A\x9C\xB4\x10\xFF\x61\xF2\x00\x15\xAD");
87+
88+
// Continue copy with "def", finalize: SHA-256("abcdef")
89+
copy.update(b"def").expect("Error with update()");
90+
let mut hash_copy = [0u8; SHA256::DIGEST_SIZE];
91+
copy.finalize(&mut hash_copy).expect("Error with finalize()");
92+
assert_eq!(hash_copy, *b"\xBE\xF5\x7E\xC7\xF5\x3A\x6D\x40\xBE\xB6\x40\xA7\x80\xA6\x39\xC8\x3B\xC2\x9A\xC8\xA9\x81\x6F\x1F\xC6\xC5\xC6\xDC\xD9\x3C\x47\x21");
93+
}
94+
7595
#[test]
7696
#[cfg(sha384)]
7797
fn test_sha384() {
@@ -95,6 +115,26 @@ fn test_sha384() {
95115
b"\x09\x33\x0c\x33\xf7\x11\x47\xe8\x3d\x19\x2f\xc7\x82\xcd\x1b\x47\x53\x11\x1b\x17\x3b\x3b\x05\xd2\x2f\xa0\x80\x86\xe3\xb0\xf7\x12\xfc\xc7\xc7\x1a\x55\x7e\x2d\xb9\x66\xc3\xe9\xfa\x91\x74\x60\x39");
96116
}
97117

118+
#[test]
119+
#[cfg(sha384)]
120+
fn test_sha384_copy() {
121+
let mut sha = SHA384::new().expect("Error with new()");
122+
sha.update(b"abc").expect("Error with update()");
123+
124+
let mut copy = sha.copy().expect("Error with copy()");
125+
126+
// Finalize original: SHA-384("abc")
127+
let mut hash_orig = [0u8; SHA384::DIGEST_SIZE];
128+
sha.finalize(&mut hash_orig).expect("Error with finalize()");
129+
assert_eq!(hash_orig, *b"\xcb\x00\x75\x3f\x45\xa3\x5e\x8b\xb5\xa0\x3d\x69\x9a\xc6\x50\x07\x27\x2c\x32\xab\x0e\xde\xd1\x63\x1a\x8b\x60\x5a\x43\xff\x5b\xed\x80\x86\x07\x2b\xa1\xe7\xcc\x23\x58\xba\xec\xa1\x34\xc8\x25\xa7");
130+
131+
// Continue copy with "def", finalize: SHA-384("abcdef")
132+
copy.update(b"def").expect("Error with update()");
133+
let mut hash_copy = [0u8; SHA384::DIGEST_SIZE];
134+
copy.finalize(&mut hash_copy).expect("Error with finalize()");
135+
assert_eq!(hash_copy, *b"\xc6\xa4\xc6\x5b\x22\x7e\x73\x87\xb9\xc3\xe8\x39\xd4\x48\x69\xc4\xcf\xca\x3e\xf5\x83\xde\xa6\x41\x17\x85\x9b\x80\x8c\x1e\x3d\x8a\xe6\x89\xe1\xe3\x14\xee\xef\x52\xa6\xff\xe2\x26\x81\xaa\x11\xf5");
136+
}
137+
98138
#[test]
99139
#[cfg(sha512)]
100140
fn test_sha512() {

0 commit comments

Comments
 (0)