1use core::ops::{Add, Div, Mul};
2
3use crate::{Error, IV_LEN, IntegrityCheckFailed, IvLen, ctx::Ctx};
4use aes::cipher::{
5 Array, Block, BlockCipherDecrypt, BlockCipherEncrypt,
6 array::ArraySize,
7 common::{InnerInit, InnerUser},
8 consts::{B1, U7, U4294967296},
9 typenum::{Add1, IsLess, Le, NonZero, Prod, Quot, Sum, U16},
10};
11
12type KwpMaxLen = U4294967296;
14const KWP_MAX_LEN: usize = u32::MAX as usize;
16
17const KWP_IV_PREFIX: [u8; IV_LEN / 2] = [0xA6, 0x59, 0x59, 0xA6];
27
28type IvLenM1 = U7;
30
31pub type KwpWrappedKey<N> = Array<u8, Prod<Add1<Quot<Sum<N, IvLenM1>, IvLen>>, IvLen>>;
34
35#[derive(Debug, Clone, Copy, PartialEq)]
39pub struct AesKwp<C> {
40 cipher: C,
41}
42
43impl<C> InnerUser for AesKwp<C> {
44 type Inner = C;
45}
46
47impl<C> InnerInit for AesKwp<C> {
48 #[inline]
49 fn inner_init(cipher: Self::Inner) -> Self {
50 AesKwp { cipher }
51 }
52}
53
54impl<C: BlockCipherEncrypt<BlockSize = U16>> AesKwp<C> {
55 fn wrap_key_trusted(&self, key: &[u8], buf: &mut [u8]) {
57 let semiblocks_len = key.len().div_ceil(IV_LEN);
58
59 let block = &mut Block::<C>::default();
65 let (prefix, mli) = block[..IV_LEN].split_at_mut(IV_LEN / 2);
66 prefix.copy_from_slice(&KWP_IV_PREFIX);
67 mli.copy_from_slice(&(key.len() as u32).to_be_bytes());
69
70 if semiblocks_len == 1 {
72 block[IV_LEN..][..key.len()].copy_from_slice(key);
75 self.cipher
76 .encrypt_block_b2b(block, buf.try_into().unwrap());
77 } else {
78 buf[IV_LEN..][..key.len()].copy_from_slice(key);
82
83 self.cipher.encrypt_with_backend(Ctx {
84 blocks_len: semiblocks_len,
85 block,
86 buf,
87 });
88
89 buf[..IV_LEN].copy_from_slice(&block[..IV_LEN]);
91 }
92 }
93
94 #[inline]
100 pub fn wrap_key<'a>(&self, key: &[u8], buf: &'a mut [u8]) -> Result<&'a [u8], Error> {
101 if key.len() > KWP_MAX_LEN {
102 return Err(Error::InvalidDataSize);
103 }
104
105 let semiblocks_len = key.len().div_ceil(IV_LEN);
109
110 let expected_len = semiblocks_len * IV_LEN + IV_LEN;
111 let buf = buf
112 .get_mut(..expected_len)
113 .ok_or(Error::InvalidOutputSize { expected_len })?;
114
115 self.wrap_key_trusted(key, buf);
116
117 Ok(buf)
118 }
119
120 #[inline]
133 pub fn wrap_fixed_key<N>(&self, key: &Array<u8, N>) -> KwpWrappedKey<N>
134 where
135 N: ArraySize + Add<IvLenM1> + IsLess<KwpMaxLen>,
136 Le<N, KwpMaxLen>: NonZero,
137 Sum<N, IvLenM1>: Div<IvLen>,
138 Quot<Sum<N, IvLenM1>, IvLen>: Add<B1>,
139 Add1<Quot<Sum<N, IvLenM1>, IvLen>>: Mul<IvLen>,
140 Prod<Add1<Quot<Sum<N, IvLenM1>, IvLen>>, IvLen>: ArraySize,
141 {
142 let semiblocks_len = key.len().div_ceil(IV_LEN);
147 let mut buf = KwpWrappedKey::<N>::default();
148 assert_eq!(semiblocks_len * IV_LEN + IV_LEN, buf.len());
149
150 self.wrap_key_trusted(key, &mut buf);
151
152 buf
153 }
154}
155
156impl<C: BlockCipherDecrypt<BlockSize = U16>> AesKwp<C> {
157 fn unwrap_key_trusted<'a>(
159 &self,
160 wkey: &[u8],
161 buf: &'a mut [u8],
162 ) -> Result<&'a [u8], IntegrityCheckFailed> {
163 let blocks_len = buf.len() / IV_LEN;
164
165 let block = &mut Block::<C>::default();
170
171 if blocks_len == 1 {
173 block.copy_from_slice(wkey);
174 self.cipher.decrypt_block(block);
175 buf.copy_from_slice(&block[IV_LEN..]);
176 } else {
177 block[..IV_LEN].copy_from_slice(&wkey[..IV_LEN]);
178
179 buf.copy_from_slice(&wkey[IV_LEN..]);
181
182 self.cipher.decrypt_with_backend(Ctx {
185 blocks_len,
186 block,
187 buf,
188 });
189 }
190
191 let prefix_calc = u32::from_ne_bytes(block[..IV_LEN / 2].try_into().unwrap());
196 let prefix_exp = u32::from_ne_bytes(KWP_IV_PREFIX);
197 if prefix_calc != prefix_exp {
198 buf.fill(0);
199 return Err(IntegrityCheckFailed);
200 }
201
202 let mli_bytes = block[IV_LEN / 2..IV_LEN].try_into().unwrap();
203 let mli: usize = usize::try_from(u32::from_be_bytes(mli_bytes)).map_err(|_| {
204 buf.fill(0);
205 IntegrityCheckFailed
206 })?;
207 if mli.div_ceil(IV_LEN) != blocks_len {
208 buf.fill(0);
209 return Err(IntegrityCheckFailed);
210 }
211
212 let (res, pad) = buf.split_at_mut(mli);
213 if !pad.iter().all(|&b| b == 0) {
214 res.fill(0);
215 pad.fill(0);
216 return Err(IntegrityCheckFailed);
217 }
218
219 Ok(res)
220 }
221
222 #[inline]
229 pub fn unwrap_key<'a>(&self, data: &[u8], buf: &'a mut [u8]) -> Result<&'a [u8], Error> {
230 let blocks_len = data.len() / IV_LEN;
231 let blocks_rem = data.len() % IV_LEN;
232 if blocks_rem != 0 || blocks_len < 1 || data.len() > KWP_MAX_LEN {
233 return Err(Error::InvalidDataSize);
234 }
235
236 let blocks_len = blocks_len - 1;
237 let expected_len = blocks_len * IV_LEN;
238 let buf = buf
239 .get_mut(..expected_len)
240 .ok_or(Error::InvalidOutputSize { expected_len })?;
241
242 self.unwrap_key_trusted(data, buf)
243 .map_err(|_| Error::IntegrityCheckFailed)
244 }
245
246 #[inline]
259 pub fn unwrap_fixed_key<N>(
260 &self,
261 wkey: &KwpWrappedKey<N>,
262 ) -> Result<Array<u8, N>, IntegrityCheckFailed>
263 where
264 N: ArraySize + Add<IvLenM1> + IsLess<KwpMaxLen>,
265 Le<N, KwpMaxLen>: NonZero,
266 Sum<N, IvLenM1>: Div<IvLen>,
267 Quot<Sum<N, IvLenM1>, IvLen>: Add<B1> + Mul<IvLen>,
268 Add1<Quot<Sum<N, IvLenM1>, IvLen>>: Mul<IvLen>,
269 Prod<Add1<Quot<Sum<N, IvLenM1>, IvLen>>, IvLen>: ArraySize,
270 Prod<Quot<Sum<N, IvLenM1>, IvLen>, IvLen>: ArraySize,
271 {
272 let mut buf = Array::<u8, Prod<Quot<Sum<N, IvLenM1>, IvLen>, IvLen>>::default();
273 self.unwrap_key_trusted(wkey, &mut buf)
274 .map(|res| res.try_into().unwrap())
275 }
276}
277
278#[cfg(feature = "zeroize")]
279impl<C: zeroize::ZeroizeOnDrop> zeroize::ZeroizeOnDrop for AesKwp<C> {}