#[cfg(all(
feature = "aes-drbg",
feature = "bearssl-aes",
feature = "debug-drbg-interop"
))]
use alloc::format;
#[cfg(all(
feature = "aes-drbg",
feature = "bearssl-aes",
feature = "debug-drbg-interop"
))]
use alloc::string::String;
#[cfg(all(
feature = "aes-drbg",
feature = "bearssl-aes",
feature = "debug-drbg-interop"
))]
use alloc::vec::Vec;
#[cfg(all(
feature = "aes-drbg",
feature = "bearssl-aes",
feature = "debug-drbg-interop"
))]
use rand_core::{
Rng,
TryCryptoRng,
TryRng,
};
#[cfg(all(
feature = "aes-drbg",
feature = "bearssl-aes",
feature = "debug-drbg-interop"
))]
use crate::aes_ctr_drbg::Aes256CtrDrbg;
#[cfg(all(
feature = "aes-drbg",
feature = "bearssl-aes",
feature = "debug-drbg-interop"
))]
use crate::bearssl_aes_ctr_drbg::BearSslAes256CtrDrbg;
#[cfg(all(
feature = "aes-drbg",
feature = "bearssl-aes",
feature = "debug-drbg-interop"
))]
pub struct DualModeDrbg {
primary: BearSslAes256CtrDrbg,
secondary: Aes256CtrDrbg,
generation_count: usize,
log_buffer: Vec<String>,
}
#[cfg(all(
feature = "aes-drbg",
feature = "bearssl-aes",
feature = "debug-drbg-interop"
))]
impl DualModeDrbg {
pub fn new(primary: BearSslAes256CtrDrbg, secondary: Aes256CtrDrbg) -> Self {
Self {
primary,
secondary,
generation_count: 0,
log_buffer: Vec::new(),
}
}
pub fn get_logs(&self) -> &[String] {
&self.log_buffer
}
pub fn clear_logs(&mut self) {
self.log_buffer.clear();
}
fn log_comparison(&mut self, primary_output: &[u8], secondary_output: &[u8]) {
let matches = primary_output == secondary_output;
let log_entry = format!(
"Generation #{}: {} bytes - Match: {} | BearSSL: {:02x?}... | Rust: {:02x?}...",
self.generation_count,
primary_output.len(),
matches,
&primary_output[..core::cmp::min(8, primary_output.len())],
&secondary_output[..core::cmp::min(8, secondary_output.len())]
);
self.log_buffer.push(log_entry);
}
}
#[cfg(all(
feature = "aes-drbg",
feature = "bearssl-aes",
feature = "debug-drbg-interop"
))]
impl TryRng for DualModeDrbg {
type Error = core::convert::Infallible;
fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
self.generation_count += 1;
let primary_val = self.primary.next_u32();
let secondary_val = self.secondary.next_u32();
if primary_val != secondary_val {
let log = format!(
"Generation #{} (u32): BearSSL={:08x}, Rust={:08x}",
self.generation_count, primary_val, secondary_val
);
self.log_buffer.push(log);
}
Ok(primary_val)
}
fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
self.generation_count += 1;
let primary_val = self.primary.next_u64();
let secondary_val = self.secondary.next_u64();
if primary_val != secondary_val {
let log = format!(
"Generation #{} (u64): BearSSL={:016x}, Rust={:016x}",
self.generation_count, primary_val, secondary_val
);
self.log_buffer.push(log);
}
Ok(primary_val)
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Self::Error> {
self.generation_count += 1;
self.primary.fill_bytes(dest);
let primary_output = dest.to_vec();
let mut secondary_output = vec![0u8; dest.len()];
self.secondary.fill_bytes(&mut secondary_output);
self.log_comparison(&primary_output, &secondary_output);
Ok(())
}
}
#[cfg(all(
feature = "aes-drbg",
feature = "bearssl-aes",
feature = "debug-drbg-interop"
))]
impl TryCryptoRng for DualModeDrbg {}