Skip to main content

kernel/hil/
symmetric_encryption.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4// Copyright OxidOS Automotive 2026.
5
6//! Interface for symmetric-cipher encryption
7//!
8//! see boards/imix/src/aes_test.rs for example usage
9
10use crate::ErrorCode;
11
12/// Implement this trait and use `set_client()` in order to receive callbacks from an `AES`
13/// instance.
14pub trait Client<'a> {
15    fn crypt_done(&'a self, source: Option<&'static mut [u8]>, dest: &'static mut [u8]);
16}
17
18/// The number of bytes used for AES block operations.  Keys and IVs must have this length,
19/// and encryption/decryption inputs must be have a multiple of this length.
20pub const AES_BLOCK_SIZE: usize = 16;
21pub const AES128_KEY_SIZE: usize = 16;
22pub const AES192_KEY_SIZE: usize = 24;
23pub const AES256_KEY_SIZE: usize = 32;
24
25pub trait AESKeySize {
26    const LENGTH: usize;
27}
28
29pub struct AES128;
30impl AESKeySize for AES128 {
31    const LENGTH: usize = 16;
32}
33pub struct AES192;
34impl AESKeySize for AES192 {
35    const LENGTH: usize = 24;
36}
37
38pub struct AES256;
39impl AESKeySize for AES256 {
40    const LENGTH: usize = 32;
41}
42
43pub trait AES<'a, K: AESKeySize> {
44    /// Enable the AES hardware.
45    /// Must be called before any other methods
46    fn enable(&self);
47
48    /// Disable the AES hardware
49    fn disable(&self);
50
51    /// Set the client instance which will receive `crypt_done()` callbacks
52    fn set_client(&'a self, client: &'a dyn Client<'a>);
53
54    /// Set the encryption key.
55    /// Returns `INVAL` if length is not `AESKeySize::LENGTH`
56    fn set_key(&self, key: &[u8]) -> Result<(), ErrorCode>;
57
58    /// Set the IV (or initial counter).
59    /// Returns `INVAL` if length is not `AES_BLOCK_SIZE`
60    fn set_iv(&self, iv: &[u8]) -> Result<(), ErrorCode>;
61
62    /// Begin a new message (with the configured IV) when `crypt()` is
63    /// next called.  Multiple calls to `crypt()` may be made between
64    /// calls to `start_message()`, allowing the encryption context to
65    /// extend over non-contiguous extents of data.
66    ///
67    /// If an encryption operation is in progress, this method instead
68    /// has no effect.
69    fn start_message(&self);
70
71    /// Request an encryption/decryption
72    ///
73    /// If the source buffer is not `None`, the encryption input
74    /// will be that entire buffer.  Otherwise the destination buffer
75    /// at indices between `start_index` and `stop_index` will
76    /// provide the input, which will be overwritten.
77    ///
78    /// If `None` is returned, the client's `crypt_done` method will eventually
79    /// be called, and the portion of the data buffer between `start_index`
80    /// and `stop_index` will hold the result of the encryption/decryption.
81    ///
82    /// If `Some(result, source, dest)` is returned, `result` is the
83    /// error condition and `source` and `dest` are the buffers that
84    /// were passed to `crypt`.
85    ///
86    /// The indices `start_index` and `stop_index` must be valid
87    /// offsets in the destination buffer, and the length
88    /// `stop_index - start_index` must be a multiple of
89    /// `AES_BLOCK_SIZE`.  Otherwise, `Some(INVAL, ...)` will be
90    /// returned.
91    ///
92    /// If the source buffer is not `None`, its length must be
93    /// `stop_index - start_index`.  Otherwise, `Some(INVAL, ...)`
94    /// will be returned.
95    ///
96    /// If an encryption operation is already in progress,
97    /// `Some(BUSY, ...)` will be returned.
98    ///
99    /// For correct operation, the methods `set_key` and `set_iv` must have
100    /// previously been called to set the buffers containing the
101    /// key and the IV (or initial counter value), and a method `set_mode_*()`
102    /// must have been called to set the desired mode.  These settings persist
103    /// across calls to `crypt()`.
104    ///
105    fn crypt(
106        &self,
107        source: Option<&'static mut [u8]>,
108        dest: &'static mut [u8],
109        start_index: usize,
110        stop_index: usize,
111    ) -> Option<(
112        Result<(), ErrorCode>,
113        Option<&'static mut [u8]>,
114        &'static mut [u8],
115    )>;
116}
117
118pub trait AESCtr {
119    /// Call before `AES::crypt()` to perform AESCtr
120    fn set_mode_aesctr(&self, encrypting: bool) -> Result<(), ErrorCode>;
121}
122
123pub trait AESCBC {
124    /// Call before `AES::crypt()` to perform AESCBC
125    fn set_mode_aescbc(&self, encrypting: bool) -> Result<(), ErrorCode>;
126}
127
128pub trait AESECB {
129    /// Call before `AES::crypt()` to perform AESECB
130    fn set_mode_aesecb(&self, encrypting: bool) -> Result<(), ErrorCode>;
131}
132
133pub trait CCMClient {
134    /// `res` is Ok(()) if the encryption/decryption process succeeded. This
135    /// does not mean that the message has been verified in the case of
136    /// decryption.
137    /// If we are encrypting: `tag_is_valid` is `true` iff `res` is Ok(()).
138    /// If we are decrypting: `tag_is_valid` is `true` iff `res` is Ok(()) and the
139    /// message authentication tag is valid.
140    fn crypt_done(&self, buf: &'static mut [u8], res: Result<(), ErrorCode>, tag_is_valid: bool);
141}
142
143pub const CCM_NONCE_LENGTH: usize = 13;
144
145pub trait AESCCM<'a, K: AESKeySize> {
146    /// Set the client instance which will receive `crypt_done()` callbacks
147    fn set_client(&'a self, client: &'a dyn CCMClient);
148
149    /// Set the key to be used for CCM encryption
150    fn set_key(&self, key: &[u8]) -> Result<(), ErrorCode>;
151
152    /// Set the nonce (length NONCE_LENGTH) to be used for CCM encryption
153    fn set_nonce(&self, nonce: &[u8]) -> Result<(), ErrorCode>;
154
155    /// Try to begin the encryption/decryption process
156    fn crypt(
157        &self,
158        buf: &'static mut [u8],
159        a_off: usize,
160        m_off: usize,
161        m_len: usize,
162        mic_len: usize,
163        confidential: bool,
164        encrypting: bool,
165    ) -> Result<(), (ErrorCode, &'static mut [u8])>;
166}
167
168pub trait GCMClient {
169    /// `res` is Ok(()) if the encryption/decryption process succeeded. This
170    /// does not mean that the message has been verified in the case of
171    /// decryption.
172    /// If we are encrypting: `tag_is_valid` is `true` iff `res` is Ok(()).
173    /// If we are decrypting: `tag_is_valid` is `true` iff `res` is Ok(()) and the
174    /// message authentication tag is valid.
175    fn crypt_done(&self, buf: &'static mut [u8], res: Result<(), ErrorCode>, tag_is_valid: bool);
176}
177
178pub trait AESGCM<'a, K: AESKeySize> {
179    /// Set the client instance which will receive `crypt_done()` callbacks
180    fn set_client(&'a self, client: &'a dyn GCMClient);
181
182    /// Set the key to be used for GCM encryption
183    /// Returns `INVAL` if length is not `AESKeySize::LENGTH`
184    fn set_key(&self, key: &[u8]) -> Result<(), ErrorCode>;
185
186    /// Set the IV to be used for GCM encryption. The IV should be less
187    /// or equal to 12 bytes (96 bits) as recommened in NIST-800-38D.
188    /// Returns `INVAL` if length is greater then 12 bytes
189    fn set_iv(&self, nonce: &[u8]) -> Result<(), ErrorCode>;
190
191    /// Try to begin the encryption/decryption process
192    /// The possible ErrorCodes are:
193    ///     - `BUSY`: An operation is already in progress
194    ///     - `SIZE`: The offset and lengths don't fit inside the buffer
195    fn crypt(
196        &self,
197        buf: &'static mut [u8],
198        aad_offset: usize,
199        message_offset: usize,
200        message_len: usize,
201        tag_len: usize,
202        encrypting: bool,
203    ) -> Result<(), (ErrorCode, &'static mut [u8])>;
204}