1use anyhow::anyhow;
6use async_trait::async_trait;
7use chacha20::cipher::{KeyIvInit, StreamCipher as _, StreamCipherSeek};
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 = Self(ChaCha20::new(
238 &chacha20::Key::try_from(&key[..]).expect("Invalid StreamCipher key length"),
239 &[0; 12].into(),
240 ));
241 cipher.0.seek(offset);
242 cipher
243 }
244
245 pub fn encrypt(&mut self, buffer: &mut [u8]) {
246 fxfs_trace::duration!("StreamCipher::encrypt", "len" => buffer.len());
247 self.0.apply_keystream(buffer);
248 }
249
250 pub fn decrypt(&mut self, buffer: &mut [u8]) {
251 fxfs_trace::duration!("StreamCipher::decrypt", "len" => buffer.len());
252 self.0.apply_keystream(buffer);
253 }
254
255 pub fn offset(&self) -> u64 {
256 self.0.current_pos()
257 }
258}
259
260pub enum KeyPurpose {
263 Data,
265 Metadata,
267}
268
269impl TryFrom<fidl_fuchsia_fxfs::KeyPurpose> for KeyPurpose {
270 type Error = zx::Status;
271
272 fn try_from(purpose: fidl_fuchsia_fxfs::KeyPurpose) -> Result<Self, Self::Error> {
273 match purpose {
274 fidl_fuchsia_fxfs::KeyPurpose::Data => Ok(KeyPurpose::Data),
275 fidl_fuchsia_fxfs::KeyPurpose::Metadata => Ok(KeyPurpose::Metadata),
276 _ => Err(zx::Status::INVALID_ARGS),
277 }
278 }
279}
280
281pub enum WrappingKey {
284 Aes256GcmSiv([u8; 32]),
286 Fscrypt([u8; 64]),
288}
289impl From<[u8; 32]> for WrappingKey {
290 fn from(value: [u8; 32]) -> Self {
291 WrappingKey::Aes256GcmSiv(value)
292 }
293}
294impl From<[u8; 64]> for WrappingKey {
295 fn from(value: [u8; 64]) -> Self {
296 WrappingKey::Fscrypt(value)
297 }
298}
299
300#[async_trait]
308pub trait Crypt: Send + Sync {
309 async fn create_key(
314 &self,
315 owner: u64,
316 purpose: KeyPurpose,
317 ) -> Result<(FxfsKey, UnwrappedKey), zx::Status>;
318
319 async fn create_key_with_id(
324 &self,
325 owner: u64,
326 wrapping_key_id: WrappingKeyId,
327 object_type: ObjectType,
328 ) -> Result<(EncryptionKey, UnwrappedKey), zx::Status>;
329
330 async fn unwrap_key(
336 &self,
337 wrapped_key: &WrappedKey,
338 owner: u64,
339 ) -> Result<UnwrappedKey, zx::Status>;
340
341 async fn unwrap_keys(
346 &self,
347 keys: &BTreeMap<u64, WrappedKey>,
348 owner: u64,
349 ) -> Result<CipherSet, zx::Status> {
350 let futures: FuturesUnordered<_> = keys
351 .iter()
352 .map(|(key_id, key)| {
353 let key_id = *key_id;
354 let owner = owner;
355 async move {
356 match self.unwrap_key(&key, owner).await {
357 Ok(unwrapped_key) => cipher::key_to_cipher(key, &unwrapped_key)
358 .map(|c| (key_id, cipher::CipherHolder::Cipher(c))),
359 Err(zx::Status::UNAVAILABLE) => {
360 Ok((key_id, cipher::CipherHolder::Unavailable))
361 }
362 Err(e) => Err(e),
363 }
364 }
365 })
366 .collect();
367 let result = futures.try_collect::<BTreeMap<u64, _>>().await?;
368 Ok(result.into())
369 }
370}
371
372#[cfg(test)]
373mod tests {
374 use super::{StreamCipher, UnwrappedKey};
375
376 #[test]
377 fn test_stream_cipher_offset() {
378 let key = UnwrappedKey::new(vec![
379 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
380 25, 26, 27, 28, 29, 30, 31, 32,
381 ]);
382 let mut cipher1 = StreamCipher::new(&key, 0);
383 let mut p1 = [1, 2, 3, 4];
384 let mut c1 = p1.clone();
385 cipher1.encrypt(&mut c1);
386
387 let mut cipher2 = StreamCipher::new(&key, 1);
388 let p2 = [5, 6, 7, 8];
389 let mut c2 = p2.clone();
390 cipher2.encrypt(&mut c2);
391
392 let xor_fn = |buf1: &mut [u8], buf2| {
393 for (b1, b2) in buf1.iter_mut().zip(buf2) {
394 *b1 ^= b2;
395 }
396 };
397
398 xor_fn(&mut c1, &c2);
401 xor_fn(&mut p1, &p2);
402 assert_ne!(c1, p1);
403 }
404}