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::{
23 Cipher, CipherHolder, CipherSet, FindKeyResult, KeyType, MutPtrByteSlice, key_to_cipher,
24};
25pub use fidl_fuchsia_fxfs::{
26 EmptyStruct, FscryptKeyIdentifier, FscryptKeyIdentifierAndNonce, ObjectType, WrappedKey,
27};
28
29pub use cipher::FSCRYPT_PADDING;
30pub const FXFS_KEY_SIZE: usize = 256 / 8;
31pub const FXFS_WRAPPED_KEY_SIZE: usize = FXFS_KEY_SIZE + 16;
32
33#[derive(Debug)]
36pub struct UnwrappedKey(Vec<u8>);
37impl UnwrappedKey {
38 pub fn new(key: Vec<u8>) -> Self {
39 UnwrappedKey(key)
40 }
41}
42impl std::ops::Deref for UnwrappedKey {
43 type Target = Vec<u8>;
44 fn deref(&self) -> &Self::Target {
45 &self.0
46 }
47}
48
49#[repr(transparent)]
51#[derive(Clone, Debug, PartialEq)]
52pub struct WrappedKeyBytes(pub [u8; FXFS_WRAPPED_KEY_SIZE]);
53impl Default for WrappedKeyBytes {
54 fn default() -> Self {
55 Self([0u8; FXFS_WRAPPED_KEY_SIZE])
56 }
57}
58impl TryFrom<Vec<u8>> for WrappedKeyBytes {
59 type Error = anyhow::Error;
60
61 fn try_from(buf: Vec<u8>) -> Result<Self, Self::Error> {
62 Ok(Self(buf.try_into().map_err(|_| anyhow!("wrapped key wrong length"))?))
63 }
64}
65impl From<[u8; FXFS_WRAPPED_KEY_SIZE]> for WrappedKeyBytes {
66 fn from(buf: [u8; FXFS_WRAPPED_KEY_SIZE]) -> Self {
67 Self(buf)
68 }
69}
70impl TypeFingerprint for WrappedKeyBytes {
71 fn fingerprint() -> String {
72 "WrappedKeyBytes".to_owned()
73 }
74}
75
76impl std::ops::Deref for WrappedKeyBytes {
77 type Target = [u8; FXFS_WRAPPED_KEY_SIZE];
78 fn deref(&self) -> &Self::Target {
79 &self.0
80 }
81}
82
83impl std::ops::DerefMut for WrappedKeyBytes {
84 fn deref_mut(&mut self) -> &mut Self::Target {
85 &mut self.0
86 }
87}
88
89impl Serialize for WrappedKeyBytes {
92 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
93 where
94 S: Serializer,
95 {
96 serializer.serialize_bytes(&self[..])
97 }
98}
99
100impl<'de> Deserialize<'de> for WrappedKeyBytes {
101 fn deserialize<D>(deserializer: D) -> Result<WrappedKeyBytes, D::Error>
102 where
103 D: Deserializer<'de>,
104 {
105 struct WrappedKeyVisitor;
106
107 impl<'d> Visitor<'d> for WrappedKeyVisitor {
108 type Value = WrappedKeyBytes;
109
110 fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
111 formatter.write_str("Expected wrapped keys to be 48 bytes")
112 }
113
114 fn visit_bytes<E>(self, bytes: &[u8]) -> Result<WrappedKeyBytes, E>
115 where
116 E: SerdeError,
117 {
118 self.visit_byte_buf(bytes.to_vec())
119 }
120
121 fn visit_byte_buf<E>(self, bytes: Vec<u8>) -> Result<WrappedKeyBytes, E>
122 where
123 E: SerdeError,
124 {
125 let orig_len = bytes.len();
126 let bytes: [u8; FXFS_WRAPPED_KEY_SIZE] =
127 bytes.try_into().map_err(|_| SerdeError::invalid_length(orig_len, &self))?;
128 Ok(WrappedKeyBytes::from(bytes))
129 }
130 }
131 deserializer.deserialize_byte_buf(WrappedKeyVisitor)
132 }
133}
134
135#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TypeFingerprint)]
137pub enum EncryptionKey {
138 LegacyFxfs(FxfsKey),
140 FscryptInoLblk32File {
146 key_identifier: [u8; 16],
147 },
148 FscryptInoLblk32Dir {
149 key_identifier: [u8; 16],
150 nonce: [u8; 16],
151 },
152 Fxfs(FxfsKey),
154}
155
156impl EncryptionKey {
157 pub fn wrapping_key_id(&self) -> Option<WrappingKeyId> {
158 match self {
159 EncryptionKey::LegacyFxfs(key) | EncryptionKey::Fxfs(key) => Some(key.wrapping_key_id),
160 EncryptionKey::FscryptInoLblk32File { key_identifier }
161 | EncryptionKey::FscryptInoLblk32Dir { key_identifier, .. } => Some(*key_identifier),
162 }
163 }
164}
165
166impl<'a> arbitrary::Arbitrary<'a> for EncryptionKey {
167 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
168 Ok(match u.int_in_range(0..=3)? {
169 0 => EncryptionKey::LegacyFxfs(u.arbitrary()?),
170 1 => EncryptionKey::FscryptInoLblk32File { key_identifier: u.arbitrary()? },
171 2 => EncryptionKey::FscryptInoLblk32Dir {
172 key_identifier: u.arbitrary()?,
173 nonce: u.arbitrary()?,
174 },
175 3 => EncryptionKey::Fxfs(u.arbitrary()?),
176 _ => unreachable!(),
177 })
178 }
179}
180
181impl From<EncryptionKey> for WrappedKey {
182 fn from(value: EncryptionKey) -> Self {
183 match value {
184 EncryptionKey::LegacyFxfs(key) | EncryptionKey::Fxfs(key) => {
185 WrappedKey::Fxfs(key.into())
186 }
187 EncryptionKey::FscryptInoLblk32File { key_identifier } => {
188 WrappedKey::FscryptInoLblk32File(FscryptKeyIdentifier { key_identifier })
189 }
190 EncryptionKey::FscryptInoLblk32Dir { key_identifier, nonce } => {
191 WrappedKey::FscryptInoLblk32Dir(FscryptKeyIdentifierAndNonce {
192 key_identifier,
193 nonce,
194 })
195 }
196 }
197 }
198}
199
200impl From<&EncryptionKey> for KeyType {
201 fn from(value: &EncryptionKey) -> Self {
202 match value {
203 EncryptionKey::LegacyFxfs(_) => KeyType::LegacyFxfs,
204 EncryptionKey::Fxfs(_) => KeyType::Fxfs,
205 EncryptionKey::FscryptInoLblk32File { .. } => KeyType::FscryptInoLblk32File,
206 EncryptionKey::FscryptInoLblk32Dir { .. } => KeyType::FscryptInoLblk32Dir,
207 }
208 }
209}
210
211impl TryFrom<WrappedKey> for EncryptionKey {
212 type Error = zx::Status;
213
214 fn try_from(value: WrappedKey) -> Result<Self, Self::Error> {
215 Ok(match value {
216 WrappedKey::Fxfs(fidl_fuchsia_fxfs::FxfsKey { wrapping_key_id, wrapped_key }) => {
217 EncryptionKey::Fxfs(FxfsKey { wrapping_key_id, key: WrappedKeyBytes(wrapped_key) })
218 }
219 WrappedKey::FscryptInoLblk32File(FscryptKeyIdentifier { key_identifier }) => {
220 EncryptionKey::FscryptInoLblk32File { key_identifier }
221 }
222 WrappedKey::FscryptInoLblk32Dir(FscryptKeyIdentifierAndNonce {
223 key_identifier,
224 nonce,
225 }) => EncryptionKey::FscryptInoLblk32Dir { key_identifier, nonce },
226 _ => return Err(zx::Status::NOT_SUPPORTED),
227 })
228 }
229}
230
231#[derive(Clone, Default, Debug, Serialize, Deserialize, TypeFingerprint, PartialEq)]
234pub struct FxfsKey {
235 pub wrapping_key_id: WrappingKeyId,
238 pub key: WrappedKeyBytes,
244}
245
246pub type WrappingKeyId = [u8; 16];
247
248impl From<FxfsKey> for fidl_fuchsia_fxfs::FxfsKey {
249 fn from(value: FxfsKey) -> Self {
250 fidl_fuchsia_fxfs::FxfsKey {
251 wrapping_key_id: value.wrapping_key_id,
252 wrapped_key: value.key.0,
253 }
254 }
255}
256
257impl<'a> arbitrary::Arbitrary<'a> for FxfsKey {
258 fn arbitrary(_u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
259 return Ok(FxfsKey::default());
261 }
262}
263
264pub struct StreamCipher(ChaCha20);
268
269impl StreamCipher {
270 pub fn new(key: &UnwrappedKey, offset: u64) -> Self {
271 let mut cipher = Self(ChaCha20::new(
272 &chacha20::Key::try_from(&key[..]).expect("Invalid StreamCipher key length"),
273 &[0; 12].into(),
274 ));
275 cipher.0.seek(offset);
276 cipher
277 }
278
279 pub fn encrypt(&mut self, buffer: &mut [u8]) {
280 fxfs_trace::duration!("StreamCipher::encrypt", "len" => buffer.len());
281 self.0.apply_keystream(buffer);
282 }
283
284 pub fn decrypt(&mut self, buffer: &mut [u8]) {
285 fxfs_trace::duration!("StreamCipher::decrypt", "len" => buffer.len());
286 self.0.apply_keystream(buffer);
287 }
288
289 pub fn offset(&self) -> u64 {
290 self.0.current_pos()
291 }
292}
293
294pub enum KeyPurpose {
297 Data,
299 Metadata,
301}
302
303impl TryFrom<fidl_fuchsia_fxfs::KeyPurpose> for KeyPurpose {
304 type Error = zx::Status;
305
306 fn try_from(purpose: fidl_fuchsia_fxfs::KeyPurpose) -> Result<Self, Self::Error> {
307 match purpose {
308 fidl_fuchsia_fxfs::KeyPurpose::Data => Ok(KeyPurpose::Data),
309 fidl_fuchsia_fxfs::KeyPurpose::Metadata => Ok(KeyPurpose::Metadata),
310 _ => Err(zx::Status::INVALID_ARGS),
311 }
312 }
313}
314
315pub enum WrappingKey {
318 Aes256GcmSiv([u8; 32]),
320 Fscrypt([u8; 64]),
322}
323impl From<[u8; 32]> for WrappingKey {
324 fn from(value: [u8; 32]) -> Self {
325 WrappingKey::Aes256GcmSiv(value)
326 }
327}
328impl From<[u8; 64]> for WrappingKey {
329 fn from(value: [u8; 64]) -> Self {
330 WrappingKey::Fscrypt(value)
331 }
332}
333
334#[async_trait]
342pub trait Crypt: Send + Sync {
343 async fn create_key(
348 &self,
349 owner: u64,
350 purpose: KeyPurpose,
351 ) -> Result<(FxfsKey, UnwrappedKey), zx::Status>;
352
353 async fn create_key_with_id(
358 &self,
359 owner: u64,
360 wrapping_key_id: WrappingKeyId,
361 object_type: ObjectType,
362 ) -> Result<(EncryptionKey, UnwrappedKey), zx::Status>;
363
364 async fn unwrap_key(
370 &self,
371 wrapped_key: &WrappedKey,
372 owner: u64,
373 ) -> Result<UnwrappedKey, zx::Status>;
374
375 async fn unwrap_keys(
380 &self,
381 keys: &[(u64, EncryptionKey)],
382 owner: u64,
383 ) -> Result<CipherSet, zx::Status> {
384 let futures: FuturesUnordered<_> = keys
385 .iter()
386 .map(|(key_id, key)| {
387 let key_id = *key_id;
388 let wrapped_key = WrappedKey::from(key.clone());
389 let owner = owner;
390 async move {
391 match self.unwrap_key(&wrapped_key, owner).await {
392 Ok(unwrapped_key) => cipher::key_to_cipher(key, &unwrapped_key)
393 .map(|c| (key_id, cipher::CipherHolder::Cipher(c))),
394 Err(zx::Status::UNAVAILABLE) => {
395 Ok((key_id, cipher::CipherHolder::Unavailable))
396 }
397 Err(e) => Err(e),
398 }
399 }
400 })
401 .collect();
402 let result = futures.try_collect::<BTreeMap<u64, _>>().await?;
403 Ok(result.into())
404 }
405}
406
407#[cfg(test)]
408mod tests {
409 use super::{StreamCipher, UnwrappedKey};
410
411 #[test]
412 fn test_stream_cipher_offset() {
413 let key = UnwrappedKey::new(vec![
414 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
415 25, 26, 27, 28, 29, 30, 31, 32,
416 ]);
417 let mut cipher1 = StreamCipher::new(&key, 0);
418 let mut p1 = [1, 2, 3, 4];
419 let mut c1 = p1.clone();
420 cipher1.encrypt(&mut c1);
421
422 let mut cipher2 = StreamCipher::new(&key, 1);
423 let p2 = [5, 6, 7, 8];
424 let mut c2 = p2.clone();
425 cipher2.encrypt(&mut c2);
426
427 let xor_fn = |buf1: &mut [u8], buf2| {
428 for (b1, b2) in buf1.iter_mut().zip(buf2) {
429 *b1 ^= b2;
430 }
431 };
432
433 xor_fn(&mut c1, &c2);
436 xor_fn(&mut p1, &p2);
437 assert_ne!(c1, p1);
438 }
439}