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