From 15b55ef2796e8bc5e73e34593047930c0af5c3c8 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Thu, 20 Nov 2025 15:00:31 -0500 Subject: [PATCH] Rust wrapper: add HAVE_HASHDRBG RNG functions --- wrapper/rust/wolfssl/build.rs | 3 + wrapper/rust/wolfssl/src/wolfcrypt/random.rs | 158 +++++++++++++++++++ wrapper/rust/wolfssl/tests/test_random.rs | 25 +++ 3 files changed, 186 insertions(+) diff --git a/wrapper/rust/wolfssl/build.rs b/wrapper/rust/wolfssl/build.rs index de4f95c419..7da0f46051 100644 --- a/wrapper/rust/wolfssl/build.rs +++ b/wrapper/rust/wolfssl/build.rs @@ -165,6 +165,9 @@ fn scan_cfg() -> Result<()> { check_cfg(&binding, "wc_SSH_KDF", "kdf_ssh"); check_cfg(&binding, "wc_Tls13_HKDF_Extract_ex", "kdf_tls13"); + /* random */ + check_cfg(&binding, "wc_RNG_DRBG_Reseed", "random_hashdrbg"); + /* rsa */ check_cfg(&binding, "wc_InitRsaKey", "rsa"); check_cfg(&binding, "wc_RsaDirect", "rsa_direct"); diff --git a/wrapper/rust/wolfssl/src/wolfcrypt/random.rs b/wrapper/rust/wolfssl/src/wolfcrypt/random.rs index b3dafe5264..a4f9b408d0 100644 --- a/wrapper/rust/wolfssl/src/wolfcrypt/random.rs +++ b/wrapper/rust/wolfssl/src/wolfcrypt/random.rs @@ -159,6 +159,132 @@ impl RNG { } } + /// Create and test functionality of DRBG. + /// + /// # Parameters + /// + /// * `nonce`: Optional nonce to use to initialize DRBG. + /// * `seed_a`: Buffer containing seed data (required). + /// * `seed_b`: Optional buffer containing more seed data. If present, the + /// DRBG will be reseeded. + /// * `output`: Output buffer. + /// + /// # Returns + /// + /// Returns either Ok(()) on success or Err(e) containing the wolfSSL + /// library error code value. + /// + /// # Example + /// + /// ```rust + /// #![cfg(random_hashdrbg)] + /// use wolfssl::wolfcrypt::random::RNG; + /// let nonce = [99u8, 88, 77, 66]; + /// let seed_a = [42u8, 33, 55, 88]; + /// let seed_b = [45u8, 10, 20, 30]; + /// let mut output = [0u8; 128]; + /// RNG::health_test(Some(&nonce), &seed_a, Some(&seed_b), &mut output).expect("Error with health_test()"); + /// ``` + #[cfg(random_hashdrbg)] + pub fn health_test(nonce: Option<&[u8]>, seed_a: &[u8], seed_b: Option<&[u8]>, output: &mut [u8]) -> Result<(), i32> { + Self::health_test_ex(nonce, seed_a, seed_b, output, None, None) + } + + /// Create and test functionality of DRBG with optional heap and device ID. + /// + /// # Parameters + /// + /// * `nonce`: Optional nonce to use to initialize DRBG. + /// * `seed_a`: Buffer containing seed data (required). + /// * `seed_b`: Optional buffer containing more seed data. If present, the + /// DRBG will be reseeded. + /// * `output`: Output buffer. + /// * `heap`: Optional heap hint. + /// * `dev_id` Optional device ID to use with crypto callbacks or async hardware. + /// + /// # Returns + /// + /// Returns either Ok(()) on success or Err(e) containing the wolfSSL + /// library error code value. + /// + /// # Example + /// + /// ```rust + /// #![cfg(random_hashdrbg)] + /// use wolfssl::wolfcrypt::random::RNG; + /// let nonce = [99u8, 88, 77, 66]; + /// let seed_a = [42u8, 33, 55, 88]; + /// let seed_b = [45u8, 10, 20, 30]; + /// let mut output = [0u8; 128]; + /// RNG::health_test_ex(Some(&nonce), &seed_a, Some(&seed_b), &mut output, None, None).expect("Error with health_test_ex()"); + /// ``` + #[cfg(random_hashdrbg)] + pub fn health_test_ex(nonce: Option<&[u8]>, seed_a: &[u8], seed_b: Option<&[u8]>, output: &mut [u8], heap: Option<*mut std::os::raw::c_void>, dev_id: Option) -> Result<(), i32> { + let mut nonce_ptr = core::ptr::null(); + let mut nonce_size = 0u32; + if let Some(nonce) = nonce { + nonce_ptr = nonce.as_ptr(); + nonce_size = nonce.len() as u32; + } + let seed_a_size = seed_a.len() as u32; + let mut seed_b_ptr = core::ptr::null(); + let mut seed_b_size = 0u32; + if let Some(seed_b) = seed_b { + seed_b_ptr = seed_b.as_ptr(); + seed_b_size = seed_b.len() as u32; + } + let output_size = output.len() as u32; + let heap = match heap { + Some(heap) => heap, + None => core::ptr::null_mut(), + }; + let dev_id = match dev_id { + Some(dev_id) => dev_id, + None => sys::INVALID_DEVID, + }; + let rc = unsafe { + sys::wc_RNG_HealthTest_ex(if seed_b_size > 0 {1} else {0}, + nonce_ptr, nonce_size, + seed_a.as_ptr(), seed_a_size, + seed_b_ptr, seed_b_size, + output.as_mut_ptr(), output_size, + heap, dev_id) + }; + if rc != 0 { + return Err(rc); + } + Ok(()) + } + + /// Test a seed. + /// + /// # Parameters + /// + /// * `seed`: Buffer containing seed data. + /// + /// # Returns + /// + /// Returns either Ok(()) on success or Err(e) containing the wolfSSL + /// library error code value. + /// + /// # Example + /// + /// ```rust + /// #![cfg(random_hashdrbg)] + /// use wolfssl::wolfcrypt::random::RNG; + /// let seed = [42u8, 33, 55, 88]; + /// RNG::test_seed(&seed).expect("Error with test_seed()"); + /// ``` + #[cfg(random_hashdrbg)] + pub fn test_seed(seed: &[u8]) -> Result<(), i32> { + let seed_size = seed.len() as u32; + let rc = unsafe { sys::wc_RNG_TestSeed(seed.as_ptr(), seed_size) }; + if rc != 0 { + return Err(rc); + } + Ok(()) + } + /// Generate a single cryptographically secure random byte. /// /// This method calls the `wc_RNG_GenerateByte` wolfSSL library function to @@ -202,6 +328,38 @@ impl RNG { Err(rc) } } + + /// Reseed random number generator. + /// + /// # Parameters + /// + /// * `seed`: Buffer with new seed data. + /// + /// # Returns + /// + /// Returns either Ok(()) on success or Err(e) containing the wolfSSL + /// library error code value. + /// + /// # Example + /// + /// ```rust + /// #![cfg(random_hashdrbg)] + /// use wolfssl::wolfcrypt::random::RNG; + /// let mut rng = RNG::new().expect("Failed to create RNG"); + /// let seed = [1u8, 2, 3, 4]; + /// rng.reseed(&seed).expect("Error with reseed()"); + /// ``` + #[cfg(random_hashdrbg)] + pub fn reseed(&mut self, seed: &[u8]) -> Result<(), i32> { + let seed_size = seed.len() as u32; + let rc = unsafe { + sys::wc_RNG_DRBG_Reseed(&mut self.wc_rng, seed.as_ptr(), seed_size) + }; + if rc != 0 { + return Err(rc); + } + Ok(()) + } } impl Drop for RNG { diff --git a/wrapper/rust/wolfssl/tests/test_random.rs b/wrapper/rust/wolfssl/tests/test_random.rs index dbf8fa325e..f7d7cb7946 100644 --- a/wrapper/rust/wolfssl/tests/test_random.rs +++ b/wrapper/rust/wolfssl/tests/test_random.rs @@ -28,6 +28,23 @@ fn test_rng_new_with_nonce_ex_and_drop() { let _rng = RNG::new_with_nonce_ex(&mut nonce, None, None).expect("Failed to create RNG"); } +#[test] +#[cfg(random_hashdrbg)] +fn test_health_test() { + let nonce = [99u8, 88, 77, 66]; + let seed_a = [42u8, 33, 55, 88]; + let seed_b = [45u8, 10, 20, 30]; + let mut output = [0u8; 128]; + RNG::health_test(Some(&nonce), &seed_a, Some(&seed_b), &mut output).expect("Error with health_test()"); +} + +#[test] +#[cfg(random_hashdrbg)] +fn test_test_seed() { + let seed = [42u8, 33, 55, 88]; + RNG::test_seed(&seed).expect("Error with test_seed()"); +} + // Test that generate_byte() returns random values. #[test] fn test_rng_generate_byte() { @@ -70,3 +87,11 @@ fn test_rng_generate_block_u32() { assert_ne!(buffer[buffer.len() - 1], 0u32); assert_ne!(buffer[buffer.len() - 1], 0xFFFF_FFFFu32); } + +#[test] +#[cfg(random_hashdrbg)] +fn test_rng_reseed() { + let mut rng = RNG::new().expect("Failed to create RNG"); + let seed = [1u8, 2, 3, 4]; + rng.reseed(&seed).expect("Error with reseed()"); +}