use native_ossl_sys as sys;
#[must_use]
pub fn ct_eq(a: &[u8], b: &[u8]) -> bool {
if a.len() != b.len() {
return false;
}
if a.is_empty() {
return true;
}
let rc = unsafe {
sys::CRYPTO_memcmp(
a.as_ptr().cast::<std::ffi::c_void>(),
b.as_ptr().cast::<std::ffi::c_void>(),
a.len(),
)
};
rc == 0
}
pub struct SecretBuf {
data: Vec<u8>,
}
impl SecretBuf {
#[must_use]
pub fn new(data: Vec<u8>) -> Self {
SecretBuf { data }
}
#[must_use]
pub fn with_len(len: usize) -> Self {
SecretBuf {
data: vec![0u8; len],
}
}
#[must_use]
pub fn from_slice(data: &[u8]) -> Self {
SecretBuf {
data: data.to_vec(),
}
}
#[must_use]
pub fn len(&self) -> usize {
self.data.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
pub fn as_mut_slice(&mut self) -> &mut [u8] {
&mut self.data
}
}
impl AsRef<[u8]> for SecretBuf {
fn as_ref(&self) -> &[u8] {
&self.data
}
}
impl Drop for SecretBuf {
fn drop(&mut self) {
if !self.data.is_empty() {
unsafe {
sys::OPENSSL_cleanse(
self.data.as_mut_ptr().cast::<std::ffi::c_void>(),
self.data.len(),
);
}
}
}
}
unsafe impl Send for SecretBuf {}
unsafe impl Sync for SecretBuf {}
#[cfg(test)]
mod tests {
use super::{ct_eq, SecretBuf};
#[test]
fn ct_eq_equal_slices() {
assert!(ct_eq(b"hello", b"hello"));
}
#[test]
fn ct_eq_different_values() {
assert!(!ct_eq(b"hello", b"world"));
}
#[test]
fn ct_eq_different_lengths() {
assert!(!ct_eq(b"hi", b"hii"));
}
#[test]
fn ct_eq_empty_slices() {
assert!(ct_eq(b"", b""));
}
#[test]
fn ct_eq_one_byte_differ() {
assert!(!ct_eq(&[0u8; 32], &{
let mut v = [0u8; 32];
v[31] = 1;
v
}));
}
#[test]
fn with_len_creates_correct_size() {
let buf = SecretBuf::with_len(32);
assert_eq!(buf.len(), 32);
assert!(!buf.is_empty());
}
#[test]
fn from_slice_copies_data() {
let src = b"secret key material";
let buf = SecretBuf::from_slice(src);
assert_eq!(buf.as_ref(), src);
}
#[test]
fn new_wraps_ownership() {
let v = vec![1u8, 2, 3];
let buf = SecretBuf::new(v);
assert_eq!(buf.as_ref(), &[1, 2, 3]);
}
#[test]
fn empty_buf_is_empty() {
let buf = SecretBuf::new(vec![]);
assert!(buf.is_empty());
}
#[test]
fn as_mut_slice_writes_through() {
let mut buf = SecretBuf::with_len(4);
buf.as_mut_slice().copy_from_slice(&[10, 20, 30, 40]);
assert_eq!(buf.as_ref(), &[10, 20, 30, 40]);
}
}