1 //! Functionality related to AES encryption 2 3 use super::{nonce, Rng}; 4 use crate::{get_tag_value, km_err, tag, try_to_vec, Error}; 5 use alloc::vec::Vec; 6 use core::convert::TryInto; 7 use kmr_wire::keymint::{BlockMode, ErrorCode, KeyParam, PaddingMode}; 8 use kmr_wire::KeySizeInBits; 9 use zeroize::ZeroizeOnDrop; 10 11 /// Size of an AES block in bytes. 12 pub const BLOCK_SIZE: usize = 16; 13 14 /// Size of AES-GCM nonce in bytes. 15 pub const GCM_NONCE_SIZE: usize = 12; // 96 bits 16 17 /// AES variant. 18 #[derive(Clone)] 19 pub enum Variant { 20 Aes128, 21 Aes192, 22 Aes256, 23 } 24 25 /// An AES-128, AES-192 or AES-256 key. 26 #[derive(Clone, PartialEq, Eq, ZeroizeOnDrop)] 27 pub enum Key { 28 Aes128([u8; 16]), 29 Aes192([u8; 24]), 30 Aes256([u8; 32]), 31 } 32 33 impl Key { 34 /// Create a new [`Key`] from raw data, which must be 16, 24 or 32 bytes long. new(data: Vec<u8>) -> Result<Self, Error>35 pub fn new(data: Vec<u8>) -> Result<Self, Error> { 36 match data.len() { 37 16 => Ok(Key::Aes128(data.try_into().unwrap())), // safe: len checked 38 24 => Ok(Key::Aes192(data.try_into().unwrap())), // safe: len checked 39 32 => Ok(Key::Aes256(data.try_into().unwrap())), // safe: len checked 40 l => Err(km_err!(UnsupportedKeySize, "AES keys must be 16, 24 or 32 bytes not {}", l)), 41 } 42 } 43 /// Create a new [`Key`] from raw data, which must be 16, 24 or 32 bytes long. new_from(data: &[u8]) -> Result<Self, Error>44 pub fn new_from(data: &[u8]) -> Result<Self, Error> { 45 Key::new(try_to_vec(data)?) 46 } 47 48 /// Indicate the size of the key in bits. size(&self) -> KeySizeInBits49 pub fn size(&self) -> KeySizeInBits { 50 KeySizeInBits(match self { 51 Key::Aes128(_) => 128, 52 Key::Aes192(_) => 192, 53 Key::Aes256(_) => 256, 54 }) 55 } 56 } 57 58 /// Mode of AES plain cipher operation. Associated value is the nonce. 59 #[derive(Clone, Copy, Debug)] 60 pub enum CipherMode { 61 EcbNoPadding, 62 EcbPkcs7Padding, 63 CbcNoPadding { nonce: [u8; BLOCK_SIZE] }, 64 CbcPkcs7Padding { nonce: [u8; BLOCK_SIZE] }, 65 Ctr { nonce: [u8; BLOCK_SIZE] }, 66 } 67 68 /// Mode of AES-GCM operation. Associated value is the nonce. 69 #[derive(Clone, Copy, Debug)] 70 pub enum GcmMode { 71 GcmTag12 { nonce: [u8; GCM_NONCE_SIZE] }, 72 GcmTag13 { nonce: [u8; GCM_NONCE_SIZE] }, 73 GcmTag14 { nonce: [u8; GCM_NONCE_SIZE] }, 74 GcmTag15 { nonce: [u8; GCM_NONCE_SIZE] }, 75 GcmTag16 { nonce: [u8; GCM_NONCE_SIZE] }, 76 } 77 78 /// Mode of AES operation. 79 #[derive(Clone, Copy, Debug)] 80 pub enum Mode { 81 Cipher(CipherMode), 82 Aead(GcmMode), 83 } 84 85 impl Mode { 86 /// Determine the [`Mode`], rejecting invalid parameters. Use `caller_nonce` if provided, 87 /// 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>88 pub fn new( 89 params: &[KeyParam], 90 caller_nonce: Option<&Vec<u8>>, 91 rng: &mut dyn Rng, 92 ) -> Result<Self, Error> { 93 let mode = tag::get_block_mode(params)?; 94 let padding = tag::get_padding_mode(params)?; 95 match mode { 96 BlockMode::Ecb => { 97 if caller_nonce.is_some() { 98 return Err(km_err!(InvalidNonce, "nonce unexpectedly provided for AES-ECB")); 99 } 100 match padding { 101 PaddingMode::None => Ok(Mode::Cipher(CipherMode::EcbNoPadding)), 102 PaddingMode::Pkcs7 => Ok(Mode::Cipher(CipherMode::EcbPkcs7Padding)), 103 _ => Err(km_err!( 104 IncompatiblePaddingMode, 105 "expected NONE/PKCS7 padding for AES-ECB" 106 )), 107 } 108 } 109 BlockMode::Cbc => { 110 let nonce: [u8; BLOCK_SIZE] = 111 nonce(BLOCK_SIZE, caller_nonce, rng)?.try_into().map_err(|_e| { 112 km_err!(InvalidNonce, "want {} byte nonce for AES-CBC", BLOCK_SIZE) 113 })?; 114 match padding { 115 PaddingMode::None => Ok(Mode::Cipher(CipherMode::CbcNoPadding { nonce })), 116 PaddingMode::Pkcs7 => Ok(Mode::Cipher(CipherMode::CbcPkcs7Padding { nonce })), 117 _ => Err(km_err!( 118 IncompatiblePaddingMode, 119 "expected NONE/PKCS7 padding for AES-CBC" 120 )), 121 } 122 } 123 BlockMode::Ctr => { 124 if padding != PaddingMode::None { 125 return Err(km_err!( 126 IncompatiblePaddingMode, 127 "expected NONE padding for AES-CTR" 128 )); 129 } 130 let nonce: [u8; BLOCK_SIZE] = 131 nonce(BLOCK_SIZE, caller_nonce, rng)?.try_into().map_err(|_e| { 132 km_err!(InvalidNonce, "want {} byte nonce for AES-CTR", BLOCK_SIZE) 133 })?; 134 Ok(Mode::Cipher(CipherMode::Ctr { nonce })) 135 } 136 BlockMode::Gcm => { 137 if padding != PaddingMode::None { 138 return Err(km_err!( 139 IncompatiblePaddingMode, 140 "expected NONE padding for AES-GCM" 141 )); 142 } 143 let nonce: [u8; GCM_NONCE_SIZE] = nonce(GCM_NONCE_SIZE, caller_nonce, rng)? 144 .try_into() 145 .map_err(|_e| km_err!(InvalidNonce, "want 12 byte nonce for AES-GCM"))?; 146 let tag_len = get_tag_value!(params, MacLength, ErrorCode::InvalidMacLength)?; 147 if tag_len % 8 != 0 { 148 return Err(km_err!( 149 InvalidMacLength, 150 "tag length {} not a multiple of 8", 151 tag_len 152 )); 153 } 154 match tag_len / 8 { 155 12 => Ok(Mode::Aead(GcmMode::GcmTag12 { nonce })), 156 13 => Ok(Mode::Aead(GcmMode::GcmTag13 { nonce })), 157 14 => Ok(Mode::Aead(GcmMode::GcmTag14 { nonce })), 158 15 => Ok(Mode::Aead(GcmMode::GcmTag15 { nonce })), 159 16 => Ok(Mode::Aead(GcmMode::GcmTag16 { nonce })), 160 v => Err(km_err!( 161 InvalidMacLength, 162 "want 12-16 byte tag for AES-GCM not {} bytes", 163 v 164 )), 165 } 166 } 167 } 168 } 169 170 /// Indicate whether the AES mode is an AEAD. is_aead(&self) -> bool171 pub fn is_aead(&self) -> bool { 172 match self { 173 Mode::Aead(_) => true, 174 Mode::Cipher(_) => false, 175 } 176 } 177 } 178 179 impl GcmMode { 180 /// Return the tag length (in bytes) for an AES-GCM mode. tag_len(&self) -> usize181 pub fn tag_len(&self) -> usize { 182 match self { 183 GcmMode::GcmTag12 { nonce: _ } => 12, 184 GcmMode::GcmTag13 { nonce: _ } => 13, 185 GcmMode::GcmTag14 { nonce: _ } => 14, 186 GcmMode::GcmTag15 { nonce: _ } => 15, 187 GcmMode::GcmTag16 { nonce: _ } => 16, 188 } 189 } 190 } 191