#![no_std]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg"
)]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![warn(missing_docs, rust_2018_idioms)]
#[cfg(feature = "std")]
extern crate std;
use core::fmt;
pub use generic_array;
use generic_array::{ArrayLength, GenericArray};
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum PadType {
Reversible,
Ambiguous,
NoPadding,
}
pub trait RawPadding {
const TYPE: PadType;
fn raw_pad(block: &mut [u8], pos: usize);
fn raw_unpad(block: &[u8]) -> Result<&[u8], UnpadError>;
}
pub type Block<B> = GenericArray<u8, B>;
pub trait Padding<BlockSize: ArrayLength<u8>> {
const TYPE: PadType;
fn pad(block: &mut Block<BlockSize>, pos: usize);
fn unpad(block: &Block<BlockSize>) -> Result<&[u8], UnpadError>;
fn unpad_blocks(blocks: &[Block<BlockSize>]) -> Result<&[u8], UnpadError> {
let bs = BlockSize::USIZE;
let res_len = match (blocks.last(), Self::TYPE) {
(_, PadType::NoPadding) => bs * blocks.len(),
(Some(last_block), _) => {
let n = Self::unpad(last_block)?.len();
assert!(n <= bs);
n + bs * (blocks.len() - 1)
}
(None, PadType::Ambiguous) => 0,
(None, PadType::Reversible) => return Err(UnpadError),
};
Ok(unsafe {
let p = blocks.as_ptr() as *const u8;
core::slice::from_raw_parts(p, res_len)
})
}
}
impl<T, B: ArrayLength<u8>> Padding<B> for T
where
T: RawPadding,
{
const TYPE: PadType = T::TYPE;
#[inline]
fn pad(block: &mut Block<B>, pos: usize) {
T::raw_pad(block.as_mut_slice(), pos);
}
#[inline]
fn unpad(block: &Block<B>) -> Result<&[u8], UnpadError> {
T::raw_unpad(block.as_slice())
}
}
#[derive(Clone, Copy, Debug)]
pub struct ZeroPadding;
impl RawPadding for ZeroPadding {
const TYPE: PadType = PadType::Ambiguous;
#[inline]
fn raw_pad(block: &mut [u8], pos: usize) {
if pos > block.len() {
panic!("`pos` is bigger than block size");
}
for b in &mut block[pos..] {
*b = 0;
}
}
#[inline]
fn raw_unpad(block: &[u8]) -> Result<&[u8], UnpadError> {
for i in (0..block.len()).rev() {
if block[i] != 0 {
return Ok(&block[..i + 1]);
}
}
Ok(&block[..0])
}
}
#[derive(Clone, Copy, Debug)]
pub struct Pkcs7;
impl Pkcs7 {
#[inline]
fn unpad(block: &[u8], strict: bool) -> Result<&[u8], UnpadError> {
if block.len() > 255 {
panic!("block size is too big for PKCS#7");
}
let bs = block.len();
let n = block[bs - 1];
if n == 0 || n as usize > bs {
return Err(UnpadError);
}
let s = bs - n as usize;
if strict && block[s..bs - 1].iter().any(|&v| v != n) {
return Err(UnpadError);
}
Ok(&block[..s])
}
}
impl RawPadding for Pkcs7 {
const TYPE: PadType = PadType::Reversible;
#[inline]
fn raw_pad(block: &mut [u8], pos: usize) {
if block.len() > 255 {
panic!("block size is too big for PKCS#7");
}
if pos >= block.len() {
panic!("`pos` is bigger or equal to block size");
}
let n = (block.len() - pos) as u8;
for b in &mut block[pos..] {
*b = n;
}
}
#[inline]
fn raw_unpad(block: &[u8]) -> Result<&[u8], UnpadError> {
Pkcs7::unpad(block, true)
}
}
#[derive(Clone, Copy, Debug)]
pub struct Iso10126;
impl RawPadding for Iso10126 {
const TYPE: PadType = PadType::Reversible;
#[inline]
fn raw_pad(block: &mut [u8], pos: usize) {
Pkcs7::raw_pad(block, pos)
}
#[inline]
fn raw_unpad(block: &[u8]) -> Result<&[u8], UnpadError> {
Pkcs7::unpad(block, false)
}
}
#[derive(Clone, Copy, Debug)]
pub struct AnsiX923;
impl RawPadding for AnsiX923 {
const TYPE: PadType = PadType::Reversible;
#[inline]
fn raw_pad(block: &mut [u8], pos: usize) {
if block.len() > 255 {
panic!("block size is too big for PKCS#7");
}
if pos >= block.len() {
panic!("`pos` is bigger or equal to block size");
}
let bs = block.len();
for b in &mut block[pos..bs - 1] {
*b = 0;
}
block[bs - 1] = (bs - pos) as u8;
}
#[inline]
fn raw_unpad(block: &[u8]) -> Result<&[u8], UnpadError> {
if block.len() > 255 {
panic!("block size is too big for PKCS#7");
}
let bs = block.len();
let n = block[bs - 1] as usize;
if n == 0 || n > bs {
return Err(UnpadError);
}
let s = bs - n;
if block[s..bs - 1].iter().any(|&v| v != 0) {
return Err(UnpadError);
}
Ok(&block[..s])
}
}
#[derive(Clone, Copy, Debug)]
pub struct Iso7816;
impl RawPadding for Iso7816 {
const TYPE: PadType = PadType::Reversible;
#[inline]
fn raw_pad(block: &mut [u8], pos: usize) {
if pos >= block.len() {
panic!("`pos` is bigger or equal to block size");
}
block[pos] = 0x80;
for b in &mut block[pos + 1..] {
*b = 0;
}
}
#[inline]
fn raw_unpad(block: &[u8]) -> Result<&[u8], UnpadError> {
for i in (0..block.len()).rev() {
match block[i] {
0x80 => return Ok(&block[..i]),
0x00 => continue,
_ => return Err(UnpadError),
}
}
Err(UnpadError)
}
}
#[derive(Clone, Copy, Debug)]
pub struct NoPadding;
impl RawPadding for NoPadding {
const TYPE: PadType = PadType::NoPadding;
#[inline]
fn raw_pad(block: &mut [u8], pos: usize) {
if pos > block.len() {
panic!("`pos` is bigger than block size");
}
}
#[inline]
fn raw_unpad(block: &[u8]) -> Result<&[u8], UnpadError> {
Ok(block)
}
}
#[derive(Clone, Copy, Debug)]
pub struct UnpadError;
impl fmt::Display for UnpadError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.write_str("Unpad Error")
}
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl std::error::Error for UnpadError {}