use crate::ffi;
use libc::c_void;
pub fn memzero(x: &mut [u8]) {
unsafe {
ffi::sodium_memzero(x.as_mut_ptr() as *mut c_void, x.len());
}
}
pub fn memcmp(x: &[u8], y: &[u8]) -> bool {
if x.len() != y.len() {
return false;
}
unsafe {
ffi::sodium_memcmp(
x.as_ptr() as *mut c_void,
y.as_ptr() as *mut c_void,
x.len(),
) == 0
}
}
pub fn increment_le(x: &mut [u8]) {
unsafe {
ffi::sodium_increment(x.as_mut_ptr(), x.len());
}
}
pub fn pad(mut buf: Vec<u8>, blocksize: usize) -> Result<Vec<u8>, ()> {
let unpadded_buflen = buf.len();
let max_buflen = unpadded_buflen + blocksize;
let mut padded_buflen = 0;
if max_buflen <= unpadded_buflen {
return Err(());
}
buf.resize(max_buflen, 0);
let error = unsafe {
ffi::sodium_pad(
&mut padded_buflen,
buf.as_mut_ptr(),
unpadded_buflen,
blocksize,
max_buflen,
)
};
assert!(error == 0, "sodium_pad: unsatisfied precondition?!");
assert!(padded_buflen <= max_buflen, "math is broken?!");
assert!(padded_buflen > unpadded_buflen, "no padding added?!");
buf.truncate(padded_buflen);
Ok(buf)
}
pub fn unpad(buf: &[u8], blocksize: usize) -> Result<&[u8], ()> {
let padded_buflen = buf.len();
let mut unpadded_buflen = 0;
let error =
unsafe { ffi::sodium_unpad(&mut unpadded_buflen, buf.as_ptr(), padded_buflen, blocksize) };
if error != 0 {
return Err(());
}
assert!(unpadded_buflen < padded_buflen, "no padding?!");
Ok(&buf[..unpadded_buflen])
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_memcmp() {
use crate::randombytes::randombytes;
unwrap!(crate::init());
for i in 0usize..256 {
let x = randombytes(i);
assert!(memcmp(&x, &x));
let mut y = x.clone();
assert!(memcmp(&x, &y));
y.push(0);
assert!(!memcmp(&x, &y));
assert!(!memcmp(&y, &x));
y = randombytes(i);
if x == y {
assert!(memcmp(&x, &y))
} else {
assert!(!memcmp(&x, &y))
}
}
}
#[test]
fn test_increment_le_zero() {
unwrap!(crate::init());
for i in 1usize..256 {
let mut x = vec![0u8; i];
increment_le(&mut x);
assert!(!x.iter().all(|x| *x == 0));
let mut y = vec![0u8; i];
y[0] += 1;
assert_eq!(x, y);
}
}
#[test]
fn test_increment_le_vectors() {
unwrap!(crate::init());
let mut x = [255, 2, 3, 4, 5];
let y = [0, 3, 3, 4, 5];
increment_le(&mut x);
assert!(!x.iter().all(|x| *x == 0));
assert_eq!(x, y);
let mut x = [255, 255, 3, 4, 5];
let y = [0, 0, 4, 4, 5];
increment_le(&mut x);
assert!(!x.iter().all(|x| *x == 0));
assert_eq!(x, y);
let mut x = [255, 255, 255, 4, 5];
let y = [0, 0, 0, 5, 5];
increment_le(&mut x);
assert!(!x.iter().all(|x| *x == 0));
assert_eq!(x, y);
let mut x = [255, 255, 255, 255, 5];
let y = [0, 0, 0, 0, 6];
increment_le(&mut x);
assert!(!x.iter().all(|x| *x == 0));
assert_eq!(x, y);
let mut x = [255, 255, 255, 255, 255];
let y = [0, 0, 0, 0, 0];
increment_le(&mut x);
assert!(x.iter().all(|x| *x == 0));
assert_eq!(x, y);
}
#[test]
fn test_increment_le_overflow() {
unwrap!(crate::init());
for i in 1usize..256 {
let mut x = vec![255u8; i];
increment_le(&mut x);
assert!(x.iter().all(|xi| *xi == 0));
}
}
#[test]
fn test_padding_not_multiple_of_blocksize() {
unwrap!(crate::init());
let v = vec![1, 2, 3, 4, 5, 6, 7];
let p = unwrap!(pad(v.clone(), 5));
let u = unwrap!(unpad(&p, 5));
assert!(p.len() == 10);
assert!(u == &v[..]);
}
#[test]
fn test_padding_multiple_of_blocksize() {
unwrap!(crate::init());
let v = vec![1, 2, 3, 4, 5, 6];
let p = unwrap!(pad(v.clone(), 3));
let u = unwrap!(unpad(&p, 3));
assert!(p.len() == 9);
assert!(u == &v[..]);
}
#[test]
fn test_padding_not_multiple_of_blocksize_pow2() {
unwrap!(crate::init());
let v = vec![1, 2, 3, 4, 5, 6, 7];
let p = unwrap!(pad(v.clone(), 4));
let u = unwrap!(unpad(&p, 4));
assert!(p.len() == 8);
assert!(u == &v[..]);
}
#[test]
fn test_padding_multiple_of_blocksize_pow2() {
unwrap!(crate::init());
let v = vec![1, 2, 3, 4, 5, 6, 7, 8];
let p = unwrap!(pad(v.clone(), 4));
let u = unwrap!(unpad(&p, 4));
assert!(p.len() == 12);
assert!(u == &v[..]);
}
#[test]
fn test_padding_invalid_block_size() {
unwrap!(crate::init());
unwrap_err!(pad(Vec::new(), 0));
let v = vec![0x80];
unwrap_err!(unpad(&v, 0));
let v = unwrap!(pad(Vec::new(), 8));
unwrap_err!(unpad(&v, 4));
}
#[test]
fn test_padding_invalid_padded_size() {
unwrap!(crate::init());
unwrap_err!(unpad(&[], 1));
let mut v = unwrap!(pad(vec![42], 1337));
let _ = v.pop();
unwrap_err!(unpad(&v, 1337));
}
#[test]
fn test_padding_invalid_padded_data() {
unwrap!(crate::init());
let mut v = unwrap!(pad(vec![42], 128));
*v.last_mut().expect("non-empty") = 99;
unwrap_err!(unpad(&v, 128));
}
}