• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! Traits for AES-CBC 256 with PKCS7 padding.
16 
17 #[cfg(feature = "alloc")]
18 extern crate alloc;
19 use crate::tinyvec::SliceVec;
20 #[cfg(feature = "alloc")]
21 use alloc::vec::Vec;
22 
23 use super::Aes256Key;
24 
25 /// Type of the initialization vector for AES-CBC
26 pub type AesCbcIv = [u8; 16];
27 
28 /// Trait for implementing AES-CBC with PKCS7 padding.
29 pub trait AesCbcPkcs7Padded {
30     /// Calculate the padded output length (e.g. output of `encrypt`) from the unpadded length (e.g.
31     /// input message of `encrypt`).
32     #[allow(clippy::expect_used)]
padded_output_len(unpadded_len: usize) -> usize33     fn padded_output_len(unpadded_len: usize) -> usize {
34         (unpadded_len - (unpadded_len % 16))
35             .checked_add(16)
36             .expect("Padded output length is larger than usize::MAX")
37     }
38 
39     /// Encrypt message using `key` and `iv`, returning a ciphertext.
40     #[cfg(feature = "alloc")]
encrypt(key: &Aes256Key, iv: &AesCbcIv, message: &[u8]) -> Vec<u8>41     fn encrypt(key: &Aes256Key, iv: &AesCbcIv, message: &[u8]) -> Vec<u8>;
42 
43     /// Encrypt message using `key` and `iv` in-place in the given `message` vec. The given slice
44     /// vec should have enough capacity to contain both the ciphertext and the padding (which can be
45     /// calculated from `padded_output_len()`). If it doesn't have enough capacity, an error will be
46     /// returned. The contents of the input `message` buffer is undefined in that case.
encrypt_in_place( key: &Aes256Key, iv: &AesCbcIv, message: &mut SliceVec<u8>, ) -> Result<(), EncryptionError>47     fn encrypt_in_place(
48         key: &Aes256Key,
49         iv: &AesCbcIv,
50         message: &mut SliceVec<u8>,
51     ) -> Result<(), EncryptionError>;
52 
53     /// Decrypt ciphertext using `key` and `iv`, returning the original message if `Ok()` otherwise
54     /// a `DecryptionError` indicating the type of error that occurred while decrypting.
55     #[cfg(feature = "alloc")]
decrypt( key: &Aes256Key, iv: &AesCbcIv, ciphertext: &[u8], ) -> Result<Vec<u8>, DecryptionError>56     fn decrypt(
57         key: &Aes256Key,
58         iv: &AesCbcIv,
59         ciphertext: &[u8],
60     ) -> Result<Vec<u8>, DecryptionError>;
61 
62     /// Decrypt ciphertext using `key` and `iv` and unpad it in-place. Returning the original
63     /// message if `Ok()` otherwise a `DecryptionError` indicating the type of error that occurred
64     /// while decrypting. In that case, the contents of the `ciphertext` buffer is undefined.
decrypt_in_place( key: &Aes256Key, iv: &AesCbcIv, ciphertext: &mut SliceVec<u8>, ) -> Result<(), DecryptionError>65     fn decrypt_in_place(
66         key: &Aes256Key,
67         iv: &AesCbcIv,
68         ciphertext: &mut SliceVec<u8>,
69     ) -> Result<(), DecryptionError>;
70 }
71 
72 /// Error type for describing what went wrong encrypting a message.
73 #[derive(Debug, PartialEq, Eq)]
74 pub enum EncryptionError {
75     /// Failed to add PKCS7 padding to the output when encrypting a message. This typically happens
76     /// when the given output buffer does not have enough capacity to append the padding.
77     PaddingFailed,
78 }
79 
80 /// Error type for describing what went wrong decrypting a ciphertext.
81 #[derive(Debug, PartialEq, Eq)]
82 pub enum DecryptionError {
83     /// Invalid padding, the input ciphertext does not have valid PKCS7 padding. If you get this
84     /// error, check the encryption side generating this data to make sure it is adding the padding
85     /// correctly. Exposing padding errors can cause a padding oracle vulnerability.
86     BadPadding,
87 }
88 
89 #[cfg(test)]
90 mod test {
91     #[cfg(feature = "alloc")]
92     extern crate alloc;
93     #[cfg(feature = "alloc")]
94     use alloc::vec::Vec;
95 
96     use crate::aes::Aes256Key;
97     use crate::tinyvec::SliceVec;
98 
99     use super::{AesCbcIv, AesCbcPkcs7Padded, DecryptionError, EncryptionError};
100 
101     #[test]
test_padded_output_len()102     fn test_padded_output_len() {
103         assert_eq!(AesCbcPkcs7PaddedStub::padded_output_len(0), 16);
104         assert_eq!(AesCbcPkcs7PaddedStub::padded_output_len(15), 16);
105         assert_eq!(AesCbcPkcs7PaddedStub::padded_output_len(16), 32);
106         assert_eq!(AesCbcPkcs7PaddedStub::padded_output_len(30), 32);
107         assert_eq!(AesCbcPkcs7PaddedStub::padded_output_len(32), 48);
108     }
109 
110     #[test]
111     #[should_panic]
test_padded_output_len_overflow()112     fn test_padded_output_len_overflow() {
113         let _ = AesCbcPkcs7PaddedStub::padded_output_len(usize::MAX);
114     }
115 
116     struct AesCbcPkcs7PaddedStub;
117 
118     impl AesCbcPkcs7Padded for AesCbcPkcs7PaddedStub {
119         #[cfg(feature = "alloc")]
encrypt(_key: &Aes256Key, _iv: &AesCbcIv, _message: &[u8]) -> Vec<u8>120         fn encrypt(_key: &Aes256Key, _iv: &AesCbcIv, _message: &[u8]) -> Vec<u8> {
121             unimplemented!()
122         }
123 
encrypt_in_place( _key: &Aes256Key, _iv: &AesCbcIv, _message: &mut SliceVec<u8>, ) -> Result<(), EncryptionError>124         fn encrypt_in_place(
125             _key: &Aes256Key,
126             _iv: &AesCbcIv,
127             _message: &mut SliceVec<u8>,
128         ) -> Result<(), EncryptionError> {
129             unimplemented!()
130         }
131 
132         #[cfg(feature = "alloc")]
decrypt( _key: &Aes256Key, _iv: &AesCbcIv, _ciphertext: &[u8], ) -> Result<Vec<u8>, DecryptionError>133         fn decrypt(
134             _key: &Aes256Key,
135             _iv: &AesCbcIv,
136             _ciphertext: &[u8],
137         ) -> Result<Vec<u8>, DecryptionError> {
138             unimplemented!()
139         }
140 
decrypt_in_place( _key: &Aes256Key, _iv: &AesCbcIv, _ciphertext: &mut SliceVec<u8>, ) -> Result<(), DecryptionError>141         fn decrypt_in_place(
142             _key: &Aes256Key,
143             _iv: &AesCbcIv,
144             _ciphertext: &mut SliceVec<u8>,
145         ) -> Result<(), DecryptionError> {
146             unimplemented!()
147         }
148     }
149 }
150