From 867340aa30aed9206e1ec94efbc9be8b52906c92 Mon Sep 17 00:00:00 2001 From: "Neal H. Walfield" Date: Fri, 17 Feb 2023 18:28:46 +0100 Subject: [PATCH] Add pgp_random. - Add a function to return some random numbers. --- src/ffi.rs | 13 +++++++++++++ src/lib.rs | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/src/ffi.rs b/src/ffi.rs index f84dbdc..47214fd 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -127,6 +127,19 @@ macro_rules! check_slice { } } +// Checks if a `*mut T` pointer is NULL if so, returns an error. +// Otherwise, returns a slice `&mut [T]` with `l` elements. +macro_rules! check_slice_mut { + ($p:ident, $l:expr) => { + if $p.is_null() { + return Err(Error::IllegalValue( + format!("{} must not be NULL", stringify!($p)))); + } else { + std::slice::from_raw_parts_mut($p as *mut u8, $l) + } + } +} + // Checks if a `*const c_char` pointer is NULL if so, returns an // error. Otherwise, returns a CStr. macro_rules! check_cstr { diff --git a/src/lib.rs b/src/lib.rs index 6e8b4b4..2b97de6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2256,3 +2256,55 @@ ffi!(fn pgp_contains_priv_key(session: *mut Session, fpr: *const c_char, Ok(()) }); + +// PEP_STATUS pgp_random(char *buffer, size_t len) +ffi!(fn pgp_random(buffer: *mut c_char, len: size_t) -> Result<()> { + let buffer = unsafe { check_slice_mut!(buffer, len) }; + openpgp::crypto::random(buffer); + Ok(()) +}); + +#[test] +fn test_random() { + fn rand(i: usize) -> Vec { + let mut buffer = vec![0u8; i]; + let result = pgp_random(buffer.as_mut_ptr() as *mut c_char, i); + assert_eq!(result, 0, "pgp_random does not fail"); + buffer + } + + for _ in 0..32 { + // Get a bunch of bytes, sum them and figure out the average. + let mut total = 0u64; + let mut ones_count = 0u64; + let mut samples = 0; + for i in 0..128 { + let buffer = rand(i); + for e in buffer.into_iter() { + total += e as u64; + ones_count += (e as u8).count_ones() as u64; + samples += 1; + } + } + + // On average we expect: total / samples to be 127.5. Fail if it is + // very unlikely (probability is left as an exercise for the + // reader). + assert!(samples > 0); + let average = total / samples; + eprintln!("{} / {} = {}", total, samples, average); + assert!(128 - 8 < average && average < 128 + 8, + "{} is extremely unlikely, your random number generator \ + is broken", + average); + + // On average, we should have 4 ones. + let average_ones = ones_count / samples; + eprintln!("ones count: {} / {} = {}", + ones_count, samples, average_ones); + assert!(3 * samples <= ones_count && ones_count <= 5 * samples, + "Average number of ones ({}) is extremely unlikely, \ + your random number generator is broken", + average_ones); + } +} -- GitLab