tinyaes/
padding.rs

1//! A module containing padding modes.
2
3
4
5
6
7// DISABLED LINTS
8
9#![allow(clippy::needless_range_loop)]  // better readability
10
11
12
13
14
15// ENUMS
16
17/// The enum with padding errors.
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
19pub enum PaddingError {
20    /// The padding is invalid and cannot be removed.
21    InvalidPadding,
22    /// The input to be padded is 16 or more bytes long.
23    /// Should be less than 16 bytes long.
24    InvalidSize,
25    /// The padded input isn't 16 bytes long.
26    InvalidPaddedSize,
27    /// Trying to pad/de-pad with `PaddingTypes::None`.
28    NonePadding,
29}
30
31/// The enum with padding types.
32#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
33pub enum PaddingTypes {
34    /// PKCS#7 padding.
35    /// The value of each added byte is the total number of bytes that need to be added.
36    /// This padding scheme is defined in RFC 2315.
37    PKCS7,
38    /// ISO 7816-4 padding.
39    /// The first byte of the padding is 0x80.
40    /// All other bytes of the padding are 0x00.
41    /// This padding scheme is defined in ISO/IEC 7816-4.
42    ISO78164,
43    /// ANSI X9.23 padding.
44    /// The last byte of the padding (thus, the last byte of the block) is the number of pad bytes.
45    /// All other bytes of the padding are zeros.
46    /// This padding scheme is defined in ANSI X9.23.
47    X923,
48    /// Don't use padding.
49    /// For use with certain cipher modes which don't require padding.
50    None,
51}
52
53
54
55
56
57// STRUCTS
58
59/// The padding struct.
60#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
61pub struct Padding {
62    /// The padding type.
63    padding_type: PaddingTypes,
64}
65
66/// The public functions for the padding struct.
67impl Padding {
68    pub fn new(padding_type: PaddingTypes) -> Self {
69        //! Creates a new padding struct.
70        //! # Arguments
71        //! * `padding_type` - The padding type, see the `PaddingTypes` enum.
72
73        Self {
74            padding_type,
75        }
76    }
77
78    pub fn padding_type(&self) -> PaddingTypes {
79        //! Returns the padding type.
80        //! # Returns
81        //! * PaddingTypes - The padding type, see the `PaddingTypes` enum.
82
83        self.padding_type
84    }
85
86    pub fn set_padding_type(&mut self, padding_type: PaddingTypes) {
87        //! Sets the padding type.
88        //! # Arguments
89        //! * `padding_type` - The padding type, see the `PaddingTypes` enum.
90
91        self.padding_type = padding_type;
92    }
93
94    pub fn pad(&self, input: &[u8]) -> Result<[u8; 16], PaddingError> {
95        //! Pads the input to 16 bytes.
96        //! # Arguments
97        //! * `input` - The input to be padded. Should be less than 16 bytes long. Zero length input is allowed.
98        //! # Returns
99        //! * Result<[u8; 16], PaddingError> - The padded input or an error.
100        //! # Errors
101        //! * PaddingError::InvalidSize - The input is 16 or more bytes long.
102        //! * PaddingError::NonePadding - Trying to pad with `PaddingTypes::None`.
103
104        if self.padding_type == PaddingTypes::None {
105            return Err(PaddingError::NonePadding);
106        }
107
108        if input.len() >= 16 {
109            return Err(PaddingError::InvalidSize);
110        }
111
112        let mut output: [u8; 16] = [0; 16];
113        output[..input.len()].copy_from_slice(input);
114
115        match self.padding_type {
116            PaddingTypes::PKCS7 => {
117                output[input.len()..16].fill((16 - input.len()) as u8);
118            }
119            PaddingTypes::ISO78164 => {
120                output[input.len()] = 0x80;
121                output[(input.len() + 1)..16].fill(0);
122            }
123            PaddingTypes::X923 => {
124                output[15] = (16 - input.len()) as u8;
125                output[input.len()..15].fill(0);
126            }
127            PaddingTypes::None => panic!("This should not be possible to reach."),
128        }
129
130        Ok(output)
131    }
132
133    pub fn de_pad<'a>(&self, input: &'a [u8]) -> Result<&'a [u8], PaddingError> {
134        //! Removes the padding from the input.
135        //! # Arguments
136        //! * `input` - The input to be de-padded. Should be 16 bytes long.
137        //! # Returns
138        //! * Result<&[u8], PaddingError> - The de-padded input or an error.
139        //! # Errors
140        //! * PaddingError::InvalidPadding - The padding is invalid and cannot be removed.
141        //! * PaddingError::InvalidPaddedSize - The input isn't 16 bytes long.
142        //! * PaddingError::NonePadding - Trying to de-pad with `PaddingTypes::None`.
143
144        if self.padding_type == PaddingTypes::None {
145            return Err(PaddingError::NonePadding);
146        }
147
148        if input.len() != 16 {
149            return Err(PaddingError::InvalidPaddedSize);
150        }
151
152        let upper_bound = match self.padding_type {
153            PaddingTypes::PKCS7 => {
154                let padding_length = input[input.len() - 1];
155
156                if padding_length > 16 || padding_length as usize > input.len() {
157                    return Err(PaddingError::InvalidPadding);
158                }
159
160                for i in (input.len() - padding_length as usize)..(input.len() - 1) {
161                    if input[i] != padding_length {
162                        return Err(PaddingError::InvalidPadding);
163                    }
164                }
165
166                input.len() - padding_length as usize
167            }
168            PaddingTypes::ISO78164 => {
169                let mut curr_index: usize = input.len() - 1;
170
171                while input[curr_index] == 0 {
172                    curr_index -= 1;
173                }
174
175                if input[curr_index] != 0x80 || input.len() - curr_index > 16{
176                    return Err(PaddingError::InvalidPadding);
177                }
178
179                curr_index
180            }
181            PaddingTypes::X923 => {
182                let padding_length = input[input.len() - 1] as usize;
183                if padding_length > 16 {
184                    return Err(PaddingError::InvalidPadding);
185                }
186
187                for i in (input.len() - padding_length)..(input.len() - 1) {
188                    if input[i] != 0 {
189                        return Err(PaddingError::InvalidPadding);
190                    }
191                }
192
193                input.len() - padding_length
194            }
195            PaddingTypes::None => panic!("This should not be possible to reach."),
196        };
197
198        Ok(&input[..upper_bound])
199    }
200}
201
202
203
204
205
206// TESTS
207
208#[cfg(test)]
209mod tests {
210    use super::*;
211
212    #[test]
213    fn new() {
214        let padding = Padding::new(PaddingTypes::PKCS7);
215
216        assert_eq!(padding.padding_type, PaddingTypes::PKCS7);
217    }
218
219    #[test]
220    fn set_padding_type() {
221        let mut padding = Padding::new(PaddingTypes::X923);
222
223        assert_eq!(padding.padding_type, PaddingTypes::X923);
224        assert_eq!(padding.padding_type(), PaddingTypes::X923);
225
226        padding.set_padding_type(PaddingTypes::PKCS7);
227
228        assert_eq!(padding.padding_type, PaddingTypes::PKCS7);
229        assert_eq!(padding.padding_type(), PaddingTypes::PKCS7);
230    }
231
232    #[test]
233    fn pkcs7_padding() {
234        //! Tests the PKCS#7 padding.
235
236        let padding: Padding = Padding::new(PaddingTypes::PKCS7);
237
238        let input1: [u8; 2] = [0b10100001, 0b10100000];
239        let output1: [u8; 16] = padding.pad(&input1).unwrap();
240        let wanted1: [u8; 16] = [0b10100001, 0b10100000, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e];
241        assert_eq!(output1, wanted1);
242
243        let input2: [u8; 0] = [];
244        let output2: [u8; 16] = padding.pad(&input2).unwrap();
245        let wanted2: [u8; 16] = [0x10; 16];
246        assert_eq!(output2, wanted2);
247
248        let input3: [u8; 15] = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F];
249        let output3: [u8; 16] = padding.pad(&input3).unwrap();
250        let wanted3: [u8; 16] = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0b00000001];
251        assert_eq!(output3, wanted3);
252    }
253
254    #[test]
255    fn pkcs7_de_padding() {
256        //! Tests the PKCS#7 de-padding.
257
258        let padding: Padding = Padding::new(PaddingTypes::PKCS7);
259
260        let input1: [u8; 16] = [0b10100001, 0b10100000, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e];
261        let output1: &[u8] = padding.de_pad(&input1).unwrap();
262        let wanted1: [u8; 2] = [0b10100001, 0b10100000];
263        assert_eq!(output1, wanted1);
264
265        let input2: [u8; 16] = [0x10; 16];
266        let output2: &[u8] = padding.de_pad(&input2).unwrap();
267        let wanted2: [u8; 0] = [];
268        assert_eq!(output2, wanted2);
269
270        let input3: [u8; 16] = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0b00000001];
271        let output3: &[u8] = padding.de_pad(&input3).unwrap();
272        let wanted3: [u8; 15] = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F];
273        assert_eq!(output3, wanted3);
274    }
275
276    #[test]
277    fn iso78164_padding() {
278        //! Tests the ISO 7816-4 padding.
279
280        let padding: Padding = Padding::new(PaddingTypes::ISO78164);
281
282        let input1: [u8; 2] = [0b10100001, 0b10100000];
283        let output1: [u8; 16] = padding.pad(&input1).unwrap();
284        let wanted1: [u8; 16] = [0b10100001, 0b10100000, 0b10000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
285        assert_eq!(output1, wanted1);
286
287        let input2: [u8; 0] = [];
288        let output2: [u8; 16] = padding.pad(&input2).unwrap();
289        let wanted2: [u8; 16] = [0b10000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
290        assert_eq!(output2, wanted2);
291
292        let input3: [u8; 15] = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F];
293        let output3: [u8; 16] = padding.pad(&input3).unwrap();
294        let wanted3: [u8; 16] = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0b10000000];
295        assert_eq!(output3, wanted3);
296    }
297
298    #[test]
299    fn iso78164_de_padding() {
300        //! Tests the ISO 7816-4 de-padding.
301
302        let padding: Padding = Padding::new(PaddingTypes::ISO78164);
303
304        let input1: [u8; 16] = [0b10100001, 0b10100000, 0b10000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
305        let output1: &[u8] = padding.de_pad(&input1).unwrap();
306        let wanted1: [u8; 2] = [0b10100001, 0b10100000];
307        assert_eq!(output1, wanted1);
308
309        let input2: [u8; 16] = [0b10000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
310        let output2: &[u8] = padding.de_pad(&input2).unwrap();
311        let wanted2: [u8; 0] = [];
312        assert_eq!(output2, wanted2);
313
314        let input3: [u8; 16] = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0b10000000];
315        let output3: &[u8] = padding.de_pad(&input3).unwrap();
316        let wanted3: [u8; 15] = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F];
317        assert_eq!(output3, wanted3);
318    }
319
320    #[test]
321    fn x923_padding() {
322        //! Tests the ANSI X9.23 padding.
323
324        let padding: Padding = Padding::new(PaddingTypes::X923);
325
326        let input1: [u8; 2] = [0b10100001, 0b10100000];
327        let output1: [u8; 16] = padding.pad(&input1).unwrap();
328        let wanted1: [u8; 16] = [0b10100001, 0b10100000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0e];
329        assert_eq!(output1, wanted1);
330
331        let input2: [u8; 0] = [];
332        let output2: [u8; 16] = padding.pad(&input2).unwrap();
333        let mut wanted2: [u8; 16] = [0; 16];
334        wanted2[15] = 0x10;
335        assert_eq!(output2, wanted2);
336
337        let input3: [u8; 15] = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F];
338        let output3: [u8; 16] = padding.pad(&input3).unwrap();
339        let wanted3: [u8; 16] = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0b00000001];
340        assert_eq!(output3, wanted3);
341    }
342
343    #[test]
344    fn x923_de_padding() {
345        //! Tests the ANSI X9.23 de-padding.
346
347        let padding: Padding = Padding::new(PaddingTypes::X923);
348
349        let input1: [u8; 16] = [0b10100001, 0b10100000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0e];
350        let output1: &[u8] = padding.de_pad(&input1).unwrap();
351        let wanted1: [u8; 2] = [0b10100001, 0b10100000];
352        assert_eq!(output1, wanted1);
353
354        let mut input2: [u8; 16] = [0; 16];
355        input2[15] = 0x10;
356        let output2: &[u8] = padding.de_pad(&input2).unwrap();
357        let wanted2: [u8; 0] = [];
358        assert_eq!(output2, wanted2);
359
360        let input3: [u8; 16] = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0b00000001];
361        let output3: &[u8] = padding.de_pad(&input3).unwrap();
362        let wanted3: [u8; 15] = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F];
363        assert_eq!(output3, wanted3);
364    }
365
366    #[test]
367    fn padding_errors() {
368        let padding_type = PaddingTypes::PKCS7;
369        let input = [
370            0x01, 0x02, 0x03, 0x04,
371            0x05, 0x06, 0x07, 0x08,
372            0x09, 0x0A, 0x0B, 0x0C,
373        ];
374        let mut padded_input = [
375            0x01, 0x02, 0x03, 0x04,
376            0x05, 0x06, 0x07, 0x08,
377            0x09, 0x0A, 0x0B, 0x0C,
378            0x04, 0x04, 0x04, 0x04,
379        ];
380        let padding = Padding::new(padding_type);
381
382        assert_eq!(padding.pad(&input).unwrap(), padded_input);
383        assert_eq!(padding.pad(&[0; 16]), Err(PaddingError::InvalidSize));
384        assert_eq!(padding.pad(&[0; 17]), Err(PaddingError::InvalidSize));
385
386        assert_eq!(padding.de_pad(&padded_input).unwrap(), input);
387        assert_eq!(padding.de_pad(&[0; 15]), Err(PaddingError::InvalidPaddedSize));
388        assert_eq!(padding.de_pad(&[0; 17]), Err(PaddingError::InvalidPaddedSize));
389
390        padded_input[15] = 0x05;
391        assert_eq!(padding.de_pad(&padded_input), Err(PaddingError::InvalidPadding));
392
393        let new_padding = Padding::new(PaddingTypes::None);
394        assert_eq!(new_padding.pad(&input), Err(PaddingError::NonePadding));
395        assert_eq!(new_padding.de_pad(&padded_input), Err(PaddingError::NonePadding));
396    }
397}