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