use crate::Result;
#[cfg(any(test, feature = "insecure-test-vectors"))]
use crate::rng::insecure_test_vectors::FixedRng;
use crate::rng::{self, CryptoRngAdapter};
pub(crate) trait RandomSource {
fn fill(&mut self, dst: &mut [u8]) -> Result<()>;
fn crypto_rng(&mut self) -> CryptoRngAdapter<'_>;
}
pub(crate) struct OsRandom;
impl RandomSource for OsRandom {
fn fill(&mut self, dst: &mut [u8]) -> Result<()> {
rng::fill_random(dst)
}
fn crypto_rng(&mut self) -> CryptoRngAdapter<'_> {
CryptoRngAdapter::os()
}
}
#[cfg(any(test, feature = "insecure-test-vectors"))]
impl RandomSource for FixedRng {
fn fill(&mut self, dst: &mut [u8]) -> Result<()> {
FixedRng::fill(self, dst)
}
fn crypto_rng(&mut self) -> CryptoRngAdapter<'_> {
CryptoRngAdapter::fixed(self)
}
}
#[cfg(test)]
mod tests {
use p256::elliptic_curve::rand_core::TryRng;
use super::*;
use crate::Error;
#[test]
fn os_bytes_differ_between_two_draws() {
let source: &mut dyn RandomSource = &mut OsRandom;
let (mut a, mut b) = ([0u8; 32], [0u8; 32]);
assert_eq!(source.fill(&mut a), Ok(()));
assert_eq!(source.fill(&mut b), Ok(()));
assert_ne!(a, b);
assert_ne!(a, [0u8; 32]);
let mut c = [0u8; 32];
assert_eq!(source.crypto_rng().try_fill_bytes(&mut c), Ok(()));
assert_ne!(c, a);
assert_ne!(c, b);
}
#[test]
fn fixed_bytes_replay_in_order() {
let mut fixed = FixedRng::new([1u8, 2, 3, 4, 5, 6]);
let source: &mut dyn RandomSource = &mut fixed;
let (mut cek, mut iv) = ([0u8; 2], [0u8; 4]);
assert_eq!(source.fill(&mut cek), Ok(()));
assert_eq!(source.fill(&mut iv), Ok(()));
assert_eq!((cek, iv), ([1, 2], [3, 4, 5, 6]));
assert_eq!(fixed.remaining(), 0);
}
#[test]
fn fixed_source_fails_closed_when_exhausted() {
let mut fixed = FixedRng::new([7u8, 8, 9]);
let source: &mut dyn RandomSource = &mut fixed;
let mut too_long = [0xA5u8; 4];
assert_eq!(
source.fill(&mut too_long),
Err(Error::RandomnessUnavailable)
);
assert_eq!(too_long, [0u8; 4]);
let mut rest = [0u8; 3];
assert_eq!(source.fill(&mut rest), Ok(()));
assert_eq!(rest, [7, 8, 9]);
assert_eq!(
source.crypto_rng().try_fill_bytes(&mut [0u8; 1]),
Err(Error::RandomnessUnavailable)
);
}
#[test]
fn crypto_rng_continues_the_same_fixed_stream() {
let mut fixed = FixedRng::new([1u8, 2, 3, 4, 5, 6, 7, 8]);
let source: &mut dyn RandomSource = &mut fixed;
let mut cek = [0u8; 2];
assert_eq!(source.fill(&mut cek), Ok(()));
let mut seed = [0u8; 3];
assert_eq!(source.crypto_rng().try_fill_bytes(&mut seed), Ok(()));
let mut iv = [0u8; 3];
assert_eq!(source.fill(&mut iv), Ok(()));
assert_eq!((cek, seed, iv), ([1, 2], [3, 4, 5], [6, 7, 8]));
assert_eq!(fixed.remaining(), 0);
}
}