1use aes::cipher::{KeyIvInit, StreamCipher as _, StreamCipherSeek};
6use anyhow::anyhow;
7use async_trait::async_trait;
8use chacha20::{self, ChaCha20};
9use fprint::TypeFingerprint;
10use futures::TryStreamExt as _;
11use futures::stream::FuturesUnordered;
12use serde::de::{Error as SerdeError, Visitor};
13use serde::{Deserialize, Deserializer, Serialize, Serializer};
14use std::collections::BTreeMap;
15use zx_status as zx;
16
17mod cipher;
18pub mod ff1;
19
20pub use cipher::fscrypt_ino_lblk32::FscryptSoftwareInoLblk32FileCipher;
21pub use cipher::fxfs::FxfsCipher;
22pub use cipher::{Cipher, CipherHolder, CipherSet, FindKeyResult, KeyType, key_to_cipher};
23pub use fidl_fuchsia_fxfs::{
24 EmptyStruct, FscryptKeyIdentifier, FscryptKeyIdentifierAndNonce, ObjectType, WrappedKey,
25};
26
27pub use cipher::FSCRYPT_PADDING;
28pub const FXFS_KEY_SIZE: usize = 256 / 8;
29pub const FXFS_WRAPPED_KEY_SIZE: usize = FXFS_KEY_SIZE + 16;
30
31#[derive(Debug)]
34pub struct UnwrappedKey(Vec<u8>);
35impl UnwrappedKey {
36 pub fn new(key: Vec<u8>) -> Self {
37 UnwrappedKey(key)
38 }
39}
40impl std::ops::Deref for UnwrappedKey {
41 type Target = Vec<u8>;
42 fn deref(&self) -> &Self::Target {
43 &self.0
44 }
45}
46
47#[repr(transparent)]
49#[derive(Clone, Debug, PartialEq)]
50pub struct WrappedKeyBytes(pub [u8; FXFS_WRAPPED_KEY_SIZE]);
51impl Default for WrappedKeyBytes {
52 fn default() -> Self {
53 Self([0u8; FXFS_WRAPPED_KEY_SIZE])
54 }
55}
56impl TryFrom<Vec<u8>> for WrappedKeyBytes {
57 type Error = anyhow::Error;
58
59 fn try_from(buf: Vec<u8>) -> Result<Self, Self::Error> {
60 Ok(Self(buf.try_into().map_err(|_| anyhow!("wrapped key wrong length"))?))
61 }
62}
63impl From<[u8; FXFS_WRAPPED_KEY_SIZE]> for WrappedKeyBytes {
64 fn from(buf: [u8; FXFS_WRAPPED_KEY_SIZE]) -> Self {
65 Self(buf)
66 }
67}
68impl TypeFingerprint for WrappedKeyBytes {
69 fn fingerprint() -> String {
70 "WrappedKeyBytes".to_owned()
71 }
72}
73
74impl std::ops::Deref for WrappedKeyBytes {
75 type Target = [u8; FXFS_WRAPPED_KEY_SIZE];
76 fn deref(&self) -> &Self::Target {
77 &self.0
78 }
79}
80
81impl std::ops::DerefMut for WrappedKeyBytes {
82 fn deref_mut(&mut self) -> &mut Self::Target {
83 &mut self.0
84 }
85}
86
87impl Serialize for WrappedKeyBytes {
90 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
91 where
92 S: Serializer,
93 {
94 serializer.serialize_bytes(&self[..])
95 }
96}
97
98impl<'de> Deserialize<'de> for WrappedKeyBytes {
99 fn deserialize<D>(deserializer: D) -> Result<WrappedKeyBytes, D::Error>
100 where
101 D: Deserializer<'de>,
102 {
103 struct WrappedKeyVisitor;
104
105 impl<'d> Visitor<'d> for WrappedKeyVisitor {
106 type Value = WrappedKeyBytes;
107
108 fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
109 formatter.write_str("Expected wrapped keys to be 48 bytes")
110 }
111
112 fn visit_bytes<E>(self, bytes: &[u8]) -> Result<WrappedKeyBytes, E>
113 where
114 E: SerdeError,
115 {
116 self.visit_byte_buf(bytes.to_vec())
117 }
118
119 fn visit_byte_buf<E>(self, bytes: Vec<u8>) -> Result<WrappedKeyBytes, E>
120 where
121 E: SerdeError,
122 {
123 let orig_len = bytes.len();
124 let bytes: [u8; FXFS_WRAPPED_KEY_SIZE] =
125 bytes.try_into().map_err(|_| SerdeError::invalid_length(orig_len, &self))?;
126 Ok(WrappedKeyBytes::from(bytes))
127 }
128 }
129 deserializer.deserialize_byte_buf(WrappedKeyVisitor)
130 }
131}
132
133#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TypeFingerprint)]
135pub enum EncryptionKey {
136 Fxfs(FxfsKey),
137 FscryptInoLblk32File { key_identifier: [u8; 16] },
143 FscryptInoLblk32Dir { key_identifier: [u8; 16], nonce: [u8; 16] },
144}
145
146impl<'a> arbitrary::Arbitrary<'a> for EncryptionKey {
147 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
148 Ok(match u.int_in_range(0..=2)? {
149 0 => EncryptionKey::Fxfs(u.arbitrary()?),
150 1 => EncryptionKey::FscryptInoLblk32File { key_identifier: u.arbitrary()? },
151 2 => EncryptionKey::FscryptInoLblk32Dir {
152 key_identifier: u.arbitrary()?,
153 nonce: u.arbitrary()?,
154 },
155 _ => unreachable!(),
156 })
157 }
158}
159
160impl From<EncryptionKey> for WrappedKey {
161 fn from(value: EncryptionKey) -> Self {
162 match value {
163 EncryptionKey::Fxfs(key) => WrappedKey::Fxfs(key.into()),
164 EncryptionKey::FscryptInoLblk32File { key_identifier } => {
165 WrappedKey::FscryptInoLblk32File(FscryptKeyIdentifier { key_identifier })
166 }
167 EncryptionKey::FscryptInoLblk32Dir { key_identifier, nonce } => {
168 WrappedKey::FscryptInoLblk32Dir(FscryptKeyIdentifierAndNonce {
169 key_identifier,
170 nonce,
171 })
172 }
173 }
174 }
175}
176
177impl TryFrom<WrappedKey> for EncryptionKey {
178 type Error = zx::Status;
179
180 fn try_from(value: WrappedKey) -> Result<Self, Self::Error> {
181 Ok(match value {
182 WrappedKey::Fxfs(fidl_fuchsia_fxfs::FxfsKey { wrapping_key_id, wrapped_key }) => {
183 EncryptionKey::Fxfs(FxfsKey { wrapping_key_id, key: WrappedKeyBytes(wrapped_key) })
184 }
185 WrappedKey::FscryptInoLblk32File(FscryptKeyIdentifier { key_identifier }) => {
186 EncryptionKey::FscryptInoLblk32File { key_identifier }
187 }
188 WrappedKey::FscryptInoLblk32Dir(FscryptKeyIdentifierAndNonce {
189 key_identifier,
190 nonce,
191 }) => EncryptionKey::FscryptInoLblk32Dir { key_identifier, nonce },
192 _ => return Err(zx::Status::NOT_SUPPORTED),
193 })
194 }
195}
196
197#[derive(Clone, Default, Debug, Serialize, Deserialize, TypeFingerprint, PartialEq)]
200pub struct FxfsKey {
201 pub wrapping_key_id: WrappingKeyId,
204 pub key: WrappedKeyBytes,
210}
211
212pub type WrappingKeyId = [u8; 16];
213
214impl From<FxfsKey> for fidl_fuchsia_fxfs::FxfsKey {
215 fn from(value: FxfsKey) -> Self {
216 fidl_fuchsia_fxfs::FxfsKey {
217 wrapping_key_id: value.wrapping_key_id,
218 wrapped_key: value.key.0,
219 }
220 }
221}
222
223impl<'a> arbitrary::Arbitrary<'a> for FxfsKey {
224 fn arbitrary(_u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
225 return Ok(FxfsKey::default());
227 }
228}
229
230pub struct StreamCipher(ChaCha20);
234
235impl StreamCipher {
236 pub fn new(key: &UnwrappedKey, offset: u64) -> Self {
237 let mut cipher =
238 Self(ChaCha20::new(chacha20::Key::from_slice(key), &[0; 12].into()));
239 cipher.0.seek(offset);
240 cipher
241 }
242
243 pub fn encrypt(&mut self, buffer: &mut [u8]) {
244 fxfs_trace::duration!("StreamCipher::encrypt", "len" => buffer.len());
245 self.0.apply_keystream(buffer);
246 }
247
248 pub fn decrypt(&mut self, buffer: &mut [u8]) {
249 fxfs_trace::duration!("StreamCipher::decrypt", "len" => buffer.len());
250 self.0.apply_keystream(buffer);
251 }
252
253 pub fn offset(&self) -> u64 {
254 self.0.current_pos()
255 }
256}
257
258pub enum KeyPurpose {
261 Data,
263 Metadata,
265}
266
267impl TryFrom<fidl_fuchsia_fxfs::KeyPurpose> for KeyPurpose {
268 type Error = zx::Status;
269
270 fn try_from(purpose: fidl_fuchsia_fxfs::KeyPurpose) -> Result<Self, Self::Error> {
271 match purpose {
272 fidl_fuchsia_fxfs::KeyPurpose::Data => Ok(KeyPurpose::Data),
273 fidl_fuchsia_fxfs::KeyPurpose::Metadata => Ok(KeyPurpose::Metadata),
274 _ => Err(zx::Status::INVALID_ARGS),
275 }
276 }
277}
278
279pub enum WrappingKey {
282 Aes256GcmSiv([u8; 32]),
284 Fscrypt([u8; 64]),
286}
287impl From<[u8; 32]> for WrappingKey {
288 fn from(value: [u8; 32]) -> Self {
289 WrappingKey::Aes256GcmSiv(value)
290 }
291}
292impl From<[u8; 64]> for WrappingKey {
293 fn from(value: [u8; 64]) -> Self {
294 WrappingKey::Fscrypt(value)
295 }
296}
297
298#[async_trait]
306pub trait Crypt: Send + Sync {
307 async fn create_key(
312 &self,
313 owner: u64,
314 purpose: KeyPurpose,
315 ) -> Result<(FxfsKey, UnwrappedKey), zx::Status>;
316
317 async fn create_key_with_id(
322 &self,
323 owner: u64,
324 wrapping_key_id: WrappingKeyId,
325 object_type: ObjectType,
326 ) -> Result<(EncryptionKey, UnwrappedKey), zx::Status>;
327
328 async fn unwrap_key(
334 &self,
335 wrapped_key: &WrappedKey,
336 owner: u64,
337 ) -> Result<UnwrappedKey, zx::Status>;
338
339 async fn unwrap_keys(
344 &self,
345 keys: &BTreeMap<u64, WrappedKey>,
346 owner: u64,
347 ) -> Result<CipherSet, zx::Status> {
348 let futures: FuturesUnordered<_> = keys
349 .iter()
350 .map(|(key_id, key)| {
351 let key_id = *key_id;
352 let owner = owner;
353 async move {
354 match self.unwrap_key(&key, owner).await {
355 Ok(unwrapped_key) => cipher::key_to_cipher(key, &unwrapped_key)
356 .map(|c| (key_id, cipher::CipherHolder::Cipher(c))),
357 Err(zx::Status::UNAVAILABLE) => {
358 Ok((key_id, cipher::CipherHolder::Unavailable))
359 }
360 Err(e) => Err(e),
361 }
362 }
363 })
364 .collect();
365 let result = futures.try_collect::<BTreeMap<u64, _>>().await?;
366 Ok(result.into())
367 }
368}
369
370#[cfg(test)]
371mod tests {
372 use super::{StreamCipher, UnwrappedKey};
373
374 #[test]
375 fn test_stream_cipher_offset() {
376 let key = UnwrappedKey::new(vec![
377 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
378 25, 26, 27, 28, 29, 30, 31, 32,
379 ]);
380 let mut cipher1 = StreamCipher::new(&key, 0);
381 let mut p1 = [1, 2, 3, 4];
382 let mut c1 = p1.clone();
383 cipher1.encrypt(&mut c1);
384
385 let mut cipher2 = StreamCipher::new(&key, 1);
386 let p2 = [5, 6, 7, 8];
387 let mut c2 = p2.clone();
388 cipher2.encrypt(&mut c2);
389
390 let xor_fn = |buf1: &mut [u8], buf2| {
391 for (b1, b2) in buf1.iter_mut().zip(buf2) {
392 *b1 ^= b2;
393 }
394 };
395
396 xor_fn(&mut c1, &c2);
399 xor_fn(&mut p1, &p2);
400 assert_ne!(c1, p1);
401 }
402}