crypto/
messages.rs

1// SPDX-FileCopyrightText: 2024 Foundation Devices, Inc. <hello@foundation.xyz>
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4use server::{xous::MemoryRange, SimpleMemoryMessage};
5use zeroize::{Zeroize, ZeroizeOnDrop};
6
7use crate::error::{CryptoError, ShamirError};
8use crate::Direction;
9
10#[derive(
11    Debug, Clone, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize, Zeroize, ZeroizeOnDrop,
12)]
13#[response(Result<usize, CryptoError>)]
14pub struct AesSetup {
15    pub key: Vec<u8>,
16    pub mode: AesMode,
17}
18
19#[derive(Debug, Clone, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize, Zeroize, ZeroizeOnDrop)]
20pub enum AesMode {
21    Ecb,
22    Cbc { iv: [u8; 16] },
23    Ctr { iv: [u8; 16] },
24    Gcm { iv: [u8; 12] },
25}
26
27#[derive(Debug, server::Message)]
28#[response(Result<usize, CryptoError>)]
29pub struct AesExecute {
30    pub buf: MemoryRange,
31    pub transfer_id: u8,
32    pub direction: Direction,
33    pub offset: usize,
34    pub len: usize,
35}
36
37const OFFSET_OFFSET: usize = 9;
38const TRANSFER_ID_OFFSET: usize = 1;
39const DECRYPT_FLAG: usize = 1;
40
41impl From<AesExecute> for SimpleMemoryMessage {
42    fn from(value: AesExecute) -> Self {
43        Self {
44            buf: value.buf,
45            arg1: value.len,
46            arg2: (value.offset << OFFSET_OFFSET)
47                | ((value.transfer_id as usize) << TRANSFER_ID_OFFSET)
48                | match value.direction {
49                    Direction::Encrypt => 0,
50                    Direction::Decrypt => DECRYPT_FLAG,
51                },
52        }
53    }
54}
55
56impl From<SimpleMemoryMessage> for AesExecute {
57    fn from(value: SimpleMemoryMessage) -> Self {
58        Self {
59            buf: value.buf,
60            len: value.arg1,
61            transfer_id: (value.arg2 >> TRANSFER_ID_OFFSET) as u8,
62            direction: if value.arg2 & DECRYPT_FLAG != 0 { Direction::Decrypt } else { Direction::Encrypt },
63            offset: (value.arg2 >> OFFSET_OFFSET),
64        }
65    }
66}
67
68#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
69#[response(Result<usize, CryptoError>)]
70pub struct AesAad {
71    pub transfer_id: u8,
72    pub aad: Vec<u8>,
73}
74
75#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
76#[response(Result<[u8;16], CryptoError>)]
77pub struct AesGcmTag {
78    pub transfer_id: u8,
79}
80
81#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
82#[response(Result<(), CryptoError>)]
83pub struct DiskEncryptUnsafe {
84    pub tweak: [u8; 16],
85    pub j: usize,
86    pub src: usize,
87    pub dst: usize,
88    pub len: usize,
89    pub direction: Direction,
90}
91
92#[cfg(keyos)]
93#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
94#[event(DiskEncryptComplete)]
95#[error(CryptoError)]
96pub struct SubscribeDiskEncryptComplete;
97
98/// Fired when a previously-accepted `DiskEncryptUnsafe` finishes.
99/// No strut body, because Pre-DMA failures are reported synchronously and
100/// DMA cannot fail without taking down the system.
101#[cfg(keyos)]
102#[derive(Debug, Clone, Copy)]
103pub struct DiskEncryptComplete;
104
105#[cfg(keyos)]
106impl server::AsScalar<1> for DiskEncryptComplete {
107    fn as_scalar(&self) -> [u32; 1] { [0] }
108}
109
110#[cfg(keyos)]
111impl server::FromScalar<1> for DiskEncryptComplete {
112    fn from_scalar(_: [u32; 1]) -> Self { Self }
113}
114
115#[derive(Debug, server::Message)]
116pub struct AesClear(pub u8);
117
118pub use crate::sha2::ShaAlgo;
119
120/// Allocate a server-side SHA context slot (or overwrite an existing one) and seed it
121/// with the supplied hash state. `context_id = None` on first use; the server allocates
122/// a slot and returns its id. Subsequent calls with the returned id overwrite the state.
123#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
124#[response(Result<usize, CryptoError>)]
125pub struct ShaSetContext {
126    /// `None` → allocate a new slot; `Some(id)` → overwrite existing slot.
127    pub context_id: Option<usize>,
128    pub algo: ShaAlgo,
129    /// Intermediate hash state in standard digest byte order (BE per word).
130    /// SHA-224/256 use the first 32 bytes; SHA-384/512 use all 64.
131    pub hash_state: [u8; 64],
132}
133
134/// Feed a block-aligned chunk of data into the hardware SHA engine via DMA.
135/// `buf` must be page-aligned; `length` must be a multiple of the algo's block size.
136/// Data always starts at offset 0 in `buf`.
137#[derive(Debug, server::Message)]
138#[response(Result<usize, CryptoError>)]
139pub struct ShaUpdate {
140    pub context_id: usize,
141    pub buf: MemoryRange,
142    pub length: usize,
143}
144
145impl From<ShaUpdate> for SimpleMemoryMessage {
146    fn from(value: ShaUpdate) -> Self { Self { buf: value.buf, arg1: value.context_id, arg2: value.length } }
147}
148
149impl From<SimpleMemoryMessage> for ShaUpdate {
150    fn from(value: SimpleMemoryMessage) -> Self {
151        Self { context_id: value.arg1, buf: value.buf, length: value.arg2 }
152    }
153}
154
155/// Retrieve the current intermediate hash state for a context slot.
156#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
157#[response(Result<ShaContextSnapshot, CryptoError>)]
158pub struct ShaGetContext {
159    pub context_id: usize,
160}
161
162/// Snapshot of a server-side SHA context (returned by `ShaGetContext`).
163#[derive(Debug, Clone, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
164pub struct ShaContextSnapshot {
165    pub algo: ShaAlgo,
166    pub hash_state: [u8; 64],
167}
168
169/// Release a server-side SHA context slot.
170#[derive(Debug, server::Message)]
171pub struct ShaDrop(pub usize);
172
173#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
174#[response(Result<Vec<u8>, CryptoError>)]
175pub struct Hmac {
176    pub algo: ShaAlgo,
177    pub key: Vec<u8>,
178    pub data: Vec<u8>,
179}
180
181#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
182#[response(Result<Vec<Vec<u8>>, ShamirError>)]
183pub struct ShamirSplit {
184    pub secret: Vec<u8>,
185    pub num_shares: usize,
186    pub threshold: usize,
187}
188
189#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
190#[response(Result<Vec<u8>, ShamirError>)]
191pub struct ShamirRecover {
192    pub indexes: Vec<usize>,
193    pub shares: Vec<Vec<u8>>,
194}