• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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