use crate::error::{CryptoError, Result};
pub struct Pkcs7Padding;
impl Pkcs7Padding {
pub fn pad(data: &[u8], block_size: usize) -> Result<Vec<u8>> {
if !(2..=255).contains(&block_size) {
return Err(CryptoError::InvalidParameter(format!(
"Invalid block size: {}",
block_size
)));
}
let padding_len = block_size - (data.len() % block_size);
if padding_len == 0 {
let mut result = data.to_vec();
result.extend(vec![block_size as u8; block_size]);
return Ok(result);
}
let mut result = data.to_vec();
result.extend(vec![padding_len as u8; padding_len]);
Ok(result)
}
pub fn unpad(data: &[u8], block_size: usize) -> Result<Vec<u8>> {
if !(2..=255).contains(&block_size) {
return Err(CryptoError::InvalidParameter(format!(
"Invalid block size: {}",
block_size
)));
}
if data.len() < block_size || !data.len().is_multiple_of(block_size) {
return Err(CryptoError::DecryptionFailed(
"Invalid padded data length".into(),
));
}
let padding_len = data[data.len() - 1] as usize;
if padding_len == 0 || padding_len > block_size {
return Err(CryptoError::DecryptionFailed(
"Invalid padding length".into(),
));
}
for i in 1..=padding_len {
if data[data.len() - i] != padding_len as u8 {
return Err(CryptoError::DecryptionFailed(
"Invalid padding bytes".into(),
));
}
}
Ok(data[..data.len() - padding_len].to_vec())
}
#[allow(dead_code)]
pub fn get_padding_length(data_len: usize, block_size: usize) -> usize {
if block_size == 0 {
return 0;
}
let remainder = data_len % block_size;
if remainder == 0 {
block_size
} else {
block_size - remainder
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_pkcs7_pad_normal() {
let data = b"Hello World";
let block_size = 16;
let padded = Pkcs7Padding::pad(data, block_size).unwrap();
assert_eq!(padded.len(), 16);
assert_eq!(padded[11], 5);
assert_eq!(padded[12], 5);
assert_eq!(padded[13], 5);
assert_eq!(padded[14], 5);
assert_eq!(padded[15], 5);
}
#[test]
fn test_pkcs7_pad_exact_block() {
let data = b"1234567890123456"; let block_size = 16;
let padded = Pkcs7Padding::pad(data, block_size).unwrap();
assert_eq!(padded.len(), 32); assert_eq!(padded[16], 16);
assert_eq!(padded[31], 16);
}
#[test]
fn test_pkcs7_unpad_normal() {
let data = b"Hello World";
let block_size = 16;
let padded = Pkcs7Padding::pad(data, block_size).unwrap();
let unpadded = Pkcs7Padding::unpad(&padded, block_size).unwrap();
assert_eq!(unpadded, data);
}
#[test]
fn test_pkcs7_unpad_exact_block() {
let data = b"1234567890123456"; let block_size = 16;
let padded = Pkcs7Padding::pad(data, block_size).unwrap();
let unpadded = Pkcs7Padding::unpad(&padded, block_size).unwrap();
assert_eq!(unpadded, data);
}
#[test]
fn test_pkcs7_invalid_block_size() {
let data = b"test";
assert!(Pkcs7Padding::pad(data, 1).is_err());
assert!(Pkcs7Padding::pad(data, 256).is_err());
assert!(Pkcs7Padding::unpad(data, 1).is_err());
assert!(Pkcs7Padding::unpad(data, 256).is_err());
}
#[test]
fn test_pkcs7_invalid_padding() {
let invalid_data = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 20];
assert!(Pkcs7Padding::unpad(&invalid_data, 16).is_err());
}
#[test]
fn test_get_padding_length() {
assert_eq!(Pkcs7Padding::get_padding_length(10, 16), 6);
assert_eq!(Pkcs7Padding::get_padding_length(16, 16), 16);
assert_eq!(Pkcs7Padding::get_padding_length(20, 16), 12);
assert_eq!(Pkcs7Padding::get_padding_length(0, 16), 16);
}
}