1 // Copyright 2022, The Android Open Source Project
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 //! BoringSSL-based implementation of AES.
16 use crate::{openssl_err, openssl_err_or, ossl};
17 use alloc::boxed::Box;
18 use alloc::vec::Vec;
19 use core::cmp::min;
20 use kmr_common::{
21     crypto, crypto::OpaqueOr, explicit, km_err, vec_try, vec_try_with_capacity, Error,
22     FallibleAllocExt,
23 };
24 use openssl::symm::{Cipher, Crypter};
25 
26 /// [`crypto::Aes`] implementation based on BoringSSL.
27 pub struct BoringAes;
28 
29 impl crypto::Aes for BoringAes {
begin( &self, key: OpaqueOr<crypto::aes::Key>, mode: crypto::aes::CipherMode, dir: crypto::SymmetricOperation, ) -> Result<Box<dyn crypto::EmittingOperation>, Error>30     fn begin(
31         &self,
32         key: OpaqueOr<crypto::aes::Key>,
33         mode: crypto::aes::CipherMode,
34         dir: crypto::SymmetricOperation,
35     ) -> Result<Box<dyn crypto::EmittingOperation>, Error> {
36         let key = explicit!(key)?;
37         let dir_mode = match dir {
38             crypto::SymmetricOperation::Encrypt => openssl::symm::Mode::Encrypt,
39             crypto::SymmetricOperation::Decrypt => openssl::symm::Mode::Decrypt,
40         };
41         let crypter = match mode {
42             crypto::aes::CipherMode::EcbNoPadding | crypto::aes::CipherMode::EcbPkcs7Padding => {
43                 let (cipher, key) = match &key {
44                     crypto::aes::Key::Aes128(k) => (Cipher::aes_128_ecb(), &k[..]),
45                     crypto::aes::Key::Aes192(k) => (Cipher::aes_192_ecb(), &k[..]),
46                     crypto::aes::Key::Aes256(k) => (Cipher::aes_256_ecb(), &k[..]),
47                 };
48                 let mut crypter = Crypter::new(cipher, dir_mode, key, None)
49                     .map_err(openssl_err!("failed to create ECB Crypter"))?;
50                 if let crypto::aes::CipherMode::EcbPkcs7Padding = mode {
51                     crypter.pad(true);
52                 } else {
53                     crypter.pad(false);
54                 }
55                 crypter
56             }
57 
58             crypto::aes::CipherMode::CbcNoPadding { nonce: n }
59             | crypto::aes::CipherMode::CbcPkcs7Padding { nonce: n } => {
60                 let (cipher, key) = match &key {
61                     crypto::aes::Key::Aes128(k) => (Cipher::aes_128_cbc(), &k[..]),
62                     crypto::aes::Key::Aes192(k) => (Cipher::aes_192_cbc(), &k[..]),
63                     crypto::aes::Key::Aes256(k) => (Cipher::aes_256_cbc(), &k[..]),
64                 };
65                 let mut crypter = Crypter::new(cipher, dir_mode, key, Some(&n[..]))
66                     .map_err(openssl_err!("failed to create CBC Crypter"))?;
67                 if let crypto::aes::CipherMode::CbcPkcs7Padding { nonce: _ } = mode {
68                     crypter.pad(true);
69                 } else {
70                     crypter.pad(false);
71                 }
72                 crypter
73             }
74 
75             crypto::aes::CipherMode::Ctr { nonce: n } => {
76                 let (cipher, key) = match &key {
77                     crypto::aes::Key::Aes128(k) => (Cipher::aes_128_ctr(), &k[..]),
78                     crypto::aes::Key::Aes192(k) => (Cipher::aes_192_ctr(), &k[..]),
79                     crypto::aes::Key::Aes256(k) => (Cipher::aes_256_ctr(), &k[..]),
80                 };
81                 Crypter::new(cipher, dir_mode, key, Some(&n[..]))
82                     .map_err(openssl_err!("failed to create CTR Crypter"))?
83             }
84         };
85 
86         Ok(Box::new(BoringAesOperation { crypter }))
87     }
88 
begin_aead( &self, key: OpaqueOr<crypto::aes::Key>, mode: crypto::aes::GcmMode, dir: crypto::SymmetricOperation, ) -> Result<Box<dyn crypto::AadOperation>, Error>89     fn begin_aead(
90         &self,
91         key: OpaqueOr<crypto::aes::Key>,
92         mode: crypto::aes::GcmMode,
93         dir: crypto::SymmetricOperation,
94     ) -> Result<Box<dyn crypto::AadOperation>, Error> {
95         let key = explicit!(key)?;
96         let dir_mode = match dir {
97             crypto::SymmetricOperation::Encrypt => openssl::symm::Mode::Encrypt,
98             crypto::SymmetricOperation::Decrypt => openssl::symm::Mode::Decrypt,
99         };
100         let crypter = match mode {
101             crypto::aes::GcmMode::GcmTag12 { nonce: n }
102             | crypto::aes::GcmMode::GcmTag13 { nonce: n }
103             | crypto::aes::GcmMode::GcmTag14 { nonce: n }
104             | crypto::aes::GcmMode::GcmTag15 { nonce: n }
105             | crypto::aes::GcmMode::GcmTag16 { nonce: n } => {
106                 let (cipher, key) = match &key {
107                     crypto::aes::Key::Aes128(k) => (Cipher::aes_128_gcm(), &k[..]),
108                     crypto::aes::Key::Aes192(k) => (Cipher::aes_192_gcm(), &k[..]),
109                     crypto::aes::Key::Aes256(k) => (Cipher::aes_256_gcm(), &k[..]),
110                 };
111                 Crypter::new(cipher, dir_mode, key, Some(&n[..])).map_err(openssl_err!(
112                     "failed to create GCM Crypter for {:?} {:?}",
113                     mode,
114                     dir
115                 ))?
116             }
117         };
118 
119         Ok(match dir {
120             crypto::SymmetricOperation::Encrypt => Box::new({
121                 BoringAesGcmEncryptOperation { mode, inner: BoringAesOperation { crypter } }
122             }),
123             crypto::SymmetricOperation::Decrypt => Box::new(BoringAesGcmDecryptOperation {
124                 crypter,
125                 decrypt_tag_len: mode.tag_len(),
126                 pending_input_tail: vec_try_with_capacity!(mode.tag_len())?,
127             }),
128         })
129     }
130 }
131 
132 /// [`crypto::AesOperation`] implementation based on BoringSSL.
133 pub struct BoringAesOperation {
134     crypter: openssl::symm::Crypter,
135 }
136 
137 impl crypto::EmittingOperation for BoringAesOperation {
update(&mut self, data: &[u8]) -> Result<Vec<u8>, Error>138     fn update(&mut self, data: &[u8]) -> Result<Vec<u8>, Error> {
139         let mut output = vec_try![0; data.len() + crypto::aes::BLOCK_SIZE]?;
140         let out_len = self
141             .crypter
142             .update(data, &mut output)
143             .map_err(openssl_err!("update {} bytes from input failed", data.len()))?;
144         output.truncate(out_len);
145         Ok(output)
146     }
147 
finish(mut self: Box<Self>) -> Result<Vec<u8>, Error>148     fn finish(mut self: Box<Self>) -> Result<Vec<u8>, Error> {
149         let mut output = vec_try![0; crypto::aes::BLOCK_SIZE]?;
150         let out_len = ossl!(self.crypter.finalize(&mut output))?;
151         output.truncate(out_len);
152         Ok(output)
153     }
154 }
155 
156 /// [`crypto::AesGcmEncryptOperation`] implementation based on BoringSSL.
157 pub struct BoringAesGcmEncryptOperation {
158     mode: crypto::aes::GcmMode,
159     inner: BoringAesOperation,
160 }
161 
162 impl crypto::AadOperation for BoringAesGcmEncryptOperation {
update_aad(&mut self, aad: &[u8]) -> Result<(), Error>163     fn update_aad(&mut self, aad: &[u8]) -> Result<(), Error> {
164         ossl!(self.inner.crypter.aad_update(aad))
165     }
166 }
167 
168 impl crypto::EmittingOperation for BoringAesGcmEncryptOperation {
update(&mut self, data: &[u8]) -> Result<Vec<u8>, Error>169     fn update(&mut self, data: &[u8]) -> Result<Vec<u8>, Error> {
170         self.inner.update(data)
171     }
172 
finish(mut self: Box<Self>) -> Result<Vec<u8>, Error>173     fn finish(mut self: Box<Self>) -> Result<Vec<u8>, Error> {
174         let mut output = vec_try![0; crypto::aes::BLOCK_SIZE + self.mode.tag_len()]?;
175         let offset = self
176             .inner
177             .crypter
178             .finalize(&mut output)
179             .map_err(openssl_err_or!(VerificationFailed, "failed to finalize"))?;
180 
181         self.inner
182             .crypter
183             .get_tag(&mut output[offset..offset + self.mode.tag_len()])
184             .map_err(openssl_err!("failed to get tag of len {}", self.mode.tag_len()))?;
185         output.truncate(offset + self.mode.tag_len());
186         Ok(output)
187     }
188 }
189 
190 /// [`crypto::AesGcmDecryptOperation`] implementation based on BoringSSL.
191 pub struct BoringAesGcmDecryptOperation {
192     crypter: openssl::symm::Crypter,
193 
194     // Size of a final tag when decrypting.
195     decrypt_tag_len: usize,
196 
197     // For decryption, the last `decrypt_tag_len` bytes of input must be fed in separately.
198     // However, the overall size of the input data is not known in advance, so we need to hold up to
199     // `decrypt_tag_len` bytes on input in reserve until `finish()`.
200     pending_input_tail: Vec<u8>, // Capacity = decrypt_tag_len
201 }
202 
203 impl crypto::AadOperation for BoringAesGcmDecryptOperation {
update_aad(&mut self, aad: &[u8]) -> Result<(), Error>204     fn update_aad(&mut self, aad: &[u8]) -> Result<(), Error> {
205         ossl!(self.crypter.aad_update(aad))
206     }
207 }
208 
209 impl crypto::EmittingOperation for BoringAesGcmDecryptOperation {
update(&mut self, data: &[u8]) -> Result<Vec<u8>, Error>210     fn update(&mut self, data: &[u8]) -> Result<Vec<u8>, Error> {
211         // The current input is the (self.pending_input_tail || data) combination.
212         let combined_len = self.pending_input_tail.len() + data.len();
213         if combined_len <= self.decrypt_tag_len {
214             // Adding on this data is still not enough for more than just a tag,
215             // so save off the input data for next time and return.
216             self.pending_input_tail.try_extend_from_slice(data)?;
217             return Ok(Vec::new());
218         }
219 
220         // At this point the combination (self.pending_input_tail || data) includes enough data to both:
221         // - feed some into the cipher
222         // - still keep a full self.decrypt_tag_len worth of data still pending.
223         let cipherable_len = combined_len - self.decrypt_tag_len;
224         let cipherable_from_pending = min(cipherable_len, self.pending_input_tail.len());
225         let cipherable_from_data = cipherable_len - cipherable_from_pending;
226 
227         let mut output = vec_try![0; data.len()]?;
228         let mut offset = 0;
229         if cipherable_from_pending > 0 {
230             offset = self
231                 .crypter
232                 .update(&self.pending_input_tail[..cipherable_from_pending], &mut output)
233                 .map_err(openssl_err!(
234                     "update {} bytes from pending failed",
235                     cipherable_from_pending
236                 ))?;
237         }
238         if cipherable_from_data > 0 {
239             let out_len = self
240                 .crypter
241                 .update(&data[..cipherable_from_data], &mut output[offset..])
242                 .map_err(openssl_err!("update {} bytes from input failed", cipherable_from_data))?;
243             offset += out_len;
244         }
245         output.truncate(offset);
246 
247         // Reset `self.pending_input_tail` to the unused data.
248         let leftover_pending = self.pending_input_tail.len() - cipherable_from_pending;
249         self.pending_input_tail.resize(self.decrypt_tag_len, 0);
250         self.pending_input_tail.copy_within(cipherable_from_pending.., 0);
251         self.pending_input_tail[leftover_pending..].copy_from_slice(&data[cipherable_from_data..]);
252 
253         Ok(output)
254     }
255 
finish(mut self: Box<Self>) -> Result<Vec<u8>, Error>256     fn finish(mut self: Box<Self>) -> Result<Vec<u8>, Error> {
257         // Need to feed in the entire tag before completion.
258         if self.pending_input_tail.len() != self.decrypt_tag_len {
259             return Err(km_err!(
260                 InvalidTag,
261                 "only {} bytes of pending data, need {}",
262                 self.pending_input_tail.len(),
263                 self.decrypt_tag_len
264             ));
265         }
266         self.crypter.set_tag(&self.pending_input_tail).map_err(openssl_err!(
267             "failed to set {} bytes of tag",
268             self.pending_input_tail.len()
269         ))?;
270 
271         // Feeding in just the tag should not result in any output data.
272         let mut output = Vec::new();
273         let out_len = self
274             .crypter
275             .finalize(&mut output)
276             .map_err(openssl_err_or!(VerificationFailed, "failed to finalize"))?;
277         if out_len != 0 {
278             return Err(km_err!(
279                 BoringSslError,
280                 "finalizing AES-GCM tag produced {} bytes of data!",
281                 out_len
282             ));
283         }
284         Ok(output)
285     }
286 }
287