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