askar_crypto/alg/aes/
key_wrap.rs1use core::marker::PhantomData;
4
5use aes_core::{
6 cipher::{BlockCipher, BlockDecrypt, BlockEncrypt, KeyInit, KeySizeUser},
7 Aes128, Aes256,
8};
9use subtle::ConstantTimeEq;
10
11use super::{AesKey, AesType, NonceSize, TagSize};
12use crate::{
13 alg::AesTypes,
14 buffer::ResizeBuffer,
15 encrypt::{KeyAeadInPlace, KeyAeadMeta, KeyAeadParams},
16 error::Error,
17 generic_array::{
18 typenum::{consts, Unsigned},
19 GenericArray,
20 },
21};
22
23const AES_KW_DEFAULT_IV: [u8; 8] = [166, 166, 166, 166, 166, 166, 166, 166];
24
25pub type A128Kw = AesKeyWrap<Aes128>;
27
28impl AesType for A128Kw {
29 type KeySize = <Aes128 as KeySizeUser>::KeySize;
30 const ALG_TYPE: AesTypes = AesTypes::A128Kw;
31 const JWK_ALG: &'static str = "A128KW";
32}
33
34pub type A256Kw = AesKeyWrap<Aes256>;
36
37impl AesType for A256Kw {
38 type KeySize = <Aes256 as KeySizeUser>::KeySize;
39 const ALG_TYPE: AesTypes = AesTypes::A256Kw;
40 const JWK_ALG: &'static str = "A256KW";
41}
42
43#[derive(Debug)]
45pub struct AesKeyWrap<C>(PhantomData<C>);
46
47impl<C> KeyAeadMeta for AesKey<AesKeyWrap<C>>
48where
49 AesKeyWrap<C>: AesType,
50{
51 type NonceSize = consts::U0;
52 type TagSize = consts::U8;
53}
54
55impl<C> KeyAeadInPlace for AesKey<AesKeyWrap<C>>
56where
57 AesKeyWrap<C>: AesType,
58 C: KeyInit
59 + KeySizeUser<KeySize = <AesKeyWrap<C> as AesType>::KeySize>
60 + BlockCipher<BlockSize = consts::U16>
61 + BlockDecrypt
62 + BlockEncrypt,
63{
64 fn encrypt_in_place(
65 &self,
66 buffer: &mut dyn ResizeBuffer,
67 nonce: &[u8],
68 aad: &[u8],
69 ) -> Result<usize, Error> {
70 if !nonce.is_empty() {
71 return Err(err_msg!(Unsupported, "Custom nonce not supported"));
72 }
73 if !aad.is_empty() {
74 return Err(err_msg!(Unsupported, "AAD not supported"));
75 }
76 let mut buf_len = buffer.as_ref().len();
77 if buf_len % 8 != 0 {
78 return Err(err_msg!(
79 Unsupported,
80 "Data length must be a multiple of 8 bytes"
81 ));
82 }
83 let blocks = buf_len / 8;
84
85 buffer.buffer_insert(0, &[0u8; 8])?;
86 buf_len += 8;
87
88 let aes = C::new(self.0.as_ref());
89 let mut iv = AES_KW_DEFAULT_IV;
90 let mut block = GenericArray::default();
91 for j in 0..6 {
92 for (i, chunk) in buffer.as_mut()[8..].chunks_exact_mut(8).enumerate() {
93 block[0..8].copy_from_slice(iv.as_ref());
94 block[8..16].copy_from_slice(chunk);
95 aes.encrypt_block(&mut block);
96 let t = (((blocks * j) + i + 1) as u64).to_be_bytes();
97 iv.copy_from_slice(&block[0..8]);
98 for (a, t) in iv.as_mut().iter_mut().zip(&t[..]) {
99 *a ^= t;
100 }
101 chunk.copy_from_slice(&block[8..16]);
102 }
103 }
104 buffer.as_mut()[0..8].copy_from_slice(&iv[..]);
105 Ok(buf_len)
106 }
107
108 fn decrypt_in_place(
109 &self,
110 buffer: &mut dyn ResizeBuffer,
111 nonce: &[u8],
112 aad: &[u8],
113 ) -> Result<(), Error> {
114 if !nonce.is_empty() {
115 return Err(err_msg!(Unsupported, "Custom nonce not supported"));
116 }
117 if !aad.is_empty() {
118 return Err(err_msg!(Unsupported, "AAD not supported"));
119 }
120 if buffer.as_ref().len() % 8 != 0 {
121 return Err(err_msg!(
122 Encryption,
123 "Data length must be a multiple of 8 bytes"
124 ));
125 }
126 let mut blocks = buffer.as_ref().len() / 8;
127 if blocks < 1 {
128 return Err(err_msg!(Encryption));
129 }
130 blocks -= 1;
131
132 let aes = C::new(self.0.as_ref());
133 let mut iv = *TryInto::<&[u8; 8]>::try_into(&buffer.as_ref()[0..8]).unwrap();
134 buffer.buffer_remove(0..8)?;
135
136 let mut block = GenericArray::default();
137 for j in (0..6).rev() {
138 for (i, chunk) in buffer.as_mut().chunks_exact_mut(8).enumerate().rev() {
139 block[0..8].copy_from_slice(iv.as_ref());
140 let t = (((blocks * j) + i + 1) as u64).to_be_bytes();
141 for (a, t) in block[0..8].iter_mut().zip(&t[..]) {
142 *a ^= t;
143 }
144 block[8..16].copy_from_slice(chunk);
145 aes.decrypt_block(&mut block);
146 iv.copy_from_slice(&block[0..8]);
147 chunk.copy_from_slice(&block[8..16]);
148 }
149 }
150
151 if iv.ct_eq(&AES_KW_DEFAULT_IV).unwrap_u8() == 1 {
152 Ok(())
153 } else {
154 Err(err_msg!(Encryption))
155 }
156 }
157
158 fn aead_params(&self) -> KeyAeadParams {
159 KeyAeadParams {
160 nonce_length: NonceSize::<Self>::USIZE,
161 tag_length: TagSize::<Self>::USIZE,
162 }
163 }
164}
165
166#[cfg(test)]
167mod tests {
168 use super::*;
169 use crate::buffer::SecretBytes;
170 use crate::repr::KeySecretBytes;
171 use std::string::ToString;
172
173 #[test]
174 fn key_wrap_128_expected() {
176 let key =
177 AesKey::<A128Kw>::from_secret_bytes(&hex!("000102030405060708090a0b0c0d0e0f")).unwrap();
178 let input = &hex!("00112233445566778899aabbccddeeff");
179 let mut buffer = SecretBytes::from_slice(input);
180 key.encrypt_in_place(&mut buffer, &[], &[]).unwrap();
181 assert_eq!(
182 buffer.as_hex().to_string(),
183 "1fa68b0a8112b447aef34bd8fb5a7b829d3e862371d2cfe5"
184 );
185 key.decrypt_in_place(&mut buffer, &[], &[]).unwrap();
186 assert_eq!(buffer, &input[..]);
187 }
188
189 #[test]
190 fn key_wrap_256_expected() {
192 let key = AesKey::<A256Kw>::from_secret_bytes(&hex!(
193 "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"
194 ))
195 .unwrap();
196 let input = &hex!("00112233445566778899aabbccddeeff");
197 let mut buffer = SecretBytes::from_slice(input);
198 key.encrypt_in_place(&mut buffer, &[], &[]).unwrap();
199 assert_eq!(
200 buffer.as_hex().to_string(),
201 "64e8c3f9ce0f5ba263e9777905818a2a93c8191e7d6e8ae7"
202 );
203 key.decrypt_in_place(&mut buffer, &[], &[]).unwrap();
204 assert_eq!(buffer, &input[..]);
205 }
206}