Skip to main content

wasefire_board_api/crypto/
cbc.rs

1// Copyright 2024 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Cipher block chaining (CBC).
16
17use crypto_common::generic_array::{ArrayLength, GenericArray};
18#[cfg(feature = "internal-software-crypto-cbc")]
19pub use software::*;
20
21use crate::{Error, Support};
22
23/// CBC interface.
24pub trait Api<Key, Block>: Support<bool> + Send
25where
26    Key: ArrayLength<u8>,
27    Block: ArrayLength<u8>,
28{
29    /// Encrypts a sequence of blocks given a key and IV.
30    fn encrypt(key: &Array<Key>, iv: &Array<Block>, blocks: &mut [u8]) -> Result<(), Error>;
31
32    /// Decrypts a sequence of blocks given a key and IV.
33    fn decrypt(key: &Array<Key>, iv: &Array<Block>, blocks: &mut [u8]) -> Result<(), Error>;
34}
35
36/// Sequence of N bytes.
37pub type Array<N> = GenericArray<u8, N>;
38
39#[cfg(feature = "internal-software-crypto-cbc")]
40mod software {
41    use core::marker::PhantomData;
42
43    use aes::cipher::{BlockCipher, BlockDecryptMut, BlockEncryptMut};
44    use cbc::{Decryptor, Encryptor};
45    use crypto_common::{KeyInit, KeyIvInit, KeySizeUser};
46    use wasefire_error::Code;
47
48    use super::*;
49
50    /// Generic CBC software implementation.
51    pub struct Software<C> {
52        cipher: PhantomData<C>,
53    }
54
55    impl<C> Support<bool> for Software<C> {
56        const SUPPORT: bool = true;
57    }
58
59    impl<Key, Block, C> Api<Key, Block> for Software<C>
60    where
61        C: Send + KeyInit + KeySizeUser<KeySize = Key>,
62        C: BlockCipher<BlockSize = Block> + BlockDecryptMut + BlockEncryptMut,
63        Key: ArrayLength<u8>,
64        Block: ArrayLength<u8>,
65    {
66        fn encrypt(key: &Array<Key>, iv: &Array<Block>, blocks: &mut [u8]) -> Result<(), Error> {
67            Ok(Encryptor::<C>::new(key, iv).encrypt_blocks_mut(convert_blocks(blocks)?))
68        }
69
70        fn decrypt(key: &Array<Key>, iv: &Array<Block>, blocks: &mut [u8]) -> Result<(), Error> {
71            Ok(Decryptor::<C>::new(key, iv).decrypt_blocks_mut(convert_blocks(blocks)?))
72        }
73    }
74
75    fn convert_blocks<N: ArrayLength<u8>>(blocks: &mut [u8]) -> Result<&mut [Array<N>], Error> {
76        if !blocks.len().is_multiple_of(N::USIZE) {
77            return Err(Error::user(Code::InvalidLength));
78        }
79        let ptr = blocks.as_mut_ptr() as *mut Array<N>;
80        let len = blocks.len() / N::USIZE;
81        // SAFETY: Array<N> has the same layout as [u8; N].
82        let blocks = unsafe { core::slice::from_raw_parts_mut(ptr, len) };
83        Ok(blocks)
84    }
85}