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