1use aes_gcm_siv::aead::Aead;
6use aes_gcm_siv::{Aes256GcmSiv, KeyInit as _, Nonce};
7use anyhow::{Error, bail};
8use fidl_fuchsia_fxfs::{
9 CryptCreateKeyResult, CryptRequest, CryptRequestStream, FscryptKeyIdentifier,
10 FscryptKeyIdentifierAndNonce, FxfsKey, KeyPurpose, ObjectType, WrappedKey,
11};
12use fidl_fuchsia_hardware_inlineencryption::DeviceSynchronousProxy;
13use fscrypt::hkdf::{HKDF_CONTEXT_INODE_HASH_KEY, HKDF_CONTEXT_KEY_IDENTIFIER, fscrypt_hkdf};
14use fuchsia_sync::Mutex;
15use futures::stream::StreamExt;
16use hkdf::Hkdf;
17use linux_uapi::FSCRYPT_KEY_IDENTIFIER_SIZE;
18use starnix_uapi::errors::Errno;
19use starnix_uapi::{errno, error};
20use std::collections::hash_map::{Entry, HashMap};
21use std::sync::OnceLock;
22
23const FXFS_FSCRYPT_WRAPPING_KEY_INFO: &str = "fscrypt1";
28const FSCRYPT_HKDF_NONCE_PREFIX: &[u8] = b"fscrypt\0";
29
30const DATA_UNIT_SIZE: u32 = 4096;
31const AES256_KEY_SIZE: usize = 32;
32
33pub type EncryptionKeyId = [u8; FSCRYPT_KEY_IDENTIFIER_SIZE as usize];
35
36struct KeyInfo {
37 users: Vec<u32>,
38 key: Box<[u8]>,
39 slot: Option<u8>,
40}
41
42struct CryptServiceInner {
43 keys: HashMap<EncryptionKeyId, KeyInfo>,
44 metadata_key: Option<EncryptionKeyId>,
45 data_key: Option<EncryptionKeyId>,
46}
47
48pub struct CryptService {
49 inner: Mutex<CryptServiceInner>,
50 inline_crypto_proxy: Option<DeviceSynchronousProxy>,
51 uuid: OnceLock<[u8; 16]>,
52}
53
54impl CryptService {
55 pub fn new(
57 raw_metadata_key: &[u8],
58 raw_data_key: &[u8],
59 inline_crypto_proxy: Option<DeviceSynchronousProxy>,
60 ) -> Self {
61 let metadata_wrapping_key_id = derive_lblk32_wrapping_key_id(raw_metadata_key);
62 let data_wrapping_key_id = derive_lblk32_wrapping_key_id(raw_data_key);
63
64 fn to_key_info(key: &[u8]) -> KeyInfo {
65 KeyInfo { users: Vec::new(), key: key.into(), slot: None }
66 }
67
68 Self {
69 inner: Mutex::new(CryptServiceInner {
70 keys: HashMap::from_iter([
71 (metadata_wrapping_key_id, to_key_info(raw_metadata_key)),
72 (data_wrapping_key_id, to_key_info(raw_data_key)),
73 ]),
74 metadata_key: Some(metadata_wrapping_key_id),
75 data_key: Some(data_wrapping_key_id),
76 }),
77 inline_crypto_proxy,
78 uuid: OnceLock::new(),
79 }
80 }
81
82 pub fn contains_key(&self, key: EncryptionKeyId) -> bool {
84 let inner = self.inner.lock();
85 inner.keys.contains_key(&key)
86 }
87
88 pub fn get_users_for_key(&self, key: EncryptionKeyId) -> Option<Vec<u32>> {
90 let inner = self.inner.lock();
91 inner.keys.get(&key).map(|x| x.users.clone())
92 }
93
94 pub fn add_wrapping_key(&self, raw_key: &[u8], uid: u32) -> Result<EncryptionKeyId, Errno> {
96 let (key, slot) = if let Some(proxy) = self.inline_crypto_proxy.as_ref() {
97 let key = Box::from(
98 proxy
99 .derive_raw_secret(raw_key, zx::MonotonicInstant::INFINITE)
100 .map_err(|_| errno!(EPIPE))?
101 .map_err(|_| errno!(EPIPE))?,
102 );
103 let slot = proxy
104 .program_key(raw_key, DATA_UNIT_SIZE, zx::MonotonicInstant::INFINITE)
105 .map_err(|_| errno!(EPIPE))?
106 .map_err(|_| errno!(EPIPE))?;
107 (key, Some(slot))
108 } else {
109 (Box::from(raw_key), None)
110 };
111 let key_identifier = derive_lblk32_wrapping_key_id(&key);
112 let mut inner = self.inner.lock();
113 match inner.keys.entry(key_identifier) {
114 Entry::Occupied(mut e) => {
115 let users = &mut e.get_mut().users;
116 if !users.contains(&uid) {
117 users.push(uid);
118 }
119 Ok(key_identifier)
120 }
121 Entry::Vacant(vacant) => {
122 vacant.insert(KeyInfo { users: vec![uid], key, slot });
123 Ok(key_identifier)
124 }
125 }
126 }
127
128 pub async fn handle_connection(&self, mut stream: CryptRequestStream) -> Result<(), Error> {
130 while let Some(request) = stream.next().await {
131 match request {
132 Ok(CryptRequest::CreateKey { owner, purpose, responder }) => {
133 responder
134 .send(match &self.create_key(owner, purpose) {
135 Ok((id, wrapped, key)) => Ok((id, wrapped, key)),
136 Err(e) => Err(*e),
137 })
138 .unwrap_or_else(
139 |error| log::error!(error:?; "Failed to send CreateKey response"),
140 );
141 }
142 Ok(CryptRequest::CreateKeyWithId {
143 owner,
144 wrapping_key_id,
145 object_type,
146 responder,
147 ..
148 }) => {
149 responder
150 .send(
151 match self.create_key_with_id(
152 owner,
153 EncryptionKeyId::from(wrapping_key_id),
154 object_type,
155 ) {
156 Ok((ref wrapped, ref key)) => Ok((wrapped, key)),
157 Err(e) => Err(e.into_raw()),
158 },
159 )
160 .unwrap_or_else(
161 |error| log::error!(error:?; "Failed to send CreateKeyWithId response"),
162 );
163 }
164 Ok(CryptRequest::UnwrapKey { owner, wrapped_key, responder }) => {
165 responder
166 .send(match self.unwrap_key(owner, wrapped_key) {
167 Ok(ref unwrapped) => Ok(unwrapped),
168 Err(e) => Err(e.into_raw()),
169 })
170 .unwrap_or_else(
171 |error| log::error!(error:?; "Failed to send UnwrapKey response"),
172 );
173 }
174 Err(error) => {
175 log::error!(error:?; "Error in CryptRequestStream");
176 bail!(error);
177 }
178 }
179 }
180 Ok(())
181 }
182
183 pub fn forget_wrapping_key(
185 &self,
186 wrapping_key_id: EncryptionKeyId,
187 uid: u32,
188 ) -> Result<(), Errno> {
189 let mut inner = self.inner.lock();
190 match inner.keys.entry(EncryptionKeyId::from(wrapping_key_id)) {
191 Entry::Occupied(mut e) => {
192 let user_ids = &mut e.get_mut().users;
193 if !user_ids.contains(&uid) {
194 return error!(ENOKEY);
195 } else {
196 let index = user_ids.iter().position(|x: &u32| *x == uid).unwrap();
197 user_ids.remove(index);
198 if user_ids.is_empty() {
199 e.remove();
200 }
201 }
202 }
203 Entry::Vacant(_) => {
204 return error!(ENOKEY);
205 }
206 }
207 Ok(())
208 }
209
210 pub fn set_uuid(&self, uuid: [u8; 16]) {
211 self.uuid.set(uuid).unwrap();
212 }
213
214 fn derive_directory_key(&self, key: &[u8], nonce: &[u8]) -> Result<Vec<u8>, zx::Status> {
215 Ok(fscrypt::to_directory_keys(key, self.uuid.get().ok_or(zx::Status::BAD_STATE)?, nonce)
216 .to_unwrapped_key())
217 }
218
219 fn create_key(&self, owner: u64, purpose: KeyPurpose) -> CryptCreateKeyResult {
220 let inner = self.inner.lock();
221 let wrapping_key_id = match purpose {
222 KeyPurpose::Data => inner.data_key.as_ref().ok_or_else(|| {
223 log::error!(
224 "tried to create key with KeyPurpose::Data but no active data wrapping key"
225 );
226 zx::Status::BAD_STATE.into_raw()
227 })?,
228 KeyPurpose::Metadata => inner.metadata_key.as_ref().ok_or_else(|| {
229 log::error!(
230 "tried to create key with KeyPurpose::Metadata but no active data wrapping key"
231 );
232 zx::Status::BAD_STATE.into_raw()
233 })?,
234 _ => return Err(zx::Status::INVALID_ARGS.into_raw()),
235 };
236 let key =
237 &inner.keys.get(wrapping_key_id).ok_or_else(|| zx::Status::BAD_STATE.into_raw())?.key;
238 let cipher = get_fxfs_cipher(key);
239 let nonce = zero_extended_nonce(owner);
240
241 let mut key = [0u8; 32];
242 rand::fill(&mut key[..]);
243
244 let wrapped = cipher.encrypt(&nonce, &key[..]).map_err(|error| {
245 log::error!(error:?; "Failed to wrap key");
246 zx::Status::INTERNAL.into_raw()
247 })?;
248
249 Ok((*wrapping_key_id, wrapped.into(), key.into()))
250 }
251
252 fn create_key_with_id(
253 &self,
254 owner: u64,
255 wrapping_key_id: EncryptionKeyId,
256 object_type: ObjectType,
257 ) -> Result<(WrappedKey, Vec<u8>), zx::Status> {
258 let mut inner = self.inner.lock();
259 let key_info = inner.keys.get_mut(&wrapping_key_id).ok_or(zx::Status::UNAVAILABLE)?;
260 match object_type {
261 ObjectType::Directory | ObjectType::Symlink => {
262 let mut nonce = [0; 16];
263 zx::cprng_draw(&mut nonce);
264 let unwrapped_key = self.derive_directory_key(&key_info.key, &nonce)?;
265 Ok((
266 WrappedKey::FscryptInoLblk32Dir(FscryptKeyIdentifierAndNonce {
267 key_identifier: wrapping_key_id,
268 nonce,
269 }),
270 unwrapped_key,
271 ))
272 }
273 ObjectType::File => {
274 if let Some(slot) = key_info.slot {
275 let unwrapped_key = derive_file_key(slot, &key_info.key);
276 Ok((
277 WrappedKey::FscryptInoLblk32File(FscryptKeyIdentifier {
278 key_identifier: wrapping_key_id,
279 }),
280 unwrapped_key,
281 ))
282 } else {
283 let cipher = get_fxfs_cipher(&key_info.key);
285 let nonce = zero_extended_nonce(owner);
286
287 let mut key = [0u8; 32];
288 rand::fill(&mut key[..]);
289
290 let wrapped = cipher.encrypt(&nonce, &key[..]).map_err(|error| {
291 log::error!(error:?; "Failed to wrap key");
292 zx::Status::INTERNAL
293 })?;
294
295 Ok((
296 WrappedKey::Fxfs(FxfsKey {
297 wrapping_key_id,
298 wrapped_key: wrapped.try_into().expect("wrapped key wrong size"),
299 }),
300 key.into(),
301 ))
302 }
303 }
304 _ => Err(zx::Status::NOT_SUPPORTED),
305 }
306 }
307
308 fn unwrap_key(&self, owner: u64, key: WrappedKey) -> Result<Vec<u8>, zx::Status> {
309 let mut inner = self.inner.lock();
310 match key {
311 WrappedKey::Fxfs(FxfsKey { wrapping_key_id, wrapped_key }) => {
312 let wrapping_key_id = EncryptionKeyId::from(wrapping_key_id);
313 let key_info = inner.keys.get(&wrapping_key_id).ok_or(zx::Status::UNAVAILABLE)?;
314
315 let cipher = get_fxfs_cipher(&key_info.key);
316 let nonce = zero_extended_nonce(owner);
317
318 Ok(cipher
319 .decrypt(&nonce, &wrapped_key[..])
320 .map_err(|_| zx::Status::IO_DATA_INTEGRITY)?)
321 }
322 WrappedKey::FscryptInoLblk32File(FscryptKeyIdentifier { key_identifier }) => {
323 let wrapping_key_id = EncryptionKeyId::from(key_identifier);
324 let key_info =
325 inner.keys.get_mut(&wrapping_key_id).ok_or(zx::Status::UNAVAILABLE)?;
326 let Some(slot) = key_info.slot else {
327 return Err(zx::Status::UNAVAILABLE);
330 };
331 Ok(derive_file_key(slot, &key_info.key))
332 }
333 WrappedKey::FscryptInoLblk32Dir(FscryptKeyIdentifierAndNonce {
334 key_identifier,
335 nonce,
336 }) => {
337 let wrapping_key_id = EncryptionKeyId::from(key_identifier);
338 let key_info = inner.keys.get(&wrapping_key_id).ok_or(zx::Status::UNAVAILABLE)?;
339
340 self.derive_directory_key(&key_info.key, &nonce)
341 }
342 _ => Err(zx::Status::NOT_SUPPORTED),
343 }
344 }
345}
346
347fn zero_extended_nonce(val: u64) -> Nonce {
348 let mut nonce = Nonce::default();
349 nonce.as_mut_slice()[..8].copy_from_slice(&val.to_le_bytes());
350 nonce
351}
352
353fn derive_file_key(slot: u8, key: &[u8]) -> Vec<u8> {
354 let mut unwrapped_key = Vec::with_capacity(17);
355 unwrapped_key.push(slot);
356 let ino_hash_key: [u8; 16] = fscrypt_hkdf(key, &[], HKDF_CONTEXT_INODE_HASH_KEY);
357 unwrapped_key.extend_from_slice(&ino_hash_key);
358 unwrapped_key
359}
360
361fn get_fxfs_cipher(raw_key: &[u8]) -> Aes256GcmSiv {
362 let hk = Hkdf::<sha2::Sha256>::new(None, raw_key);
363 let mut wrapping_key = [0u8; AES256_KEY_SIZE];
364 hk.expand(FXFS_FSCRYPT_WRAPPING_KEY_INFO.as_bytes(), &mut wrapping_key).unwrap();
365 Aes256GcmSiv::new((&wrapping_key).into())
366}
367
368fn derive_lblk32_wrapping_key_id(raw_key: &[u8]) -> [u8; FSCRYPT_KEY_IDENTIFIER_SIZE as usize] {
369 let hk = Hkdf::<sha2::Sha512>::new(None, raw_key);
370 let mut key_identifier = [0u8; FSCRYPT_KEY_IDENTIFIER_SIZE as usize];
371 let mut hkdf_info = FSCRYPT_HKDF_NONCE_PREFIX.to_vec();
372 hkdf_info.push(HKDF_CONTEXT_KEY_IDENTIFIER);
373 hk.expand(&hkdf_info, &mut key_identifier).unwrap();
374 key_identifier
375}
376
377#[cfg(test)]
378mod tests {
379 use super::*;
380 use assert_matches::assert_matches;
381 use block_client::RemoteBlockClient;
382 use fidl_fuchsia_fxfs::{FxfsKey, KeyPurpose, WrappedKey};
383 use fidl_fuchsia_hardware_inlineencryption::{DeviceMarker, DeviceRequest};
384 use fidl_fuchsia_storage_block::BlockProxy;
385
386 use fuchsia_async::LocalExecutor;
387 use starnix_uapi::errno;
388 use std::sync::Arc;
389 use storage_device::block_device::BlockDevice;
390 use storage_device::{Device, InlineCryptoOptions, ReadOptions, WriteOptions};
391 use vmo_backed_block_server::{
392 InitialContents, VmoBackedServerOptions, VmoBackedServerTestingExt,
393 };
394
395 const BLOCK_SIZE: u32 = 4096;
396 const TEST_UUID: [u8; 16] =
397 [75, 146, 230, 48, 132, 165, 68, 97, 141, 247, 22, 242, 153, 171, 153, 38];
398
399 #[test]
400 fn add_and_forget_wrapping_keys() {
401 let service = CryptService::new(&[0; 32], &[1; 32], None);
402
403 let wrapping_key_id =
405 service.add_wrapping_key(&u128::to_le_bytes(1), 0).expect("add wrapping key failed");
406
407 let wrapping_key_id2 =
408 service.add_wrapping_key(&u128::to_le_bytes(1), 1).expect("add wrapping key failed");
409
410 assert_eq!(wrapping_key_id2, wrapping_key_id);
411
412 let wrapping_key_id3 =
414 service.add_wrapping_key(&u128::to_le_bytes(1), 1).expect("add wrapping key failed");
415
416 assert_eq!(wrapping_key_id3, wrapping_key_id);
417
418 {
419 let inner = service.inner.lock();
420 assert_eq!(inner.keys.get(&wrapping_key_id).unwrap().users, [0, 1]);
421 }
422
423 service.forget_wrapping_key(wrapping_key_id, 1).expect("forget wrapping key failed");
426 service
427 .create_key_with_id(0, wrapping_key_id, ObjectType::File)
428 .expect("create key with id failed");
429
430 assert_eq!(
432 service.forget_wrapping_key(wrapping_key_id, 1).expect_err(
433 "forget wrapping key should fail if the key was already removed by this user"
434 ),
435 errno!(ENOKEY)
436 );
437 service.forget_wrapping_key(wrapping_key_id, 0).expect("forget wrapping key failed");
439 assert_eq!(
440 service
441 .create_key_with_id(
442 0,
443 EncryptionKeyId::from(u128::to_le_bytes(1)),
444 ObjectType::File,
445 )
446 .expect_err(
447 "create_key_with_id should fail if the key hasn't been added by the caller"
448 ),
449 zx::Status::UNAVAILABLE
450 );
451 service.add_wrapping_key(&u128::to_le_bytes(1), 0).expect("add wrapping key failed");
452 }
453
454 #[fuchsia::test]
455 async fn test_derive_wrapping_key_id_and_lblk32_derived_keys() {
456 const EXPECTED_WRAPPING_KEY_ID: [u8; 16] =
457 [40, 205, 90, 253, 77, 129, 133, 220, 222, 25, 208, 200, 136, 101, 239, 101];
458 const EXPECTED_CTS_KEY: [u8; 32] = [
459 223, 72, 191, 189, 133, 62, 81, 175, 91, 93, 132, 0, 9, 246, 22, 32, 76, 91, 28, 2, 96,
460 27, 182, 66, 131, 84, 218, 118, 230, 226, 142, 115,
461 ];
462 const EXPECTED_INO_HASH_KEY: [u8; 16] =
463 [241, 22, 180, 110, 76, 135, 84, 48, 206, 33, 210, 253, 11, 10, 230, 122];
464
465 let block_server = Arc::new(
466 VmoBackedServerOptions {
467 block_size: BLOCK_SIZE,
468 initial_contents: InitialContents::FromCapacity(393216),
469 ..Default::default()
470 }
471 .build()
472 .expect("build failed"),
473 );
474
475 let block_server_clone = block_server.clone();
476 let (insecure_inilne_crypto_proxy, server) =
477 fidl::endpoints::create_sync_proxy::<DeviceMarker>();
478 std::thread::spawn(|| {
479 LocalExecutor::default().run_singlethreaded(async move {
480 block_server_clone
481 .connect_insecure_inline_encryption_server(server, TEST_UUID)
482 .await;
483 })
484 });
485
486 let service = CryptService::new(&[0; 32], &[1; 32], Some(insecure_inilne_crypto_proxy));
487 service.set_uuid(TEST_UUID);
488 let wrapping_key_id = service.add_wrapping_key(&[0xdc; 32], 0).unwrap();
489 assert_eq!(wrapping_key_id, EXPECTED_WRAPPING_KEY_ID);
490
491 let (_, unwrapped_key) =
492 service.create_key_with_id(0, wrapping_key_id, ObjectType::Directory).unwrap();
493 let (cts_key, remainder) = unwrapped_key.split_at(EXPECTED_CTS_KEY.len());
494 let (ino_hash_key, _dir_hash_key) = remainder.split_at(EXPECTED_INO_HASH_KEY.len());
495
496 assert_eq!(cts_key, &EXPECTED_CTS_KEY);
497 assert_eq!(ino_hash_key, &EXPECTED_INO_HASH_KEY);
498 }
499
500 #[fuchsia::test]
501 async fn test_create_key_with_id_with_lblk32_key() {
502 let block_server = Arc::new(
503 VmoBackedServerOptions {
504 block_size: BLOCK_SIZE,
505 initial_contents: InitialContents::FromCapacity(393216),
506 ..Default::default()
507 }
508 .build()
509 .expect("build failed"),
510 );
511
512 let block_server_clone = block_server.clone();
513 let (insecure_inilne_crypto_proxy, server) =
514 fidl::endpoints::create_sync_proxy::<DeviceMarker>();
515 std::thread::spawn(|| {
516 LocalExecutor::default().run_singlethreaded(async move {
517 block_server_clone
518 .connect_insecure_inline_encryption_server(server, TEST_UUID)
519 .await;
520 })
521 });
522
523 let service = CryptService::new(&[0; 32], &[1; 32], Some(insecure_inilne_crypto_proxy));
524 let wrapping_key_id = service.add_wrapping_key(&[0xcd; 32], 0).unwrap();
525
526 let (wrapped_key, unwrapped_key) = service
527 .create_key_with_id(0, wrapping_key_id, ObjectType::File)
528 .expect("create_key failed");
529 assert_matches!(wrapped_key, WrappedKey::FscryptInoLblk32File(FscryptKeyIdentifier { .. }));
530 let expected_slot = 0;
531 assert_eq!(unwrapped_key[0], expected_slot);
532
533 let mut key = [0xcd; 32];
534 for b in &mut key {
535 *b = *b >> 4 | *b << 4;
536 }
537 let expected_ino_hash_key: [u8; 16] = fscrypt_hkdf(&key, &[], HKDF_CONTEXT_INODE_HASH_KEY);
538 assert_eq!(unwrapped_key[1..17], expected_ino_hash_key);
539 let device = BlockDevice::new(
541 RemoteBlockClient::new(block_server.clone().connect::<BlockProxy>())
542 .await
543 .expect("Unable to create block client"),
544 false,
545 )
546 .await
547 .unwrap();
548
549 let plaintext: &[u8] = b"This is aligned sensitive data!!";
550 let mut buf = device.allocate_buffer(4096).await;
551 buf.as_mut_slice()[..plaintext.len()].copy_from_slice(plaintext);
552 device
553 .write_with_opts(
554 0,
555 buf.as_ref(),
556 WriteOptions {
557 inline_crypto: InlineCryptoOptions::enabled(expected_slot, 0),
558 ..Default::default()
559 },
560 )
561 .await
562 .expect("failed to write data");
563
564 let mut read_buf = device.allocate_buffer(4096).await;
565
566 device
568 .read_with_opts(0, read_buf.as_mut(), ReadOptions::default())
569 .await
570 .expect("Read failed");
571 assert_ne!(&read_buf.as_slice()[..plaintext.len()], plaintext);
572
573 let _wrapping_key_id = service.add_wrapping_key(&[0xab; 32], 0).unwrap();
577 device
578 .read_with_opts(
579 0,
580 read_buf.as_mut(),
581 ReadOptions { inline_crypto: InlineCryptoOptions::enabled(expected_slot + 1, 0) },
582 )
583 .await
584 .expect("Read failed");
585 assert_ne!(&read_buf.as_slice()[..plaintext.len()], plaintext);
586
587 device
589 .read_with_opts(
590 0,
591 read_buf.as_mut(),
592 ReadOptions { inline_crypto: InlineCryptoOptions::enabled(expected_slot + 2, 0) },
593 )
594 .await
595 .expect_err("Read passed unexpectedly with unused key slot");
596
597 device
599 .read_with_opts(
600 0,
601 read_buf.as_mut(),
602 ReadOptions { inline_crypto: InlineCryptoOptions::enabled(expected_slot, 0) },
603 )
604 .await
605 .expect("Read failed");
606 assert_eq!(&read_buf.as_slice()[..plaintext.len()], plaintext);
607 }
608
609 #[fuchsia::test]
610 fn unwrap_fxfs_wrapped_key_with_lblk32_key() {
611 let block_server = Arc::new(
612 VmoBackedServerOptions {
613 block_size: BLOCK_SIZE,
614 initial_contents: InitialContents::FromCapacity(393216),
615 ..Default::default()
616 }
617 .build()
618 .expect("build failed"),
619 );
620 let block_server_clone = block_server.clone();
621 let (insecure_inilne_crypto_proxy, server) =
622 fidl::endpoints::create_sync_proxy::<DeviceMarker>();
623 std::thread::spawn(|| {
624 LocalExecutor::default().run_singlethreaded(async move {
625 block_server_clone
626 .connect_insecure_inline_encryption_server(server, TEST_UUID)
627 .await;
628 })
629 });
630
631 let service = CryptService::new(&[0; 32], &[1; 32], Some(insecure_inilne_crypto_proxy));
632 service.set_uuid(TEST_UUID);
633 let wrapping_key_id =
634 service.add_wrapping_key(&[0xcd; 32], 0).expect("add wrapping key failed");
635 let (wrapped_key, expected_unwrapped_key) = service
636 .create_key_with_id(0, wrapping_key_id, ObjectType::Directory)
637 .expect("create_key failed");
638 assert_matches!(
639 wrapped_key,
640 WrappedKey::FscryptInoLblk32Dir(FscryptKeyIdentifierAndNonce {
641 key_identifier,
642 ..
643 }) if key_identifier == wrapping_key_id
644 );
645 let unwrapped_key = service.unwrap_key(0, wrapped_key).expect("create_key failed");
646 assert_eq!(unwrapped_key, expected_unwrapped_key);
647 }
648
649 #[test]
650 fn wrap_unwrap_key() {
651 let service = CryptService::new(&[0; 32], &[0xcd; 32], None);
652
653 let (wrapping_key_id, wrapped_key, unwrapped_key) =
654 service.create_key(0, KeyPurpose::Data).expect("create_key failed");
655 let unwrap_result = service
656 .unwrap_key(
657 0,
658 WrappedKey::Fxfs(FxfsKey {
659 wrapping_key_id,
660 wrapped_key: wrapped_key.try_into().unwrap(),
661 }),
662 )
663 .expect("unwrap_key failed");
664 assert_eq!(unwrap_result, unwrapped_key);
665
666 let (wrapping_key_id, wrapped_key, unwrapped_key) =
668 service.create_key(1, KeyPurpose::Data).expect("create_key failed");
669 let unwrap_result = service
670 .unwrap_key(
671 1,
672 WrappedKey::Fxfs(FxfsKey {
673 wrapping_key_id,
674 wrapped_key: wrapped_key.try_into().unwrap(),
675 }),
676 )
677 .expect("unwrap_key failed");
678 assert_eq!(unwrap_result, unwrapped_key);
679 }
680
681 #[test]
682 fn wrap_unwrap_key_with_arbitrary_wrapping_key() {
683 let service = CryptService::new(&[0; 32], &[1; 32], None);
684
685 let wrapping_key_id =
686 service.add_wrapping_key(&[2; 32], 0).expect("add wrapping key failed");
687
688 let (wrapped_key, unwrapped_key) = service
689 .create_key_with_id(0, wrapping_key_id, ObjectType::File)
690 .expect("create_key_with_id failed");
691 match wrapped_key {
693 WrappedKey::Fxfs(fxfs_key) => {
694 let unwrap_result = service
695 .unwrap_key(
696 0,
697 WrappedKey::Fxfs(FxfsKey {
698 wrapping_key_id,
699 wrapped_key: fxfs_key.wrapped_key.try_into().unwrap(),
700 }),
701 )
702 .expect("unwrap_key failed");
703 assert_eq!(unwrap_result, unwrapped_key);
704 }
705 _ => panic!("Found a non-FxfsKey wrapped key"),
706 }
707
708 let (wrapped_key, unwrapped_key) = service
710 .create_key_with_id(1, wrapping_key_id, ObjectType::File)
711 .expect("create_key_with_id failed");
712 match wrapped_key {
714 WrappedKey::Fxfs(fxfs_key) => {
715 let unwrap_result = service
716 .unwrap_key(
717 1,
718 WrappedKey::Fxfs(FxfsKey {
719 wrapping_key_id,
720 wrapped_key: fxfs_key.wrapped_key.try_into().unwrap(),
721 }),
722 )
723 .expect("unwrap_key failed");
724 assert_eq!(unwrap_result, unwrapped_key);
725 }
726 _ => panic!("Found a non-FxfsKey wrapped key"),
727 }
728 }
729
730 #[test]
731 fn create_key_with_wrapping_key_that_does_not_exist() {
732 let service = CryptService::new(&[0; 32], &[1; 32], None);
733
734 let wrapping_key_id =
735 service.add_wrapping_key(&[2; 32], 0).expect("add wrapping key failed");
736
737 let (wrapped_key, unwrapped_key) = service
738 .create_key_with_id(0, wrapping_key_id, ObjectType::File)
739 .expect("create_key_with_id failed");
740
741 match wrapped_key {
743 WrappedKey::Fxfs(fxfs_key) => {
744 let unwrap_result = service
745 .unwrap_key(
746 0,
747 WrappedKey::Fxfs(FxfsKey {
748 wrapping_key_id,
749 wrapped_key: fxfs_key.wrapped_key.try_into().unwrap(),
750 }),
751 )
752 .expect("unwrap_key failed");
753 assert_eq!(unwrap_result, unwrapped_key);
754 }
755 _ => panic!("Found a non-FxfsKey wrapped key"),
756 }
757
758 service.forget_wrapping_key(wrapping_key_id, 0).unwrap();
759
760 service
761 .create_key_with_id(0, wrapping_key_id, ObjectType::File)
762 .expect_err("create_key_with_id should fail if the wrapping key does not exist");
763 }
764
765 #[test]
766 fn unwrap_key_wrong_key() {
767 let service = CryptService::new(&[0; 32], &[0xcd; 32], None);
768 let (wrapping_key_id, mut wrapped_key, _) =
769 service.create_key(0, KeyPurpose::Data).expect("create_key failed");
770 for byte in &mut wrapped_key {
771 *byte ^= 0xff;
772 }
773 service
774 .unwrap_key(
775 0,
776 WrappedKey::Fxfs(FxfsKey {
777 wrapping_key_id,
778 wrapped_key: wrapped_key.try_into().unwrap(),
779 }),
780 )
781 .expect_err("unwrap_key should fail");
782 }
783
784 #[test]
785 fn unwrap_key_wrong_owner() {
786 let service = CryptService::new(&[0; 32], &[0xcd; 32], None);
787
788 let (wrapping_key_id, wrapped_key, _) =
789 service.create_key(0, KeyPurpose::Data).expect("create_key failed");
790 service
791 .unwrap_key(
792 1,
793 WrappedKey::Fxfs(FxfsKey {
794 wrapping_key_id,
795 wrapped_key: wrapped_key.try_into().unwrap(),
796 }),
797 )
798 .expect_err("unwrap_key should fail");
799 }
800
801 #[fuchsia::test]
802 async fn test_add_wrapping_key_uses_raw_key() {
803 let (client, server) = fidl::endpoints::create_sync_proxy::<DeviceMarker>();
804 let raw_key_bytes = [0xAB; 32];
805 let expected_key = raw_key_bytes.clone();
806
807 std::thread::spawn(move || {
808 LocalExecutor::default().run_singlethreaded(async move {
809 let mut stream = server.into_stream();
810 while let Some(Ok(request)) = stream.next().await {
811 match request {
812 DeviceRequest::DeriveRawSecret { wrapped_key, responder } => {
813 let mut derived = wrapped_key.clone();
814 derived[0] ^= 0xFF;
815 responder.send(Ok(&derived)).unwrap();
816 }
817 DeviceRequest::ProgramKey { wrapped_key, responder, .. } => {
818 if wrapped_key == expected_key {
819 responder.send(Ok(0)).unwrap();
820 } else {
821 responder.send(Err(zx::Status::INVALID_ARGS.into_raw())).unwrap();
822 }
823 }
824 }
825 }
826 })
827 });
828
829 let service = CryptService::new(&[0; 32], &[1; 32], Some(client));
830 service.add_wrapping_key(&raw_key_bytes, 0).expect("add_wrapping_key failed");
831 }
832}