xref: /aosp_15_r20/system/keymint/common/src/crypto/des.rs (revision 9860b7637a5f185913c70aa0caabe3ecb78441e4)
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 //! Functionality related to triple DES encryption
16 
17 use super::{nonce, Rng};
18 use crate::{km_err, tag, try_to_vec, Error};
19 use alloc::vec::Vec;
20 use core::convert::TryInto;
21 use kmr_wire::{
22     keymint::{BlockMode, KeyParam, PaddingMode},
23     KeySizeInBits,
24 };
25 use zeroize::ZeroizeOnDrop;
26 
27 /// Size of an DES block in bytes.
28 pub const BLOCK_SIZE: usize = 8;
29 
30 /// The size of a 3-DES key in bits.
31 pub const KEY_SIZE_BITS: KeySizeInBits = KeySizeInBits(168);
32 
33 /// The size of a 3-DES key in bytes.  Note that this is `KEY_SIZE_BITS` / 7, not
34 /// `KEY_SIZE_BITS` / 8 because each byte has a check bit (even though this check
35 /// bit is never actually checked).
36 pub const KEY_SIZE_BYTES: usize = 24;
37 
38 /// A 3-DES key. The key data is 24 bytes / 192 bits in length, but only 7/8 of the
39 /// bits are used giving an effective key size of 168 bits.
40 #[derive(Clone, PartialEq, Eq, ZeroizeOnDrop)]
41 pub struct Key(pub [u8; KEY_SIZE_BYTES]);
42 
43 impl Key {
44     /// Create a new 3-DES key from 24 bytes of data.
new(data: Vec<u8>) -> Result<Key, Error>45     pub fn new(data: Vec<u8>) -> Result<Key, Error> {
46         Ok(Key(data
47             .try_into()
48             .map_err(|_e| km_err!(UnsupportedKeySize, "3-DES key size wrong"))?))
49     }
50     /// Create a new 3-DES key from 24 bytes of data.
new_from(data: &[u8]) -> Result<Key, Error>51     pub fn new_from(data: &[u8]) -> Result<Key, Error> {
52         let data = try_to_vec(data)?;
53         Ok(Key(data
54             .try_into()
55             .map_err(|_e| km_err!(UnsupportedKeySize, "3-DES key size wrong"))?))
56     }
57 }
58 
59 /// Mode of DES operation.  Associated value is the nonce.
60 #[derive(Clone, Copy, Debug)]
61 pub enum Mode {
62     /// ECB mode with no padding.
63     EcbNoPadding,
64     /// ECB mode with PKCS#7 padding.
65     EcbPkcs7Padding,
66     /// CBC mode with no padding.
67     CbcNoPadding {
68         /// Nonce to use.
69         nonce: [u8; BLOCK_SIZE],
70     },
71     /// CBC mode with PKCS#7 padding.
72     CbcPkcs7Padding {
73         /// Nonce to use.
74         nonce: [u8; BLOCK_SIZE],
75     },
76 }
77 
78 impl Mode {
79     /// Determine the [`Mode`], rejecting invalid parameters. Use `caller_nonce` if provided,
80     /// otherwise generate a new nonce using the provided [`Rng`] instance.
new( params: &[KeyParam], caller_nonce: Option<&Vec<u8>>, rng: &mut dyn Rng, ) -> Result<Self, Error>81     pub fn new(
82         params: &[KeyParam],
83         caller_nonce: Option<&Vec<u8>>,
84         rng: &mut dyn Rng,
85     ) -> Result<Self, Error> {
86         let mode = tag::get_block_mode(params)?;
87         let padding = tag::get_padding_mode(params)?;
88         match mode {
89             BlockMode::Ecb => {
90                 if caller_nonce.is_some() {
91                     return Err(km_err!(InvalidNonce, "nonce unexpectedly provided"));
92                 }
93                 match padding {
94                     PaddingMode::None => Ok(Mode::EcbNoPadding),
95                     PaddingMode::Pkcs7 => Ok(Mode::EcbPkcs7Padding),
96                     _ => Err(km_err!(
97                         IncompatiblePaddingMode,
98                         "expected NONE/PKCS7 padding for DES-ECB"
99                     )),
100                 }
101             }
102             BlockMode::Cbc => {
103                 let nonce: [u8; BLOCK_SIZE] = nonce(BLOCK_SIZE, caller_nonce, rng)?
104                     .try_into()
105                     .map_err(|_e| km_err!(InvalidNonce, "want {} byte nonce", BLOCK_SIZE))?;
106                 match padding {
107                     PaddingMode::None => Ok(Mode::CbcNoPadding { nonce }),
108                     PaddingMode::Pkcs7 => Ok(Mode::CbcPkcs7Padding { nonce }),
109                     _ => Err(km_err!(
110                         IncompatiblePaddingMode,
111                         "expected NONE/PKCS7 padding for DES-CBC"
112                     )),
113                 }
114             }
115             _ => Err(km_err!(UnsupportedBlockMode, "want ECB/CBC")),
116         }
117     }
118 }
119