use std::array::from_fn;
use rand::thread_rng;
use crate::{Reason, Word, bail};
pub fn random_iv<W, const N: usize>() -> [W; N]
where
W: Word,
{
let mut rng = thread_rng();
from_fn(|_| W::random(&mut rng))
}
pub fn random_nonce_and_counter<W, const N: usize>() -> [W; N]
where
W: Word,
{
let mut rng = thread_rng();
from_fn(|i| match i {
n if n == N - 1 => W::ZERO,
_ => W::random(&mut rng),
})
}
pub fn pkcs7(buf: &mut Vec<u8>, bs: usize, pad: bool) -> Result<usize, Reason> {
if pad {
let rem = buf.len() % bs;
let pad_count = if rem > 0 { bs - rem } else { bs };
buf.extend(std::iter::repeat_n(pad_count as u8, pad_count));
return Ok(rem);
}
let len = buf.len();
bail!(len == 0 || len % bs != 0, Reason::Padding);
let pad_len = *buf.last().unwrap() as usize;
bail!(
pad_len == 0 || pad_len > bs,
Reason::Padding,
!buf[len - pad_len..]
.iter()
.all(|element| *element == pad_len as u8),
Reason::Padding
);
let padding = len - pad_len;
buf.truncate(padding);
Ok(pad_len)
}
#[cfg(test)]
mod tests {
use super::pkcs7;
use crate::Reason;
#[test]
fn pad_aligned_data() {
let mut data = vec![1, 2, 3, 4, 5, 6, 7, 8];
let block_size = 8;
let rem = pkcs7(&mut data, block_size, true).unwrap();
assert_eq!(rem, 0); assert_eq!(data.len(), 16);
assert_eq!(&data[8..], &[8; 8]); }
#[test]
fn pad_unaligned_data() {
let mut data = b"hello".to_vec(); let block_size = 8;
let rem = pkcs7(&mut data, block_size, true).unwrap();
assert_eq!(rem, 5);
assert_eq!(data.len(), 8);
assert_eq!(&data[5..], &[3, 3, 3]);
}
#[test]
fn unpad_valid_data() {
let mut data = b"world\x03\x03\x03".to_vec();
let block_size = 8;
let pad_len = pkcs7(&mut data, block_size, false).unwrap();
assert_eq!(pad_len, 3);
assert_eq!(data, b"world");
}
#[test]
fn unpad_full_block_padding() {
let mut data = b"messages\x08\x08\x08\x08\x08\x08\x08\x08".to_vec();
let block_size = 8;
let pad_len = pkcs7(&mut data, block_size, false).unwrap();
assert_eq!(pad_len, 8);
assert_eq!(data, b"messages");
}
#[test]
fn unpad_invalid_trailing_bytes() {
let mut data = b"bad\x04\x04\x04\x02".to_vec(); let block_size = 4;
let result = pkcs7(&mut data, block_size, false);
assert!(matches!(result, Err(Reason::Padding)));
}
#[test]
fn unpad_invalid_padding_length_too_large() {
let mut data = b"invalid\x09\x09\x09\x09\x09\x09\x09\x09\x09".to_vec(); let block_size = 8;
let result = pkcs7(&mut data, block_size, false);
assert!(matches!(result, Err(Reason::Padding)));
}
#[test]
fn unpad_invalid_buffer_not_multiple_of_block_size() {
let mut data = b"oops\x04\x04\x04".to_vec(); let block_size = 8;
let result = pkcs7(&mut data, block_size, false);
assert!(matches!(result, Err(Reason::Padding)));
}
#[test]
fn unpad_empty_buffer() {
let mut data = vec![];
let block_size = 8;
let result = pkcs7(&mut data, block_size, false);
assert!(matches!(result, Err(Reason::Padding)));
}
}