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