Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions wrapper/rust/wolfssl/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
158 changes: 158 additions & 0 deletions wrapper/rust/wolfssl/src/wolfcrypt/random.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<i32>) -> 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
Expand Down Expand Up @@ -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 {
Expand Down
25 changes: 25 additions & 0 deletions wrapper/rust/wolfssl/tests/test_random.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -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() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't you add #[cfg(random_hashdrbg)] on top of fn test_rng_reseed(){}? Since the reseed() function method is only compiled when the random_hashdrbg feature is enabled, this test will fail if that feature is not available.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for mentioning! I actually intended to add it to all of these new methods and tests!

let mut rng = RNG::new().expect("Failed to create RNG");
let seed = [1u8, 2, 3, 4];
rng.reseed(&seed).expect("Error with reseed()");
}