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 3-DES.
16 use crate::{openssl_err, ossl};
17 use alloc::boxed::Box;
18 use alloc::vec::Vec;
19 use kmr_common::{crypto, crypto::OpaqueOr, explicit, vec_try, Error};
20 use openssl::symm::{Cipher, Crypter};
21 
22 /// [`crypto::Des`] implementation based on BoringSSL.
23 pub struct BoringDes;
24 
25 impl crypto::Des for BoringDes {
begin( &self, key: OpaqueOr<crypto::des::Key>, mode: crypto::des::Mode, dir: crypto::SymmetricOperation, ) -> Result<Box<dyn crypto::EmittingOperation>, Error>26     fn begin(
27         &self,
28         key: OpaqueOr<crypto::des::Key>,
29         mode: crypto::des::Mode,
30         dir: crypto::SymmetricOperation,
31     ) -> Result<Box<dyn crypto::EmittingOperation>, Error> {
32         let key = explicit!(key)?;
33         let dir_mode = match dir {
34             crypto::SymmetricOperation::Encrypt => openssl::symm::Mode::Encrypt,
35             crypto::SymmetricOperation::Decrypt => openssl::symm::Mode::Decrypt,
36         };
37         let crypter = match mode {
38             crypto::des::Mode::EcbNoPadding | crypto::des::Mode::EcbPkcs7Padding => {
39                 let cipher = Cipher::des_ede3();
40                 let mut crypter = Crypter::new(cipher, dir_mode, &key.0, None)
41                     .map_err(openssl_err!("failed to create ECB Crypter"))?;
42                 if let crypto::des::Mode::EcbPkcs7Padding = mode {
43                     crypter.pad(true);
44                 } else {
45                     crypter.pad(false);
46                 }
47                 crypter
48             }
49 
50             crypto::des::Mode::CbcNoPadding { nonce: n }
51             | crypto::des::Mode::CbcPkcs7Padding { nonce: n } => {
52                 let cipher = Cipher::des_ede3_cbc();
53                 let mut crypter = Crypter::new(cipher, dir_mode, &key.0, Some(&n[..]))
54                     .map_err(openssl_err!("failed to create CBC Crypter"))?;
55                 if let crypto::des::Mode::CbcPkcs7Padding { nonce: _ } = mode {
56                     crypter.pad(true);
57                 } else {
58                     crypter.pad(false);
59                 }
60                 crypter
61             }
62         };
63 
64         Ok(Box::new(BoringDesOperation { crypter }))
65     }
66 }
67 
68 /// [`crypto::DesOperation`] implementation based on BoringSSL.
69 pub struct BoringDesOperation {
70     crypter: openssl::symm::Crypter,
71 }
72 
73 impl crypto::EmittingOperation for BoringDesOperation {
update(&mut self, data: &[u8]) -> Result<Vec<u8>, Error>74     fn update(&mut self, data: &[u8]) -> Result<Vec<u8>, Error> {
75         let mut output = vec_try![0; data.len() + crypto::des::BLOCK_SIZE]?;
76         let out_len = self
77             .crypter
78             .update(data, &mut output[..])
79             .map_err(openssl_err!("update with {} bytes of data failed", data.len()))?;
80         output.truncate(out_len);
81         Ok(output)
82     }
83 
finish(mut self: Box<Self>) -> Result<Vec<u8>, Error>84     fn finish(mut self: Box<Self>) -> Result<Vec<u8>, Error> {
85         let mut output = vec_try![0; crypto::des::BLOCK_SIZE]?;
86         let out_len = ossl!(self.crypter.finalize(&mut output))?;
87         output.truncate(out_len);
88         Ok(output)
89     }
90 }
91