1use aes_gcm_siv::aead::Aead;
6use aes_gcm_siv::{Aes256GcmSiv, Key, KeyInit as _, Nonce};
7use async_trait::async_trait;
8use fuchsia_sync::Mutex;
9use fxfs_crypto::{
10 Crypt, EncryptionKey, FscryptKeyIdentifierAndNonce, KeyPurpose, ObjectType, UnwrappedKey,
11 WrappedKey, WrappingKeyId,
12};
13use rand::rngs::StdRng;
14use rand::{RngCore, SeedableRng};
15use std::collections::hash_map::{Entry, HashMap};
16use std::sync::atomic::{AtomicBool, Ordering};
17use zx_status as zx;
18
19fn zero_extended_nonce(val: u64) -> Nonce {
20 let mut nonce = Nonce::default();
21 nonce.as_mut_slice()[..8].copy_from_slice(&val.to_le_bytes());
22 nonce
23}
24
25struct Cipher {
26 aes_gcm_siv: Aes256GcmSiv,
28 wrapping_key: [u8; 32],
30}
31
32impl Cipher {
33 fn new(wrapping_key: [u8; 32]) -> Self {
34 Self {
35 aes_gcm_siv: Aes256GcmSiv::new(Key::<Aes256GcmSiv>::from_slice(&wrapping_key)),
36 wrapping_key,
37 }
38 }
39
40 fn encrypt(&self, nonce: &Nonce, plaintext: &[u8]) -> Result<Vec<u8>, zx::Status> {
41 self.aes_gcm_siv.encrypt(nonce, plaintext).map_err(|_e| zx::Status::INTERNAL)
42 }
43
44 fn decrypt(&self, nonce: &Nonce, ciphertext: &[u8]) -> Result<Vec<u8>, zx::Status> {
45 self.aes_gcm_siv.decrypt(nonce, ciphertext).map_err(|_e| zx::Status::INTERNAL)
46 }
47}
48
49struct CryptBaseInner {
50 ciphers: HashMap<WrappingKeyId, Cipher>,
51 active_data_key: Option<WrappingKeyId>,
52 active_metadata_key: Option<WrappingKeyId>,
53}
54
55pub struct CryptBase {
57 inner: Mutex<CryptBaseInner>,
58 shutdown: AtomicBool,
59 filesystem_uuid: [u8; 16],
62}
63
64impl CryptBase {
65 pub fn new() -> Self {
66 Self {
67 inner: Mutex::new(CryptBaseInner {
68 ciphers: HashMap::new(),
69 active_data_key: None,
70 active_metadata_key: None,
71 }),
72 shutdown: AtomicBool::new(false),
73 filesystem_uuid: [0; 16],
74 }
75 }
76
77 pub fn add_wrapping_key(&self, id: WrappingKeyId, key: [u8; 32]) -> Result<(), zx::Status> {
78 let mut inner = self.inner.lock();
79 match inner.ciphers.entry(id) {
80 Entry::Occupied(_) => Err(zx::Status::ALREADY_EXISTS),
81 Entry::Vacant(v) => {
82 v.insert(Cipher::new(key));
83 Ok(())
84 }
85 }
86 }
87
88 pub fn set_active_key(&self, purpose: KeyPurpose, id: WrappingKeyId) -> Result<(), zx::Status> {
89 let mut inner = self.inner.lock();
90 if !inner.ciphers.contains_key(&id) {
91 return Err(zx::Status::NOT_FOUND);
92 }
93 match purpose {
94 KeyPurpose::Data => inner.active_data_key = Some(id),
95 KeyPurpose::Metadata => inner.active_metadata_key = Some(id),
96 }
97 Ok(())
98 }
99
100 pub fn forget_wrapping_key(&self, id: &WrappingKeyId) -> Result<(), zx::Status> {
101 let mut inner = self.inner.lock();
102 if let Some(active_id) = inner.active_data_key {
103 if active_id == *id {
104 return Err(zx::Status::INVALID_ARGS);
105 }
106 }
107 if let Some(active_id) = inner.active_metadata_key {
108 if active_id == *id {
109 return Err(zx::Status::INVALID_ARGS);
110 }
111 }
112 inner.ciphers.remove(id);
113 Ok(())
114 }
115
116 pub fn shutdown(&self) {
117 self.shutdown.store(true, Ordering::Relaxed);
118 }
119
120 pub fn set_filesystem_uuid(&mut self, uuid: &[u8; 16]) {
124 self.filesystem_uuid = *uuid;
125 }
126}
127
128#[async_trait]
129impl Crypt for CryptBase {
130 async fn create_key(
131 &self,
132 owner: u64,
133 purpose: KeyPurpose,
134 ) -> Result<(fxfs_crypto::FxfsKey, UnwrappedKey), zx::Status> {
135 if self.shutdown.load(Ordering::Relaxed) {
136 return Err(zx::Status::INTERNAL);
137 }
138 let inner = self.inner.lock();
139 let wrapping_key_id = match purpose {
140 KeyPurpose::Data => inner.active_data_key,
141 KeyPurpose::Metadata => inner.active_metadata_key,
142 }
143 .ok_or(zx::Status::INVALID_ARGS)?;
144
145 let cipher = inner.ciphers.get(&wrapping_key_id).ok_or(zx::Status::UNAVAILABLE)?;
146
147 let nonce = zero_extended_nonce(owner);
148
149 let mut uwnrapped_key = [0u8; 32];
150 StdRng::from_os_rng().fill_bytes(&mut uwnrapped_key);
151
152 let wrapped_key = cipher.encrypt(&nonce, &uwnrapped_key[..])?;
153 Ok((
154 fxfs_crypto::FxfsKey {
155 wrapping_key_id,
156 key: wrapped_key.try_into().map_err(|_| zx::Status::INTERNAL)?,
157 },
158 UnwrappedKey::new(uwnrapped_key.to_vec()),
159 ))
160 }
161
162 async fn create_key_with_id(
163 &self,
164 owner: u64,
165 wrapping_key_id: WrappingKeyId,
166 object_type: ObjectType,
167 ) -> Result<(EncryptionKey, UnwrappedKey), zx::Status> {
168 if self.shutdown.load(Ordering::Relaxed) {
169 return Err(zx::Status::INTERNAL);
170 }
171
172 match object_type {
173 ObjectType::Directory | ObjectType::Symlink => {
174 let mut nonce = [0; 16];
175 StdRng::from_os_rng().fill_bytes(&mut nonce);
176 let inner = self.inner.lock();
177 let cipher = inner.ciphers.get(&wrapping_key_id).ok_or(zx::Status::UNAVAILABLE)?;
178 let mut unwrapped_key = [0u8; 96];
179 fscrypt::hkdf::hkdf(&cipher.wrapping_key, &nonce, &mut unwrapped_key);
180 Ok((
181 EncryptionKey::FscryptInoLblk32Dir {
182 key_identifier: wrapping_key_id,
183 nonce: nonce.try_into().map_err(|_| zx::Status::INTERNAL)?,
184 },
185 UnwrappedKey::new(unwrapped_key.to_vec()),
186 ))
187 }
188 _ => {
189 let inner = self.inner.lock();
190 let cipher = inner.ciphers.get(&wrapping_key_id).ok_or(zx::Status::UNAVAILABLE)?;
191 let nonce = zero_extended_nonce(owner);
192 let mut unwrapped_key = [0u8; 32];
193 StdRng::from_os_rng().fill_bytes(&mut unwrapped_key);
194 let wrapped = cipher.encrypt(&nonce, &unwrapped_key[..])?;
195 Ok((
196 EncryptionKey::Fxfs(fxfs_crypto::FxfsKey {
197 wrapping_key_id,
198 key: wrapped.try_into().map_err(|_| zx::Status::INTERNAL)?,
199 }),
200 UnwrappedKey::new(unwrapped_key.to_vec()),
201 ))
202 }
203 }
204 }
205
206 async fn unwrap_key(
207 &self,
208 wrapped_key: &WrappedKey,
209 owner: u64,
210 ) -> Result<UnwrappedKey, zx::Status> {
211 if self.shutdown.load(Ordering::Relaxed) {
212 return Err(zx::Status::INTERNAL);
213 }
214
215 match wrapped_key {
216 WrappedKey::FscryptInoLblk32Dir(FscryptKeyIdentifierAndNonce {
217 key_identifier,
218 nonce,
219 }) => {
220 let inner = self.inner.lock();
221 let cipher = inner.ciphers.get(key_identifier).ok_or(zx::Status::UNAVAILABLE)?;
222 let mut unwrapped_key = [0u8; 96];
223 fscrypt::hkdf::hkdf(&cipher.wrapping_key, nonce, &mut unwrapped_key);
224 Ok(UnwrappedKey::new(unwrapped_key.to_vec()))
225 }
226 WrappedKey::Fxfs(fidl_fuchsia_fxfs::FxfsKey { wrapping_key_id, wrapped_key }) => {
227 let inner = self.inner.lock();
228 let cipher = inner.ciphers.get(wrapping_key_id).ok_or(zx::Status::UNAVAILABLE)?;
229 let mut nonce = Nonce::default();
230 nonce.as_mut_slice()[..8].copy_from_slice(&owner.to_le_bytes());
231 Ok(UnwrappedKey::new(cipher.decrypt(&nonce, wrapped_key)?))
232 }
233 _ => Err(zx::Status::NOT_SUPPORTED),
234 }
235 }
236}
237#[cfg(test)]
238mod tests {
239 use super::*;
240
241 #[fuchsia::test]
242 async fn test_wrap_unwrap() {
243 let crypt = CryptBase::new();
244 let key = [0xABu8; 32];
245 let id = [1u8; 16];
246 crypt.add_wrapping_key(id, key).expect("add_wrapping_key failed");
247 crypt.set_active_key(KeyPurpose::Data, id).expect("set_active_key failed");
248
249 let (fxfs_key, unwrapped_key) =
250 crypt.create_key(0, KeyPurpose::Data).await.expect("create_key failed");
251 assert_eq!(fxfs_key.wrapping_key_id, id);
252 assert_eq!(unwrapped_key.len(), 32);
253
254 let unwrapped_back = crypt
255 .unwrap_key(&WrappedKey::Fxfs(fxfs_key.into()), 0)
256 .await
257 .expect("unwrap_key failed");
258 assert_eq!(*unwrapped_key, *unwrapped_back);
259 }
260
261 #[fuchsia::test]
262 async fn test_forget_wrapping_key() {
263 let crypt = CryptBase::new();
264 let key = [0xABu8; 32];
265 let id = [1u8; 16];
266 crypt.add_wrapping_key(id, key).expect("add_wrapping_key failed");
267 assert_eq!(crypt.add_wrapping_key(id, key), Err(zx::Status::ALREADY_EXISTS));
268 crypt.forget_wrapping_key(&id).unwrap();
269 assert_eq!(
270 crypt
271 .unwrap_key(
272 &WrappedKey::Fxfs(fidl_fuchsia_fxfs::FxfsKey {
273 wrapping_key_id: id,
274 wrapped_key: [0u8; 48]
275 }),
276 0
277 )
278 .await
279 .expect_err("unwrap_key should fail when wrapping key is forgotten"),
280 zx::Status::UNAVAILABLE
281 );
282 crypt.add_wrapping_key(id, key).expect("add_wrapping_key failed");
283 }
284
285 #[fuchsia::test]
286 async fn test_active_key_management() {
287 let crypt = CryptBase::new();
288 let key = [0xABu8; 32];
289 let id1 = [0u8; 16];
290 let id2 = [1u8; 16];
291 crypt.add_wrapping_key(id1, key).expect("add_wrapping_key failed");
292 crypt.add_wrapping_key(id2, key).expect("add_wrapping_key failed");
293
294 crypt.set_active_key(KeyPurpose::Data, id1).expect("set_active_key failed");
295 crypt.set_active_key(KeyPurpose::Metadata, id2).expect("set_active_key failed");
296
297 assert_eq!(crypt.forget_wrapping_key(&id1), Err(zx::Status::INVALID_ARGS));
298 assert_eq!(crypt.forget_wrapping_key(&id2), Err(zx::Status::INVALID_ARGS));
299 }
300
301 #[fuchsia::test]
302 async fn test_shutdown() {
303 let crypt = CryptBase::new();
304 let key = [0xABu8; 32];
305 let id = [1u8; 16];
306 crypt.add_wrapping_key(id, key).expect("add_wrapping_key failed");
307 crypt.set_active_key(KeyPurpose::Data, id).expect("set_active_key failed");
308
309 crypt.shutdown();
310
311 assert_eq!(
312 crypt
313 .create_key(0, KeyPurpose::Data)
314 .await
315 .expect_err("create_key should fail when crypt has shut down"),
316 zx::Status::INTERNAL
317 );
318 assert_eq!(
319 crypt
320 .create_key_with_id(0, id, ObjectType::File)
321 .await
322 .expect_err("create_key_with_id should fail when crypt has shut down"),
323 zx::Status::INTERNAL
324 );
325 assert_eq!(
326 crypt
327 .unwrap_key(
328 &WrappedKey::Fxfs(fidl_fuchsia_fxfs::FxfsKey {
329 wrapping_key_id: id,
330 wrapped_key: [0u8; 48]
331 }),
332 0,
333 )
334 .await
335 .expect_err("unwrap_key should fail when crypt has shut down"),
336 zx::Status::INTERNAL
337 );
338 }
339
340 #[fuchsia::test]
341 async fn test_create_key_no_active_key() {
342 let crypt = CryptBase::new();
343 assert_eq!(
344 crypt
345 .create_key(0, KeyPurpose::Data)
346 .await
347 .expect_err("create_key should fail when no active key is set"),
348 zx::Status::INVALID_ARGS
349 );
350 }
351
352 #[fuchsia::test]
353 async fn test_create_key_with_id_not_found() {
354 let crypt = CryptBase::new();
355 let id = [1u8; 16];
356 assert_eq!(
357 crypt.create_key_with_id(0, id, ObjectType::File).await.expect_err(
358 "create_key_with_id should fail when no active key is set at wrapping key id"
359 ),
360 zx::Status::UNAVAILABLE
361 );
362 }
363
364 #[fuchsia::test]
365 async fn test_unwrap_key_not_found() {
366 let crypt = CryptBase::new();
367 let id = [1u8; 16];
368 assert_eq!(
369 crypt
370 .unwrap_key(
371 &WrappedKey::Fxfs(fidl_fuchsia_fxfs::FxfsKey {
372 wrapping_key_id: id,
373 wrapped_key: [0u8; 48]
374 }),
375 0,
376 )
377 .await
378 .expect_err("unwrap_key should fail when no active key is set at wrapping key id"),
379 zx::Status::UNAVAILABLE
380 );
381 }
382
383 #[fuchsia::test]
384 async fn test_unwrap_key_wrong_owner() {
385 let crypt = CryptBase::new();
386 let key = [0xABu8; 32];
387 let id = [0u8; 16];
388 crypt.add_wrapping_key(id, key).expect("add_wrapping_key failed");
389 crypt.set_active_key(KeyPurpose::Data, id).expect("set_active_key failed");
390
391 let (fxfs_key, _unwrapped_key) =
392 crypt.create_key(0, KeyPurpose::Data).await.expect("create_key failed");
393 assert_eq!(
395 crypt
396 .unwrap_key(&WrappedKey::Fxfs(fxfs_key.into()), 1)
397 .await
398 .expect_err("unwrap_key should fail when owner does not match"),
399 zx::Status::INTERNAL
400 );
401 }
402
403 #[fuchsia::test]
404 async fn test_wrap_unwrap_key_with_arbitrary_wrapping_key_id() {
405 let crypt = CryptBase::new();
406 let key = [0xABu8; 32];
407 let id = [2u8; 16];
408 crypt.add_wrapping_key(id, key).expect("add_key failed");
409
410 let (wrapped_key, unwrapped_key) = crypt
411 .create_key_with_id(0, id, ObjectType::File)
412 .await
413 .expect("create_key_with_id failed");
414 let unwrap_result =
415 crypt.unwrap_key(&WrappedKey::from(wrapped_key), 0).await.expect("unwrap_key failed");
416 assert_eq!(*unwrap_result, *unwrapped_key);
417
418 let (wrapped_key, unwrapped_key) = crypt
420 .create_key_with_id(1, id, ObjectType::File)
421 .await
422 .expect("create_key_with_id failed");
423 let unwrap_result =
424 crypt.unwrap_key(&WrappedKey::from(wrapped_key), 1).await.expect("unwrap_key failed");
425 assert_eq!(*unwrap_result, *unwrapped_key);
426 }
427
428 #[fuchsia::test]
429 async fn test_unwrap_key_wrong_key() {
430 let crypt = CryptBase::new();
431 let key = [0xABu8; 32];
432 let id = [0u8; 16];
433 crypt.add_wrapping_key(id, key).expect("add_key failed");
434 crypt.set_active_key(KeyPurpose::Data, id).expect("set_active_key failed");
435
436 let (fxfs_key, _unwrapped_key) =
437 crypt.create_key(0, KeyPurpose::Data).await.expect("create_key failed");
438 let mut modified_wrapped_key = fxfs_key.key.to_vec();
439 for byte in &mut modified_wrapped_key {
440 *byte ^= 0xff;
441 }
442 assert_eq!(
443 crypt
444 .unwrap_key(
445 &WrappedKey::Fxfs(fidl_fuchsia_fxfs::FxfsKey {
446 wrapping_key_id: fxfs_key.wrapping_key_id,
447 wrapped_key: modified_wrapped_key.clone().try_into().unwrap(),
448 }),
449 0,
450 )
451 .await
452 .is_err(),
453 true
454 );
455 }
456}