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 LegacyFxfs(FxfsKey),
138 FscryptInoLblk32File {
144 key_identifier: [u8; 16],
145 },
146 FscryptInoLblk32Dir {
147 key_identifier: [u8; 16],
148 nonce: [u8; 16],
149 },
150 Fxfs(FxfsKey),
152}
153
154impl<'a> arbitrary::Arbitrary<'a> for EncryptionKey {
155 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
156 Ok(match u.int_in_range(0..=3)? {
157 0 => EncryptionKey::LegacyFxfs(u.arbitrary()?),
158 1 => EncryptionKey::FscryptInoLblk32File { key_identifier: u.arbitrary()? },
159 2 => EncryptionKey::FscryptInoLblk32Dir {
160 key_identifier: u.arbitrary()?,
161 nonce: u.arbitrary()?,
162 },
163 3 => EncryptionKey::Fxfs(u.arbitrary()?),
164 _ => unreachable!(),
165 })
166 }
167}
168
169impl From<EncryptionKey> for WrappedKey {
170 fn from(value: EncryptionKey) -> Self {
171 match value {
172 EncryptionKey::LegacyFxfs(key) | EncryptionKey::Fxfs(key) => {
173 WrappedKey::Fxfs(key.into())
174 }
175 EncryptionKey::FscryptInoLblk32File { key_identifier } => {
176 WrappedKey::FscryptInoLblk32File(FscryptKeyIdentifier { key_identifier })
177 }
178 EncryptionKey::FscryptInoLblk32Dir { key_identifier, nonce } => {
179 WrappedKey::FscryptInoLblk32Dir(FscryptKeyIdentifierAndNonce {
180 key_identifier,
181 nonce,
182 })
183 }
184 }
185 }
186}
187
188impl From<&EncryptionKey> for KeyType {
189 fn from(value: &EncryptionKey) -> Self {
190 match value {
191 EncryptionKey::LegacyFxfs(_) => KeyType::LegacyFxfs,
192 EncryptionKey::Fxfs(_) => KeyType::Fxfs,
193 EncryptionKey::FscryptInoLblk32File { .. } => KeyType::FscryptInoLblk32File,
194 EncryptionKey::FscryptInoLblk32Dir { .. } => KeyType::FscryptInoLblk32Dir,
195 }
196 }
197}
198
199impl TryFrom<WrappedKey> for EncryptionKey {
200 type Error = zx::Status;
201
202 fn try_from(value: WrappedKey) -> Result<Self, Self::Error> {
203 Ok(match value {
204 WrappedKey::Fxfs(fidl_fuchsia_fxfs::FxfsKey { wrapping_key_id, wrapped_key }) => {
205 EncryptionKey::Fxfs(FxfsKey { wrapping_key_id, key: WrappedKeyBytes(wrapped_key) })
206 }
207 WrappedKey::FscryptInoLblk32File(FscryptKeyIdentifier { key_identifier }) => {
208 EncryptionKey::FscryptInoLblk32File { key_identifier }
209 }
210 WrappedKey::FscryptInoLblk32Dir(FscryptKeyIdentifierAndNonce {
211 key_identifier,
212 nonce,
213 }) => EncryptionKey::FscryptInoLblk32Dir { key_identifier, nonce },
214 _ => return Err(zx::Status::NOT_SUPPORTED),
215 })
216 }
217}
218
219#[derive(Clone, Default, Debug, Serialize, Deserialize, TypeFingerprint, PartialEq)]
222pub struct FxfsKey {
223 pub wrapping_key_id: WrappingKeyId,
226 pub key: WrappedKeyBytes,
232}
233
234pub type WrappingKeyId = [u8; 16];
235
236impl From<FxfsKey> for fidl_fuchsia_fxfs::FxfsKey {
237 fn from(value: FxfsKey) -> Self {
238 fidl_fuchsia_fxfs::FxfsKey {
239 wrapping_key_id: value.wrapping_key_id,
240 wrapped_key: value.key.0,
241 }
242 }
243}
244
245impl<'a> arbitrary::Arbitrary<'a> for FxfsKey {
246 fn arbitrary(_u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
247 return Ok(FxfsKey::default());
249 }
250}
251
252pub struct StreamCipher(ChaCha20);
256
257impl StreamCipher {
258 pub fn new(key: &UnwrappedKey, offset: u64) -> Self {
259 let mut cipher = Self(ChaCha20::new(
260 &chacha20::Key::try_from(&key[..]).expect("Invalid StreamCipher key length"),
261 &[0; 12].into(),
262 ));
263 cipher.0.seek(offset);
264 cipher
265 }
266
267 pub fn encrypt(&mut self, buffer: &mut [u8]) {
268 fxfs_trace::duration!("StreamCipher::encrypt", "len" => buffer.len());
269 self.0.apply_keystream(buffer);
270 }
271
272 pub fn decrypt(&mut self, buffer: &mut [u8]) {
273 fxfs_trace::duration!("StreamCipher::decrypt", "len" => buffer.len());
274 self.0.apply_keystream(buffer);
275 }
276
277 pub fn offset(&self) -> u64 {
278 self.0.current_pos()
279 }
280}
281
282pub enum KeyPurpose {
285 Data,
287 Metadata,
289}
290
291impl TryFrom<fidl_fuchsia_fxfs::KeyPurpose> for KeyPurpose {
292 type Error = zx::Status;
293
294 fn try_from(purpose: fidl_fuchsia_fxfs::KeyPurpose) -> Result<Self, Self::Error> {
295 match purpose {
296 fidl_fuchsia_fxfs::KeyPurpose::Data => Ok(KeyPurpose::Data),
297 fidl_fuchsia_fxfs::KeyPurpose::Metadata => Ok(KeyPurpose::Metadata),
298 _ => Err(zx::Status::INVALID_ARGS),
299 }
300 }
301}
302
303pub enum WrappingKey {
306 Aes256GcmSiv([u8; 32]),
308 Fscrypt([u8; 64]),
310}
311impl From<[u8; 32]> for WrappingKey {
312 fn from(value: [u8; 32]) -> Self {
313 WrappingKey::Aes256GcmSiv(value)
314 }
315}
316impl From<[u8; 64]> for WrappingKey {
317 fn from(value: [u8; 64]) -> Self {
318 WrappingKey::Fscrypt(value)
319 }
320}
321
322#[async_trait]
330pub trait Crypt: Send + Sync {
331 async fn create_key(
336 &self,
337 owner: u64,
338 purpose: KeyPurpose,
339 ) -> Result<(FxfsKey, UnwrappedKey), zx::Status>;
340
341 async fn create_key_with_id(
346 &self,
347 owner: u64,
348 wrapping_key_id: WrappingKeyId,
349 object_type: ObjectType,
350 ) -> Result<(EncryptionKey, UnwrappedKey), zx::Status>;
351
352 async fn unwrap_key(
358 &self,
359 wrapped_key: &WrappedKey,
360 owner: u64,
361 ) -> Result<UnwrappedKey, zx::Status>;
362
363 async fn unwrap_keys(
368 &self,
369 keys: &[(u64, EncryptionKey)],
370 owner: u64,
371 ) -> Result<CipherSet, zx::Status> {
372 let futures: FuturesUnordered<_> = keys
373 .iter()
374 .map(|(key_id, key)| {
375 let key_id = *key_id;
376 let wrapped_key = WrappedKey::from(key.clone());
377 let owner = owner;
378 async move {
379 match self.unwrap_key(&wrapped_key, owner).await {
380 Ok(unwrapped_key) => cipher::key_to_cipher(key, &unwrapped_key)
381 .map(|c| (key_id, cipher::CipherHolder::Cipher(c))),
382 Err(zx::Status::UNAVAILABLE) => {
383 Ok((key_id, cipher::CipherHolder::Unavailable))
384 }
385 Err(e) => Err(e),
386 }
387 }
388 })
389 .collect();
390 let result = futures.try_collect::<BTreeMap<u64, _>>().await?;
391 Ok(result.into())
392 }
393}
394
395#[cfg(test)]
396mod tests {
397 use super::{StreamCipher, UnwrappedKey};
398
399 #[test]
400 fn test_stream_cipher_offset() {
401 let key = UnwrappedKey::new(vec![
402 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
403 25, 26, 27, 28, 29, 30, 31, 32,
404 ]);
405 let mut cipher1 = StreamCipher::new(&key, 0);
406 let mut p1 = [1, 2, 3, 4];
407 let mut c1 = p1.clone();
408 cipher1.encrypt(&mut c1);
409
410 let mut cipher2 = StreamCipher::new(&key, 1);
411 let p2 = [5, 6, 7, 8];
412 let mut c2 = p2.clone();
413 cipher2.encrypt(&mut c2);
414
415 let xor_fn = |buf1: &mut [u8], buf2| {
416 for (b1, b2) in buf1.iter_mut().zip(buf2) {
417 *b1 ^= b2;
418 }
419 };
420
421 xor_fn(&mut c1, &c2);
424 xor_fn(&mut p1, &p2);
425 assert_ne!(c1, p1);
426 }
427}