xref: /aosp_15_r20/system/keymint/common/src/crypto/des.rs (revision 9860b7637a5f185913c70aa0caabe3ecb78441e4)
1*9860b763SAndroid Build Coastguard Worker // Copyright 2022, The Android Open Source Project
2*9860b763SAndroid Build Coastguard Worker //
3*9860b763SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*9860b763SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*9860b763SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*9860b763SAndroid Build Coastguard Worker //
7*9860b763SAndroid Build Coastguard Worker //     http://www.apache.org/licenses/LICENSE-2.0
8*9860b763SAndroid Build Coastguard Worker //
9*9860b763SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*9860b763SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*9860b763SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9860b763SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*9860b763SAndroid Build Coastguard Worker // limitations under the License.
14*9860b763SAndroid Build Coastguard Worker 
15*9860b763SAndroid Build Coastguard Worker //! Functionality related to triple DES encryption
16*9860b763SAndroid Build Coastguard Worker 
17*9860b763SAndroid Build Coastguard Worker use super::{nonce, Rng};
18*9860b763SAndroid Build Coastguard Worker use crate::{km_err, tag, try_to_vec, Error};
19*9860b763SAndroid Build Coastguard Worker use alloc::vec::Vec;
20*9860b763SAndroid Build Coastguard Worker use core::convert::TryInto;
21*9860b763SAndroid Build Coastguard Worker use kmr_wire::{
22*9860b763SAndroid Build Coastguard Worker     keymint::{BlockMode, KeyParam, PaddingMode},
23*9860b763SAndroid Build Coastguard Worker     KeySizeInBits,
24*9860b763SAndroid Build Coastguard Worker };
25*9860b763SAndroid Build Coastguard Worker use zeroize::ZeroizeOnDrop;
26*9860b763SAndroid Build Coastguard Worker 
27*9860b763SAndroid Build Coastguard Worker /// Size of an DES block in bytes.
28*9860b763SAndroid Build Coastguard Worker pub const BLOCK_SIZE: usize = 8;
29*9860b763SAndroid Build Coastguard Worker 
30*9860b763SAndroid Build Coastguard Worker /// The size of a 3-DES key in bits.
31*9860b763SAndroid Build Coastguard Worker pub const KEY_SIZE_BITS: KeySizeInBits = KeySizeInBits(168);
32*9860b763SAndroid Build Coastguard Worker 
33*9860b763SAndroid Build Coastguard Worker /// The size of a 3-DES key in bytes.  Note that this is `KEY_SIZE_BITS` / 7, not
34*9860b763SAndroid Build Coastguard Worker /// `KEY_SIZE_BITS` / 8 because each byte has a check bit (even though this check
35*9860b763SAndroid Build Coastguard Worker /// bit is never actually checked).
36*9860b763SAndroid Build Coastguard Worker pub const KEY_SIZE_BYTES: usize = 24;
37*9860b763SAndroid Build Coastguard Worker 
38*9860b763SAndroid Build Coastguard Worker /// A 3-DES key. The key data is 24 bytes / 192 bits in length, but only 7/8 of the
39*9860b763SAndroid Build Coastguard Worker /// bits are used giving an effective key size of 168 bits.
40*9860b763SAndroid Build Coastguard Worker #[derive(Clone, PartialEq, Eq, ZeroizeOnDrop)]
41*9860b763SAndroid Build Coastguard Worker pub struct Key(pub [u8; KEY_SIZE_BYTES]);
42*9860b763SAndroid Build Coastguard Worker 
43*9860b763SAndroid Build Coastguard Worker impl Key {
44*9860b763SAndroid Build Coastguard Worker     /// Create a new 3-DES key from 24 bytes of data.
new(data: Vec<u8>) -> Result<Key, Error>45*9860b763SAndroid Build Coastguard Worker     pub fn new(data: Vec<u8>) -> Result<Key, Error> {
46*9860b763SAndroid Build Coastguard Worker         Ok(Key(data
47*9860b763SAndroid Build Coastguard Worker             .try_into()
48*9860b763SAndroid Build Coastguard Worker             .map_err(|_e| km_err!(UnsupportedKeySize, "3-DES key size wrong"))?))
49*9860b763SAndroid Build Coastguard Worker     }
50*9860b763SAndroid Build Coastguard Worker     /// Create a new 3-DES key from 24 bytes of data.
new_from(data: &[u8]) -> Result<Key, Error>51*9860b763SAndroid Build Coastguard Worker     pub fn new_from(data: &[u8]) -> Result<Key, Error> {
52*9860b763SAndroid Build Coastguard Worker         let data = try_to_vec(data)?;
53*9860b763SAndroid Build Coastguard Worker         Ok(Key(data
54*9860b763SAndroid Build Coastguard Worker             .try_into()
55*9860b763SAndroid Build Coastguard Worker             .map_err(|_e| km_err!(UnsupportedKeySize, "3-DES key size wrong"))?))
56*9860b763SAndroid Build Coastguard Worker     }
57*9860b763SAndroid Build Coastguard Worker }
58*9860b763SAndroid Build Coastguard Worker 
59*9860b763SAndroid Build Coastguard Worker /// Mode of DES operation.  Associated value is the nonce.
60*9860b763SAndroid Build Coastguard Worker #[derive(Clone, Copy, Debug)]
61*9860b763SAndroid Build Coastguard Worker pub enum Mode {
62*9860b763SAndroid Build Coastguard Worker     /// ECB mode with no padding.
63*9860b763SAndroid Build Coastguard Worker     EcbNoPadding,
64*9860b763SAndroid Build Coastguard Worker     /// ECB mode with PKCS#7 padding.
65*9860b763SAndroid Build Coastguard Worker     EcbPkcs7Padding,
66*9860b763SAndroid Build Coastguard Worker     /// CBC mode with no padding.
67*9860b763SAndroid Build Coastguard Worker     CbcNoPadding {
68*9860b763SAndroid Build Coastguard Worker         /// Nonce to use.
69*9860b763SAndroid Build Coastguard Worker         nonce: [u8; BLOCK_SIZE],
70*9860b763SAndroid Build Coastguard Worker     },
71*9860b763SAndroid Build Coastguard Worker     /// CBC mode with PKCS#7 padding.
72*9860b763SAndroid Build Coastguard Worker     CbcPkcs7Padding {
73*9860b763SAndroid Build Coastguard Worker         /// Nonce to use.
74*9860b763SAndroid Build Coastguard Worker         nonce: [u8; BLOCK_SIZE],
75*9860b763SAndroid Build Coastguard Worker     },
76*9860b763SAndroid Build Coastguard Worker }
77*9860b763SAndroid Build Coastguard Worker 
78*9860b763SAndroid Build Coastguard Worker impl Mode {
79*9860b763SAndroid Build Coastguard Worker     /// Determine the [`Mode`], rejecting invalid parameters. Use `caller_nonce` if provided,
80*9860b763SAndroid Build Coastguard Worker     /// 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*9860b763SAndroid Build Coastguard Worker     pub fn new(
82*9860b763SAndroid Build Coastguard Worker         params: &[KeyParam],
83*9860b763SAndroid Build Coastguard Worker         caller_nonce: Option<&Vec<u8>>,
84*9860b763SAndroid Build Coastguard Worker         rng: &mut dyn Rng,
85*9860b763SAndroid Build Coastguard Worker     ) -> Result<Self, Error> {
86*9860b763SAndroid Build Coastguard Worker         let mode = tag::get_block_mode(params)?;
87*9860b763SAndroid Build Coastguard Worker         let padding = tag::get_padding_mode(params)?;
88*9860b763SAndroid Build Coastguard Worker         match mode {
89*9860b763SAndroid Build Coastguard Worker             BlockMode::Ecb => {
90*9860b763SAndroid Build Coastguard Worker                 if caller_nonce.is_some() {
91*9860b763SAndroid Build Coastguard Worker                     return Err(km_err!(InvalidNonce, "nonce unexpectedly provided"));
92*9860b763SAndroid Build Coastguard Worker                 }
93*9860b763SAndroid Build Coastguard Worker                 match padding {
94*9860b763SAndroid Build Coastguard Worker                     PaddingMode::None => Ok(Mode::EcbNoPadding),
95*9860b763SAndroid Build Coastguard Worker                     PaddingMode::Pkcs7 => Ok(Mode::EcbPkcs7Padding),
96*9860b763SAndroid Build Coastguard Worker                     _ => Err(km_err!(
97*9860b763SAndroid Build Coastguard Worker                         IncompatiblePaddingMode,
98*9860b763SAndroid Build Coastguard Worker                         "expected NONE/PKCS7 padding for DES-ECB"
99*9860b763SAndroid Build Coastguard Worker                     )),
100*9860b763SAndroid Build Coastguard Worker                 }
101*9860b763SAndroid Build Coastguard Worker             }
102*9860b763SAndroid Build Coastguard Worker             BlockMode::Cbc => {
103*9860b763SAndroid Build Coastguard Worker                 let nonce: [u8; BLOCK_SIZE] = nonce(BLOCK_SIZE, caller_nonce, rng)?
104*9860b763SAndroid Build Coastguard Worker                     .try_into()
105*9860b763SAndroid Build Coastguard Worker                     .map_err(|_e| km_err!(InvalidNonce, "want {} byte nonce", BLOCK_SIZE))?;
106*9860b763SAndroid Build Coastguard Worker                 match padding {
107*9860b763SAndroid Build Coastguard Worker                     PaddingMode::None => Ok(Mode::CbcNoPadding { nonce }),
108*9860b763SAndroid Build Coastguard Worker                     PaddingMode::Pkcs7 => Ok(Mode::CbcPkcs7Padding { nonce }),
109*9860b763SAndroid Build Coastguard Worker                     _ => Err(km_err!(
110*9860b763SAndroid Build Coastguard Worker                         IncompatiblePaddingMode,
111*9860b763SAndroid Build Coastguard Worker                         "expected NONE/PKCS7 padding for DES-CBC"
112*9860b763SAndroid Build Coastguard Worker                     )),
113*9860b763SAndroid Build Coastguard Worker                 }
114*9860b763SAndroid Build Coastguard Worker             }
115*9860b763SAndroid Build Coastguard Worker             _ => Err(km_err!(UnsupportedBlockMode, "want ECB/CBC")),
116*9860b763SAndroid Build Coastguard Worker         }
117*9860b763SAndroid Build Coastguard Worker     }
118*9860b763SAndroid Build Coastguard Worker }
119