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 test_vmo_backed_block_server::VmoBackedServer;
405
406 const BLOCK_SIZE: u32 = 4096;
407 const BLOCK_COUNT: u64 = 393216;
408 const TEST_UUID: [u8; 16] =
409 [75, 146, 230, 48, 132, 165, 68, 97, 141, 247, 22, 242, 153, 171, 153, 38];
410
411 #[test]
412 fn add_and_forget_wrapping_keys() {
413 let service = CryptService::new(&[0; 32], &[1; 32], None);
414
415 let wrapping_key_id =
417 service.add_wrapping_key(&u128::to_le_bytes(1), 0).expect("add wrapping key failed");
418
419 let wrapping_key_id2 =
420 service.add_wrapping_key(&u128::to_le_bytes(1), 1).expect("add wrapping key failed");
421
422 assert_eq!(wrapping_key_id2, wrapping_key_id);
423
424 let wrapping_key_id3 =
426 service.add_wrapping_key(&u128::to_le_bytes(1), 1).expect("add wrapping key failed");
427
428 assert_eq!(wrapping_key_id3, wrapping_key_id);
429
430 {
431 let inner = service.inner.lock();
432 assert_eq!(inner.keys.get(&wrapping_key_id).unwrap().users, [0, 1]);
433 }
434
435 service.forget_wrapping_key(wrapping_key_id, 1).expect("forget wrapping key failed");
438 service
439 .create_key_with_id(0, wrapping_key_id, ObjectType::File)
440 .expect("create key with id failed");
441
442 assert_eq!(
444 service.forget_wrapping_key(wrapping_key_id, 1).expect_err(
445 "forget wrapping key should fail if the key was already removed by this user"
446 ),
447 errno!(ENOKEY)
448 );
449 service.forget_wrapping_key(wrapping_key_id, 0).expect("forget wrapping key failed");
451 assert_eq!(
452 service
453 .create_key_with_id(
454 0,
455 EncryptionKeyId::from(u128::to_le_bytes(1)),
456 ObjectType::File,
457 )
458 .expect_err(
459 "create_key_with_id should fail if the key hasn't been added by the caller"
460 ),
461 zx::Status::UNAVAILABLE
462 );
463 service.add_wrapping_key(&u128::to_le_bytes(1), 0).expect("add wrapping key failed");
464 }
465
466 #[fuchsia::test]
467 async fn test_derive_wrapping_key_id_and_lblk32_derived_keys() {
468 const EXPECTED_WRAPPING_KEY_ID: [u8; 16] =
469 [40, 205, 90, 253, 77, 129, 133, 220, 222, 25, 208, 200, 136, 101, 239, 101];
470 const EXPECTED_CTS_KEY: [u8; 32] = [
471 223, 72, 191, 189, 133, 62, 81, 175, 91, 93, 132, 0, 9, 246, 22, 32, 76, 91, 28, 2, 96,
472 27, 182, 66, 131, 84, 218, 118, 230, 226, 142, 115,
473 ];
474 const EXPECTED_INO_HASH_KEY: [u8; 16] =
475 [241, 22, 180, 110, 76, 135, 84, 48, 206, 33, 210, 253, 11, 10, 230, 122];
476
477 let block_server = Arc::new(
478 VmoBackedServer::new(BLOCK_COUNT, BLOCK_SIZE, &[])
479 .expect("Failed to create VmoBackedServer"),
480 );
481
482 let (insecure_inilne_crypto_proxy, server) =
483 fidl::endpoints::create_sync_proxy::<DeviceMarker>();
484 std::thread::spawn(|| {
485 LocalExecutor::default().run_singlethreaded(async move {
486 block_server.connect_insecure_inline_encryption_server(server, TEST_UUID).await;
487 })
488 });
489
490 let service = CryptService::new(&[0; 32], &[1; 32], Some(insecure_inilne_crypto_proxy));
491 service.set_uuid(TEST_UUID);
492 let wrapping_key_id = service.add_wrapping_key(&[0xdc; 32], 0).unwrap();
493 assert_eq!(wrapping_key_id, EXPECTED_WRAPPING_KEY_ID);
494
495 let (_, unwrapped_key) =
496 service.create_key_with_id(0, wrapping_key_id, ObjectType::Directory).unwrap();
497 let (cts_key, remainder) = unwrapped_key.split_at(EXPECTED_CTS_KEY.len());
498 let (ino_hash_key, _dir_hash_key) = remainder.split_at(EXPECTED_INO_HASH_KEY.len());
499
500 assert_eq!(cts_key, &EXPECTED_CTS_KEY);
501 assert_eq!(ino_hash_key, &EXPECTED_INO_HASH_KEY);
502 }
503
504 #[fuchsia::test]
505 async fn test_create_key_with_id_with_lblk32_key() {
506 let block_server = Arc::new(
507 VmoBackedServer::new(BLOCK_COUNT, BLOCK_SIZE, &[])
508 .expect("Failed to create VmoBackedServer"),
509 );
510
511 let block_server_clone = block_server.clone();
512 let (insecure_inilne_crypto_proxy, server) =
513 fidl::endpoints::create_sync_proxy::<DeviceMarker>();
514 std::thread::spawn(|| {
515 LocalExecutor::default().run_singlethreaded(async move {
516 block_server_clone
517 .connect_insecure_inline_encryption_server(server, TEST_UUID)
518 .await;
519 })
520 });
521
522 let service = CryptService::new(&[0; 32], &[1; 32], Some(insecure_inilne_crypto_proxy));
523 let wrapping_key_id = service.add_wrapping_key(&[0xcd; 32], 0).unwrap();
524
525 let (wrapped_key, unwrapped_key) = service
526 .create_key_with_id(0, wrapping_key_id, ObjectType::File)
527 .expect("create_key failed");
528 assert_matches!(wrapped_key, WrappedKey::FscryptInoLblk32File(FscryptKeyIdentifier { .. }));
529 let expected_slot = 0;
530 assert_eq!(unwrapped_key[0], expected_slot);
531
532 let mut key = [0xcd; 32];
533 for b in &mut key {
534 *b = *b >> 4 | *b << 4;
535 }
536 let expected_ino_hash_key: [u8; 16] = fscrypt_hkdf(&key, &[], HKDF_CONTEXT_INODE_HASH_KEY);
537 assert_eq!(unwrapped_key[1..17], expected_ino_hash_key);
538 let device = BlockDevice::new(
540 RemoteBlockClient::new(block_server.clone().connect::<BlockProxy>())
541 .await
542 .expect("Unable to create block client"),
543 false,
544 )
545 .await
546 .unwrap();
547
548 let plaintext: &[u8] = b"This is aligned sensitive data!!";
549 let mut buf = device.allocate_buffer(4096).await;
550 buf.as_mut_slice()[..plaintext.len()].copy_from_slice(plaintext);
551 device
552 .write_with_opts(
553 0,
554 buf.as_ref(),
555 WriteOptions {
556 inline_crypto: InlineCryptoOptions::enabled(expected_slot, 0),
557 ..Default::default()
558 },
559 )
560 .await
561 .expect("failed to write data");
562
563 let mut read_buf = device.allocate_buffer(4096).await;
564
565 device
567 .read_with_opts(0, read_buf.as_mut(), ReadOptions::default())
568 .await
569 .expect("Read failed");
570 assert_ne!(&read_buf.as_slice()[..plaintext.len()], plaintext);
571
572 let _wrapping_key_id = service.add_wrapping_key(&[0xab; 32], 0).unwrap();
576 device
577 .read_with_opts(
578 0,
579 read_buf.as_mut(),
580 ReadOptions { inline_crypto: InlineCryptoOptions::enabled(expected_slot + 1, 0) },
581 )
582 .await
583 .expect("Read failed");
584 assert_ne!(&read_buf.as_slice()[..plaintext.len()], plaintext);
585
586 device
588 .read_with_opts(
589 0,
590 read_buf.as_mut(),
591 ReadOptions { inline_crypto: InlineCryptoOptions::enabled(expected_slot + 2, 0) },
592 )
593 .await
594 .expect_err("Read passed unexpectedly with unused key slot");
595
596 device
598 .read_with_opts(
599 0,
600 read_buf.as_mut(),
601 ReadOptions { inline_crypto: InlineCryptoOptions::enabled(expected_slot, 0) },
602 )
603 .await
604 .expect("Read failed");
605 assert_eq!(&read_buf.as_slice()[..plaintext.len()], plaintext);
606 }
607
608 #[fuchsia::test]
609 fn unwrap_fxfs_wrapped_key_with_lblk32_key() {
610 let block_server = Arc::new(
611 VmoBackedServer::new(BLOCK_COUNT, BLOCK_SIZE, &[])
612 .expect("Failed to create VmoBackedServer"),
613 );
614 let (insecure_inilne_crypto_proxy, server) =
615 fidl::endpoints::create_sync_proxy::<DeviceMarker>();
616 std::thread::spawn(|| {
617 LocalExecutor::default().run_singlethreaded(async move {
618 block_server.connect_insecure_inline_encryption_server(server, TEST_UUID).await;
619 })
620 });
621
622 let service = CryptService::new(&[0; 32], &[1; 32], Some(insecure_inilne_crypto_proxy));
623 service.set_uuid(TEST_UUID);
624 let wrapping_key_id =
625 service.add_wrapping_key(&[0xcd; 32], 0).expect("add wrapping key failed");
626 let (wrapped_key, expected_unwrapped_key) = service
627 .create_key_with_id(0, wrapping_key_id, ObjectType::Directory)
628 .expect("create_key failed");
629 assert_matches!(
630 wrapped_key,
631 WrappedKey::FscryptInoLblk32Dir(FscryptKeyIdentifierAndNonce {
632 key_identifier,
633 ..
634 }) if key_identifier == wrapping_key_id
635 );
636 let unwrapped_key = service.unwrap_key(0, wrapped_key).expect("create_key failed");
637 assert_eq!(unwrapped_key, expected_unwrapped_key);
638 }
639
640 #[test]
641 fn wrap_unwrap_key() {
642 let service = CryptService::new(&[0; 32], &[0xcd; 32], None);
643
644 let (wrapping_key_id, wrapped_key, unwrapped_key) =
645 service.create_key(0, KeyPurpose::Data).expect("create_key failed");
646 let unwrap_result = service
647 .unwrap_key(
648 0,
649 WrappedKey::Fxfs(FxfsKey {
650 wrapping_key_id,
651 wrapped_key: wrapped_key.try_into().unwrap(),
652 }),
653 )
654 .expect("unwrap_key failed");
655 assert_eq!(unwrap_result, unwrapped_key);
656
657 let (wrapping_key_id, wrapped_key, unwrapped_key) =
659 service.create_key(1, KeyPurpose::Data).expect("create_key failed");
660 let unwrap_result = service
661 .unwrap_key(
662 1,
663 WrappedKey::Fxfs(FxfsKey {
664 wrapping_key_id,
665 wrapped_key: wrapped_key.try_into().unwrap(),
666 }),
667 )
668 .expect("unwrap_key failed");
669 assert_eq!(unwrap_result, unwrapped_key);
670 }
671
672 #[test]
673 fn wrap_unwrap_key_with_arbitrary_wrapping_key() {
674 let service = CryptService::new(&[0; 32], &[1; 32], None);
675
676 let wrapping_key_id =
677 service.add_wrapping_key(&[2; 32], 0).expect("add wrapping key failed");
678
679 let (wrapped_key, unwrapped_key) = service
680 .create_key_with_id(0, wrapping_key_id, ObjectType::File)
681 .expect("create_key_with_id failed");
682 match wrapped_key {
684 WrappedKey::Fxfs(fxfs_key) => {
685 let unwrap_result = service
686 .unwrap_key(
687 0,
688 WrappedKey::Fxfs(FxfsKey {
689 wrapping_key_id,
690 wrapped_key: fxfs_key.wrapped_key.try_into().unwrap(),
691 }),
692 )
693 .expect("unwrap_key failed");
694 assert_eq!(unwrap_result, unwrapped_key);
695 }
696 _ => panic!("Found a non-FxfsKey wrapped key"),
697 }
698
699 let (wrapped_key, unwrapped_key) = service
701 .create_key_with_id(1, wrapping_key_id, ObjectType::File)
702 .expect("create_key_with_id failed");
703 match wrapped_key {
705 WrappedKey::Fxfs(fxfs_key) => {
706 let unwrap_result = service
707 .unwrap_key(
708 1,
709 WrappedKey::Fxfs(FxfsKey {
710 wrapping_key_id,
711 wrapped_key: fxfs_key.wrapped_key.try_into().unwrap(),
712 }),
713 )
714 .expect("unwrap_key failed");
715 assert_eq!(unwrap_result, unwrapped_key);
716 }
717 _ => panic!("Found a non-FxfsKey wrapped key"),
718 }
719 }
720
721 #[test]
722 fn create_key_with_wrapping_key_that_does_not_exist() {
723 let service = CryptService::new(&[0; 32], &[1; 32], None);
724
725 let wrapping_key_id =
726 service.add_wrapping_key(&[2; 32], 0).expect("add wrapping key failed");
727
728 let (wrapped_key, unwrapped_key) = service
729 .create_key_with_id(0, wrapping_key_id, ObjectType::File)
730 .expect("create_key_with_id failed");
731
732 match wrapped_key {
734 WrappedKey::Fxfs(fxfs_key) => {
735 let unwrap_result = service
736 .unwrap_key(
737 0,
738 WrappedKey::Fxfs(FxfsKey {
739 wrapping_key_id,
740 wrapped_key: fxfs_key.wrapped_key.try_into().unwrap(),
741 }),
742 )
743 .expect("unwrap_key failed");
744 assert_eq!(unwrap_result, unwrapped_key);
745 }
746 _ => panic!("Found a non-FxfsKey wrapped key"),
747 }
748
749 service.forget_wrapping_key(wrapping_key_id, 0).unwrap();
750
751 service
752 .create_key_with_id(0, wrapping_key_id, ObjectType::File)
753 .expect_err("create_key_with_id should fail if the wrapping key does not exist");
754 }
755
756 #[test]
757 fn unwrap_key_wrong_key() {
758 let service = CryptService::new(&[0; 32], &[0xcd; 32], None);
759 let (wrapping_key_id, mut wrapped_key, _) =
760 service.create_key(0, KeyPurpose::Data).expect("create_key failed");
761 for byte in &mut wrapped_key {
762 *byte ^= 0xff;
763 }
764 service
765 .unwrap_key(
766 0,
767 WrappedKey::Fxfs(FxfsKey {
768 wrapping_key_id,
769 wrapped_key: wrapped_key.try_into().unwrap(),
770 }),
771 )
772 .expect_err("unwrap_key should fail");
773 }
774
775 #[test]
776 fn unwrap_key_wrong_owner() {
777 let service = CryptService::new(&[0; 32], &[0xcd; 32], None);
778
779 let (wrapping_key_id, wrapped_key, _) =
780 service.create_key(0, KeyPurpose::Data).expect("create_key failed");
781 service
782 .unwrap_key(
783 1,
784 WrappedKey::Fxfs(FxfsKey {
785 wrapping_key_id,
786 wrapped_key: wrapped_key.try_into().unwrap(),
787 }),
788 )
789 .expect_err("unwrap_key should fail");
790 }
791
792 #[fuchsia::test]
793 async fn test_add_wrapping_key_uses_raw_key() {
794 let (client, server) = fidl::endpoints::create_sync_proxy::<DeviceMarker>();
795 let raw_key_bytes = [0xAB; 32];
796 let expected_key = raw_key_bytes.clone();
797
798 std::thread::spawn(move || {
799 LocalExecutor::default().run_singlethreaded(async move {
800 let mut stream = server.into_stream();
801 while let Some(Ok(request)) = stream.next().await {
802 match request {
803 DeviceRequest::DeriveRawSecret { wrapped_key, responder } => {
804 let mut derived = wrapped_key.clone();
805 derived[0] ^= 0xFF;
806 responder.send(Ok(&derived)).unwrap();
807 }
808 DeviceRequest::ProgramKey { wrapped_key, responder, .. } => {
809 if wrapped_key == expected_key {
810 responder.send(Ok(0)).unwrap();
811 } else {
812 responder.send(Err(zx::Status::INVALID_ARGS.into_raw())).unwrap();
813 }
814 }
815 }
816 }
817 })
818 });
819
820 let service = CryptService::new(&[0; 32], &[1; 32], Some(client));
821 service.add_wrapping_key(&raw_key_bytes, 0).expect("add_wrapping_key failed");
822 }
823}