diff --git a/rust/src/ffi/hashing.rs b/rust/src/ffi/hashing.rs index 0a62772c1c..b1d1c1d4b4 100644 --- a/rust/src/ffi/hashing.rs +++ b/rust/src/ffi/hashing.rs @@ -21,12 +21,14 @@ use sha1::Sha1; use sha2::Sha256; use std::os::raw::c_char; -pub const SC_SHA1_LEN: usize = 20; pub const SC_SHA256_LEN: usize = 32; +pub const SC_SHA1_LEN: usize = 20; +pub const SC_MD5_LEN: usize = 16; // Length of hex digests without trailing NUL. -pub const SC_MD5_HEX_LEN: usize = 32; pub const SC_SHA256_HEX_LEN: usize = 64; +pub const SC_SHA1_HEX_LEN: usize = 40; +pub const SC_MD5_HEX_LEN: usize = 32; // Wrap the Rust Sha256 in a new type named SCSha256 to give this type // the "SC" prefix. The one drawback is we must access the actual context @@ -59,11 +61,13 @@ pub unsafe extern "C" fn SCSha256Finalize(hasher: &mut SCSha256, out: *mut u8, l /// But even given the notes, this appears to be faster than the equivalent that we /// did in C using NSS. #[no_mangle] -pub unsafe extern "C" fn SCSha256FinalizeToHex(hasher: &mut SCSha256, out: *mut c_char, len: u32) { +pub unsafe extern "C" fn SCSha256FinalizeToHex( + hasher: &mut SCSha256, out: *mut c_char, len: u32, +) -> bool { let hasher: Box = Box::from_raw(hasher); let result = hasher.0.finalize(); let hex = format!("{:x}", &result); - crate::ffi::strings::copy_to_c_char(hex, out, len as usize); + crate::ffi::strings::copy_to_c_char(hex, out, len as usize) } /// Free an unfinalized Sha256 context. @@ -87,6 +91,16 @@ pub unsafe extern "C" fn SCSha256HashBuffer( return true; } +#[no_mangle] +pub unsafe extern "C" fn SCSha256HashBufferToHex( + buf: *const u8, buf_len: u32, out: *mut c_char, len: u32, +) -> bool { + let data = std::slice::from_raw_parts(buf, buf_len as usize); + let hash = Sha256::new().chain(data).finalize(); + let hex = format!("{:x}", &hash); + crate::ffi::strings::copy_to_c_char(hex, out, len as usize) +} + // Start of SHA1 C bindings. pub struct SCSha1(Sha1); @@ -108,6 +122,16 @@ pub unsafe extern "C" fn SCSha1Finalize(hasher: &mut SCSha1, out: *mut u8, len: finalize(hasher.0, out, len); } +#[no_mangle] +pub unsafe extern "C" fn SCSha1FinalizeToHex( + hasher: &mut SCSha1, out: *mut c_char, len: u32, +) -> bool { + let hasher: Box = Box::from_raw(hasher); + let result = hasher.0.finalize(); + let hex = format!("{:x}", &result); + crate::ffi::strings::copy_to_c_char(hex, out, len as usize) +} + /// Free an unfinalized Sha1 context. #[no_mangle] pub unsafe extern "C" fn SCSha1Free(hasher: &mut SCSha1) { @@ -129,6 +153,16 @@ pub unsafe extern "C" fn SCSha1HashBuffer( return true; } +#[no_mangle] +pub unsafe extern "C" fn SCSha1HashBufferToHex( + buf: *const u8, buf_len: u32, out: *mut c_char, len: u32, +) -> bool { + let data = std::slice::from_raw_parts(buf, buf_len as usize); + let hash = Sha1::new().chain(data).finalize(); + let hex = format!("{:x}", &hash); + crate::ffi::strings::copy_to_c_char(hex, out, len as usize) +} + // Start of MD5 C bindings. pub struct SCMd5(Md5); @@ -157,11 +191,13 @@ pub unsafe extern "C" fn SCMd5Finalize(hasher: &mut SCMd5, out: *mut u8, len: u3 /// /// Consumes the hash context and cannot be re-used. #[no_mangle] -pub unsafe extern "C" fn SCMd5FinalizeToHex(hasher: &mut SCMd5, out: *mut c_char, len: u32) { +pub unsafe extern "C" fn SCMd5FinalizeToHex( + hasher: &mut SCMd5, out: *mut c_char, len: u32, +) -> bool { let hasher: Box = Box::from_raw(hasher); let result = hasher.0.finalize(); let hex = format!("{:x}", &result); - crate::ffi::strings::copy_to_c_char(hex, out, len as usize); + crate::ffi::strings::copy_to_c_char(hex, out, len as usize) } /// Free an unfinalized Sha1 context. @@ -172,22 +208,28 @@ pub unsafe extern "C" fn SCMd5Free(hasher: &mut SCMd5) { } #[no_mangle] -pub unsafe extern "C" fn SCMd5HashBuffer(buf: *const u8, buf_len: u32, out: *mut u8, len: u32) { +pub unsafe extern "C" fn SCMd5HashBuffer( + buf: *const u8, buf_len: u32, out: *mut u8, len: u32, +) -> bool { + if len as usize != SC_MD5_LEN { + return false; + } let data = std::slice::from_raw_parts(buf, buf_len as usize); let output = std::slice::from_raw_parts_mut(out, len as usize); let hash = Md5::new().chain(data).finalize(); output.copy_from_slice(&hash); + true } /// C binding for a function to MD5 hash a single buffer to a hex string. #[no_mangle] pub unsafe extern "C" fn SCMd5HashBufferToHex( buf: *const u8, buf_len: u32, out: *mut c_char, len: u32, -) { +) -> bool { let data = std::slice::from_raw_parts(buf, buf_len as usize); let hash = Md5::new().chain(data).finalize(); let hex = format!("{:x}", &hash); - crate::ffi::strings::copy_to_c_char(hex, out, len as usize); + crate::ffi::strings::copy_to_c_char(hex, out, len as usize) } // Functions that are generic over Digest. For the most part the C bindings are @@ -230,9 +272,18 @@ mod test { SCSha256Update(hasher, bytes.as_ptr(), bytes.len() as u32); SCSha256Update(hasher, bytes.as_ptr(), bytes.len() as u32); let hex = [0_u8; SC_SHA256_HEX_LEN + 1]; - SCSha256FinalizeToHex(hasher, hex.as_ptr() as *mut c_char, (SC_SHA256_HEX_LEN + 1) as u32); - let string = std::ffi::CStr::from_ptr(hex.as_ptr() as *mut c_char).to_str().unwrap(); - assert_eq!(string, "22a48051594c1949deed7040850c1f0f8764537f5191be56732d16a54c1d8153"); + SCSha256FinalizeToHex( + hasher, + hex.as_ptr() as *mut c_char, + (SC_SHA256_HEX_LEN + 1) as u32, + ); + let string = std::ffi::CStr::from_ptr(hex.as_ptr() as *mut c_char) + .to_str() + .unwrap(); + assert_eq!( + string, + "22a48051594c1949deed7040850c1f0f8764537f5191be56732d16a54c1d8153" + ); } } @@ -250,10 +301,15 @@ mod test { SCMd5Update(hasher, bytes.as_ptr(), bytes.len() as u32); SCMd5Update(hasher, bytes.as_ptr(), bytes.len() as u32); let hex = [0_u8; SC_MD5_HEX_LEN + 1]; - SCMd5FinalizeToHex(hasher, hex.as_ptr() as *mut c_char, (SC_MD5_HEX_LEN + 1) as u32); - let string = std::ffi::CStr::from_ptr(hex.as_ptr() as *mut c_char).to_str().unwrap(); + SCMd5FinalizeToHex( + hasher, + hex.as_ptr() as *mut c_char, + (SC_MD5_HEX_LEN + 1) as u32, + ); + let string = std::ffi::CStr::from_ptr(hex.as_ptr() as *mut c_char) + .to_str() + .unwrap(); assert_eq!(string, "5216ddcc58e8dade5256075e77f642da"); } } - }