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