1#![no_std]
2#![doc = include_str!("../README.md")]
3#![doc(
4 html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
5 html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg"
6)]
7#![deny(unsafe_code)]
8#![warn(missing_docs, missing_debug_implementations)]
9
10pub use hybrid_array as array;
11
12use core::fmt;
13use hybrid_array::{Array, ArraySize};
14
15pub trait Padding: 'static {
17 fn raw_pad(block: &mut [u8], pos: usize);
24
25 fn raw_unpad(block: &[u8]) -> Result<&[u8], Error>;
29
30 #[inline]
37 fn pad<BlockSize: ArraySize>(block: &mut Array<u8, BlockSize>, pos: usize) {
38 Self::raw_pad(block.as_mut_slice(), pos);
39 }
40
41 #[inline]
45 fn unpad<BlockSize: ArraySize>(block: &Array<u8, BlockSize>) -> Result<&[u8], Error> {
46 Self::raw_unpad(block.as_slice())
47 }
48
49 #[inline]
56 fn pad_detached<BlockSize: ArraySize>(data: &[u8]) -> PaddedData<'_, BlockSize> {
57 let (blocks, tail) = Array::slice_as_chunks(data);
58 let mut tail_block = Array::default();
59 let pos = tail.len();
60 tail_block[..pos].copy_from_slice(tail);
61 Self::pad(&mut tail_block, pos);
62 PaddedData::Pad { blocks, tail_block }
63 }
64
65 #[inline]
69 fn unpad_blocks<BlockSize: ArraySize>(blocks: &[Array<u8, BlockSize>]) -> Result<&[u8], Error> {
70 let bs = BlockSize::USIZE;
71 let (last_block, full_blocks) = blocks.split_last().ok_or(Error)?;
72 let unpad_len = Self::unpad(last_block)?.len();
73 assert!(unpad_len <= bs);
74 let buf = Array::slice_as_flattened(blocks);
75 let data_len = full_blocks.len() * bs + unpad_len;
76 Ok(&buf[..data_len])
77 }
78}
79
80#[derive(Clone, Copy, Debug)]
99pub struct ZeroPadding;
100
101impl Padding for ZeroPadding {
102 #[inline]
103 fn raw_pad(block: &mut [u8], pos: usize) {
104 if pos > block.len() {
105 panic!("`pos` is bigger than block size");
106 }
107 block[pos..].fill(0);
108 }
109
110 #[inline]
111 fn raw_unpad(block: &[u8]) -> Result<&[u8], Error> {
112 for i in (0..block.len()).rev() {
113 if block[i] != 0 {
114 return Ok(&block[..i + 1]);
115 }
116 }
117 Ok(&block[..0])
118 }
119
120 #[inline]
121 fn pad_detached<BlockSize: ArraySize>(data: &[u8]) -> PaddedData<'_, BlockSize> {
122 let (blocks, tail) = Array::slice_as_chunks(data);
123 if tail.is_empty() {
124 return PaddedData::NoPad { blocks };
125 }
126 let mut tail_block = Array::default();
127 let pos = tail.len();
128 tail_block[..pos].copy_from_slice(tail);
129 Self::pad(&mut tail_block, pos);
130 PaddedData::Pad { blocks, tail_block }
131 }
132
133 #[inline]
134 fn unpad_blocks<BlockSize: ArraySize>(blocks: &[Array<u8, BlockSize>]) -> Result<&[u8], Error> {
135 let buf = Array::slice_as_flattened(blocks);
136 for i in (0..buf.len()).rev() {
137 if buf[i] != 0 {
138 return Ok(&buf[..i + 1]);
139 }
140 }
141 Ok(&buf[..0])
142 }
143}
144
145#[derive(Clone, Copy, Debug)]
163pub struct Pkcs7;
164
165impl Pkcs7 {
166 #[inline]
167 fn unpad(block: &[u8], strict: bool) -> Result<&[u8], Error> {
168 if block.len() > 255 {
169 panic!("block size is too big for PKCS#7");
170 }
171 let bs = block.len();
172 let n = block[bs - 1];
173 if n == 0 || n as usize > bs {
174 return Err(Error);
175 }
176 let s = bs - n as usize;
177 if strict && block[s..bs - 1].iter().any(|&v| v != n) {
178 return Err(Error);
179 }
180 Ok(&block[..s])
181 }
182}
183
184impl Padding for Pkcs7 {
185 #[inline]
186 fn raw_pad(block: &mut [u8], pos: usize) {
187 if block.len() > 255 {
188 panic!("block size is too big for PKCS#7");
189 }
190 if pos >= block.len() {
191 panic!("`pos` is bigger or equal to block size");
192 }
193 let n = (block.len() - pos) as u8;
194 block[pos..].fill(n);
195 }
196
197 #[inline]
198 fn raw_unpad(block: &[u8]) -> Result<&[u8], Error> {
199 Pkcs7::unpad(block, true)
200 }
201}
202
203#[derive(Clone, Copy, Debug)]
221pub struct Iso10126;
222
223impl Padding for Iso10126 {
224 #[inline]
225 fn raw_pad(block: &mut [u8], pos: usize) {
226 Pkcs7::raw_pad(block, pos)
229 }
230
231 #[inline]
232 fn raw_unpad(block: &[u8]) -> Result<&[u8], Error> {
233 Pkcs7::unpad(block, false)
234 }
235}
236
237#[derive(Clone, Copy, Debug)]
254pub struct AnsiX923;
255
256impl Padding for AnsiX923 {
257 #[inline]
258 fn raw_pad(block: &mut [u8], pos: usize) {
259 if block.len() > 255 {
260 panic!("block size is too big for ANSI X9.23");
261 }
262 if pos >= block.len() {
263 panic!("`pos` is bigger or equal to block size");
264 }
265 let bs = block.len();
266 block[pos..bs - 1].fill(0);
267 block[bs - 1] = (bs - pos) as u8;
268 }
269
270 #[inline]
271 fn raw_unpad(block: &[u8]) -> Result<&[u8], Error> {
272 if block.len() > 255 {
273 panic!("block size is too big for ANSI X9.23");
274 }
275 let bs = block.len();
276 let n = block[bs - 1] as usize;
277 if n == 0 || n > bs {
278 return Err(Error);
279 }
280 let s = bs - n;
281 if block[s..bs - 1].iter().any(|&v| v != 0) {
282 return Err(Error);
283 }
284 Ok(&block[..s])
285 }
286}
287
288#[derive(Clone, Copy, Debug)]
304pub struct Iso7816;
305
306impl Padding for Iso7816 {
307 #[inline]
308 fn raw_pad(block: &mut [u8], pos: usize) {
309 if pos >= block.len() {
310 panic!("`pos` is bigger or equal to block size");
311 }
312 block[pos] = 0x80;
313 block[pos + 1..].fill(0);
314 }
315
316 #[inline]
317 fn raw_unpad(block: &[u8]) -> Result<&[u8], Error> {
318 for i in (0..block.len()).rev() {
319 match block[i] {
320 0x80 => return Ok(&block[..i]),
321 0x00 => continue,
322 _ => return Err(Error),
323 }
324 }
325 Err(Error)
326 }
327}
328
329#[derive(Clone, Copy, Debug)]
351pub struct NoPadding;
352
353impl Padding for NoPadding {
354 #[inline]
355 fn raw_pad(block: &mut [u8], pos: usize) {
356 if pos > block.len() {
357 panic!("`pos` is bigger than block size");
358 }
359 }
360
361 #[inline]
362 fn raw_unpad(block: &[u8]) -> Result<&[u8], Error> {
363 Ok(block)
364 }
365
366 #[inline]
367 fn pad_detached<BlockSize: ArraySize>(data: &[u8]) -> PaddedData<'_, BlockSize> {
368 let (blocks, tail) = Array::slice_as_chunks(data);
369 if tail.is_empty() {
370 PaddedData::NoPad { blocks }
371 } else {
372 PaddedData::Error
373 }
374 }
375
376 #[inline]
377 fn unpad_blocks<BlockSize: ArraySize>(blocks: &[Array<u8, BlockSize>]) -> Result<&[u8], Error> {
378 Ok(Array::slice_as_flattened(blocks))
379 }
380}
381
382#[derive(Clone, Copy, Debug)]
384pub struct Error;
385
386impl fmt::Display for Error {
387 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
388 f.write_str("Padding error")
389 }
390}
391
392impl core::error::Error for Error {}
393
394#[derive(Debug)]
396pub enum PaddedData<'a, BlockSize: ArraySize> {
397 Pad {
399 blocks: &'a [Array<u8, BlockSize>],
401 tail_block: Array<u8, BlockSize>,
403 },
404 NoPad {
406 blocks: &'a [Array<u8, BlockSize>],
408 },
409 Error,
411}
412
413impl<'a, BlockSize: ArraySize> PaddedData<'a, BlockSize> {
414 pub fn unwrap(self) -> (&'a [Array<u8, BlockSize>], Array<u8, BlockSize>) {
416 match self {
417 PaddedData::Pad { blocks, tail_block } => (blocks, tail_block),
418 PaddedData::NoPad { .. } => {
419 panic!("Expected `PaddedData::Pad`, but got `PaddedData::NoPad`");
420 }
421 PaddedData::Error => {
422 panic!("Expected `PaddedData::Pad`, but got `PaddedData::Error`");
423 }
424 }
425 }
426}