use crate::err::Error;
use crate::internal::KcApi;
#[derive(Clone)]
pub enum RngType {
JitterEntropy,
DrbgNoprHmacSha256,
DrbgNoprHmacSha384,
DrbgNoprHmacSha512,
DrbgNoprSha256,
DrbgNoprSha384,
DrbgNoprSha512,
DrbgNoprCtrAes128,
DrbgNoprCtrAes192,
DrbgNoprCtrAes256,
DrbgPrHmacSha256,
DrbgPrHmacSha384,
DrbgPrHmacSha512,
DrbgPrSha256,
DrbgPrSha384,
DrbgPrSha512,
DrbgPrCtrAes128,
DrbgPrCtrAes192,
DrbgPrCtrAes256,
}
impl RngType {
#[allow(clippy::unused_self)]
#[must_use]
pub fn get_type(&self) -> &'static str {
"rng"
}
#[must_use]
pub fn get_name(&self) -> &'static str {
match self {
Self::JitterEntropy => "jitterentropy_rng",
Self::DrbgNoprHmacSha256 => "drbg_nopr_hmac_sha256",
Self::DrbgNoprHmacSha384 => "drbg_nopr_hmac_sha384",
Self::DrbgNoprHmacSha512 => "drbg_nopr_hmac_sha512",
Self::DrbgNoprSha256 => "drbg_nopr_sha256",
Self::DrbgNoprSha384 => "drbg_nopr_sha384",
Self::DrbgNoprSha512 => "drbg_nopr_sha512",
Self::DrbgNoprCtrAes128 => "drbg_nopr_ctr_aes128",
Self::DrbgNoprCtrAes192 => "drbg_nopr_ctr_aes192",
Self::DrbgNoprCtrAes256 => "drbg_nopr_ctr_aes256",
Self::DrbgPrHmacSha256 => "drbg_pr_hmac_sha256",
Self::DrbgPrHmacSha384 => "drbg_pr_hmac_sha384",
Self::DrbgPrHmacSha512 => "drbg_pr_hmac_sha512",
Self::DrbgPrSha256 => "drbg_pr_sha256",
Self::DrbgPrSha384 => "drbg_pr_sha384",
Self::DrbgPrSha512 => "drbg_pr_sha512",
Self::DrbgPrCtrAes128 => "drbg_pr_ctr_aes128",
Self::DrbgPrCtrAes192 => "drbg_pr_ctr_aes192",
Self::DrbgPrCtrAes256 => "drbg_pr_ctr_aes256",
}
}
#[must_use]
pub fn has_prediction_resistance(&self) -> bool {
match self {
Self::DrbgNoprHmacSha256
| Self::DrbgNoprHmacSha384
| Self::DrbgNoprHmacSha512
| Self::DrbgNoprSha256
| Self::DrbgNoprSha384
| Self::DrbgNoprSha512
| Self::DrbgNoprCtrAes128
| Self::DrbgNoprCtrAes192
| Self::DrbgNoprCtrAes256 => false,
Self::JitterEntropy
| Self::DrbgPrHmacSha256
| Self::DrbgPrHmacSha384
| Self::DrbgPrHmacSha512
| Self::DrbgPrSha256
| Self::DrbgPrSha384
| Self::DrbgPrSha512
| Self::DrbgPrCtrAes128
| Self::DrbgPrCtrAes192
| Self::DrbgPrCtrAes256 => true,
}
}
}
pub struct Rng {
api: KcApi,
name: RngType
}
impl Rng {
pub fn new<T>(rng: RngType, seed: &T) -> Result<Self, Error>
where
T: AsRef<[u8]> + Clone,
{
let mut ret = Self {
api: KcApi::new(rng.get_type(), rng.get_name())?,
name: rng
};
ret.api.set_key(seed)?;
ret.api.init()?;
Ok(ret)
}
#[must_use]
pub fn name(&self) -> RngType {
self.name.clone()
}
pub fn get_bytes(&self, dest: &mut [u8]) -> Result<(), Error> {
let sz = self.api.read(dest)?;
if sz == dest.len() {
Ok(())
} else {
Err(Error::Incomplete)
}
}
}
#[cfg(feature = "rand_trait")]
impl rand_core::RngCore for Rng {
fn next_u32(&mut self) -> u32 {
let mut dest = [0_u8; 4];
self.fill_bytes(&mut dest);
u32::from_le_bytes(dest)
}
fn next_u64(&mut self) -> u64 {
let mut dest = [0_u8; 8];
self.fill_bytes(&mut dest);
u64::from_le_bytes(dest)
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
if let Err(e) = self.try_fill_bytes(dest) {
panic!("fill_bytes error : {}", e);
}
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> {
let chunks = dest.chunks_mut(128);
for chunk in chunks {
if let Err(e) = self.get_bytes(chunk) {
return Err(e.into());
}
}
Ok(())
}
}
#[cfg(feature = "rand_trait")]
impl rand_core::CryptoRng for Rng {}
#[cfg(test)]
mod tests {
use super::*;
static RNG_TYPES: &[RngType] = &[
RngType::DrbgNoprHmacSha256,
RngType::DrbgNoprHmacSha384,
RngType::DrbgNoprHmacSha512,
RngType::JitterEntropy,
RngType::DrbgPrHmacSha256,
RngType::DrbgPrHmacSha384,
RngType::DrbgPrHmacSha512,
];
#[test]
fn new() {
for rng in RNG_TYPES {
let seed = [0_u8; 32];
assert!(Rng::new(rng.clone(), &seed).is_ok());
}
}
#[test]
fn bad() {
let seed = [0_u8; 32];
let e = Rng::new(RngType::DrbgPrCtrAes256, &seed);
if let Err(ee) = e {
println!("{}", ee);
}
}
#[test]
fn get_random_bytes() -> Result<(), Error> {
for rng_type in RNG_TYPES {
let seed = [0_u8; 32];
let zero = [0_u8; 32];
let mut data = [0_u8; 32];
let mut data2 = [0_u8; 32];
let rng = Rng::new(rng_type.clone(), &seed)?;
rng.get_bytes(&mut data)?;
assert_ne!(zero, data);
rng.get_bytes(&mut data2)?;
assert_ne!(data, data2);
}
Ok(())
}
}