1pub mod error;
5pub mod messages;
6pub mod sha2;
7
8pub use messages::AesMode;
9use server::{xous::MemoryRange, CheckedConn, CheckedPermissions, MessageAllowed};
10#[cfg(keyos)]
11use server::{ScalarEventHandler, ServerContext};
12pub use sha2::{
13 Sha256StreamingContext, ShaAlgo, ShaPermissions, ShaStreamingContext, SHA224_HASH_SIZE, SHA256_HASH_SIZE,
14 SHA384_HASH_SIZE, SHA512_HASH_SIZE,
15};
16
17use crate::error::{CryptoError, ShamirError};
18use crate::messages::*;
19
20pub const AES_BLOCK_SIZE: usize = 16;
21
22#[macro_export]
23macro_rules! use_api {
24 () => {
25 mod crypto_permissions {
26 use crypto::messages::*;
27 #[derive(Clone, Default, server::Permissions)]
28 #[server_name = "os/crypto"]
29 pub struct CryptoPermissions;
30 }
31 type CryptoApi = crypto::CryptoApi<crypto_permissions::CryptoPermissions>;
32 };
33}
34
35#[derive(Default)]
36pub struct CryptoApi<P: CheckedPermissions> {
37 pub(crate) conn: CheckedConn<P>,
38}
39
40pub struct AesContext<P: CheckedPermissions + MessageAllowed<AesClear>> {
41 conn: CheckedConn<P>,
42 id: u8,
43}
44
45#[derive(Debug, Clone, Copy, PartialEq, Eq, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
46pub enum Direction {
47 Encrypt,
48 Decrypt,
49}
50
51impl<P: CheckedPermissions> CryptoApi<P> {
52 pub fn setup_aes(&self, key: &[u8], mode: AesMode) -> Result<AesContext<P>, CryptoError>
53 where
54 P: MessageAllowed<AesSetup>,
55 P: MessageAllowed<AesClear>,
56 {
57 let result = self.conn.send_blocking_archive(AesSetup { key: key.into(), mode });
58 Ok(AesContext { id: result? as u8, conn: self.conn.clone() })
59 }
60
61 #[cfg(keyos)]
74 pub unsafe fn disk_encrypt_unsafe(
75 &self,
76 tweak: [u8; 16],
77 j: usize,
78 src: MemoryRange,
79 dst: MemoryRange,
80 direction: Direction,
81 ) -> Result<(), CryptoError>
82 where
83 P: MessageAllowed<DiskEncryptUnsafe>,
84 {
85 self.conn.send_blocking_archive(DiskEncryptUnsafe {
86 tweak,
87 j,
88 src: src.as_ptr() as usize,
89 dst: dst.as_ptr() as usize,
90 len: src.len().min(dst.len()),
91 direction,
92 })
93 }
94
95 #[cfg(keyos)]
97 pub fn subscribe_disk_encrypt_complete<SR>(
98 &self,
99 context: &mut ServerContext<SR>,
100 ) -> Result<(), CryptoError>
101 where
102 P: MessageAllowed<SubscribeDiskEncryptComplete>,
103 SR: ScalarEventHandler<DiskEncryptComplete>,
104 {
105 self.conn.subscribe_scalar(SubscribeDiskEncryptComplete, context)
106 }
107
108 pub fn hmac224(&self, key: Vec<u8>, data: Vec<u8>) -> Result<Vec<u8>, CryptoError>
109 where
110 P: MessageAllowed<Hmac>,
111 {
112 self.conn.send_blocking_archive(Hmac { algo: ShaAlgo::Sha224, key, data })
113 }
114
115 pub fn hmac256(&self, key: Vec<u8>, data: Vec<u8>) -> Result<Vec<u8>, CryptoError>
116 where
117 P: MessageAllowed<Hmac>,
118 {
119 self.conn.send_blocking_archive(Hmac { algo: ShaAlgo::Sha256, key, data })
120 }
121
122 pub fn hmac384(&self, key: Vec<u8>, data: Vec<u8>) -> Result<Vec<u8>, CryptoError>
123 where
124 P: MessageAllowed<Hmac>,
125 {
126 self.conn.send_blocking_archive(Hmac { algo: ShaAlgo::Sha384, key, data })
127 }
128
129 pub fn hmac512(&self, key: Vec<u8>, data: Vec<u8>) -> Result<Vec<u8>, CryptoError>
130 where
131 P: MessageAllowed<Hmac>,
132 {
133 self.conn.send_blocking_archive(Hmac { algo: ShaAlgo::Sha512, key, data })
134 }
135
136 pub fn split_secret(
137 &self,
138 secret: Vec<u8>,
139 num_shares: usize,
140 threshold: usize,
141 ) -> Result<Vec<Vec<u8>>, ShamirError>
142 where
143 P: MessageAllowed<ShamirSplit>,
144 {
145 self.conn.send_blocking_archive(ShamirSplit { secret, num_shares, threshold })
146 }
147
148 pub fn recover_secret(&self, indexes: Vec<usize>, shares: Vec<Vec<u8>>) -> Result<Vec<u8>, ShamirError>
149 where
150 P: MessageAllowed<ShamirRecover>,
151 {
152 self.conn.send_blocking_archive(ShamirRecover { indexes, shares })
153 }
154}
155
156impl<P: CheckedPermissions + MessageAllowed<AesClear>> AesContext<P> {
157 pub fn execute(
158 &self,
159 buf: MemoryRange,
160 offset: usize,
161 len: usize,
162 direction: Direction,
163 ) -> Result<usize, CryptoError>
164 where
165 P: MessageAllowed<AesExecute>,
166 {
167 self.conn.lend_mut(AesExecute { buf, transfer_id: self.id, len, direction, offset })
168 }
169
170 pub fn add_aad(&self, aad: &[u8]) -> Result<usize, CryptoError>
171 where
172 P: MessageAllowed<AesAad>,
173 {
174 self.conn.send_blocking_archive(AesAad { transfer_id: self.id, aad: aad.into() })
175 }
176
177 pub fn gcm_tag(&self) -> Result<[u8; 16], CryptoError>
178 where
179 P: MessageAllowed<AesGcmTag>,
180 {
181 self.conn.send_blocking_archive(AesGcmTag { transfer_id: self.id })
182 }
183}
184
185impl<P: CheckedPermissions + MessageAllowed<AesClear>> Drop for AesContext<P> {
186 fn drop(&mut self) { self.conn.try_send_scalar(AesClear(self.id)).ok(); }
187}