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