fxfs_crypt/
lib.rs

1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use aes_gcm_siv::aead::Aead;
6use aes_gcm_siv::{Aes256GcmSiv, Key, KeyInit as _, Nonce};
7use anyhow::{Context, Error};
8use fidl_fuchsia_fxfs::{
9    CryptCreateKeyResult, CryptCreateKeyWithIdResult, CryptManagementAddWrappingKeyResult,
10    CryptManagementForgetWrappingKeyResult, CryptManagementRequest, CryptManagementRequestStream,
11    CryptManagementSetActiveKeyResult, CryptRequest, CryptRequestStream, CryptUnwrapKeyResult,
12    FxfsWrapped, KeyPurpose, WrappedKey,
13};
14
15use fuchsia_sync::Mutex;
16use futures::stream::TryStreamExt;
17use std::collections::hash_map::{Entry, HashMap};
18
19pub mod log;
20use log::*;
21
22pub enum Services {
23    Crypt(CryptRequestStream),
24    CryptManagement(CryptManagementRequestStream),
25}
26
27#[derive(Default)]
28struct CryptServiceInner {
29    ciphers: HashMap<u128, Aes256GcmSiv>,
30    active_data_key: Option<u128>,
31    active_metadata_key: Option<u128>,
32}
33
34pub struct CryptService {
35    inner: Mutex<CryptServiceInner>,
36}
37
38fn zero_extended_nonce(val: u64) -> Nonce {
39    let mut nonce = Nonce::default();
40    nonce.as_mut_slice()[..8].copy_from_slice(&val.to_le_bytes());
41    nonce
42}
43
44impl CryptService {
45    pub fn new() -> Self {
46        Self { inner: Mutex::new(CryptServiceInner::default()) }
47    }
48
49    fn create_key(&self, owner: u64, purpose: KeyPurpose) -> CryptCreateKeyResult {
50        let inner = self.inner.lock();
51        let wrapping_key_id = match purpose {
52            KeyPurpose::Data => inner.active_data_key.as_ref(),
53            KeyPurpose::Metadata => inner.active_metadata_key.as_ref(),
54            _ => return Err(zx::Status::INVALID_ARGS.into_raw()),
55        }
56        .ok_or_else(|| zx::Status::BAD_STATE.into_raw())?;
57        let cipher =
58            inner.ciphers.get(wrapping_key_id).ok_or_else(|| zx::Status::BAD_STATE.into_raw())?;
59        let nonce = zero_extended_nonce(owner);
60
61        let mut key = [0u8; 32];
62        zx::cprng_draw(&mut key);
63
64        let wrapped = cipher.encrypt(&nonce, &key[..]).map_err(|e| {
65            error!(error:? = e; "Failed to wrap key");
66            zx::Status::INTERNAL.into_raw()
67        })?;
68
69        Ok((wrapping_key_id.to_le_bytes(), wrapped.into(), key.into()))
70    }
71
72    fn create_key_with_id(&self, owner: u64, wrapping_key_id: u128) -> CryptCreateKeyWithIdResult {
73        let inner = self.inner.lock();
74        let cipher =
75            inner.ciphers.get(&wrapping_key_id).ok_or_else(|| zx::Status::NOT_FOUND.into_raw())?;
76        let nonce = zero_extended_nonce(owner);
77
78        let mut key = [0u8; 32];
79        zx::cprng_draw(&mut key);
80
81        let wrapped = cipher.encrypt(&nonce, &key[..]).map_err(|error| {
82            error!(error:?; "Failed to wrap key");
83            zx::Status::INTERNAL.into_raw()
84        })?;
85
86        Ok((wrapped.into(), key.into()))
87    }
88
89    fn unwrap_key(&self, owner: u64, wrapped_key: WrappedKey) -> CryptUnwrapKeyResult {
90        match wrapped_key {
91            WrappedKey::FxfsWrapped(FxfsWrapped { wrapping_key_id, wrapped_key }) => {
92                let wrapping_key_id = u128::from_le_bytes(wrapping_key_id);
93                let inner = self.inner.lock();
94                let cipher = inner
95                    .ciphers
96                    .get(&wrapping_key_id)
97                    .ok_or_else(|| zx::Status::NOT_FOUND.into_raw())?;
98                let nonce = zero_extended_nonce(owner);
99
100                Ok(cipher
101                    .decrypt(&nonce, &wrapped_key[..])
102                    .map_err(|_| zx::Status::IO_DATA_INTEGRITY.into_raw())?)
103            }
104            _ => Err(zx::Status::NOT_SUPPORTED.into_raw()),
105        }
106    }
107
108    pub fn add_wrapping_key(
109        &self,
110        wrapping_key_id: u128,
111        key: Vec<u8>,
112    ) -> CryptManagementAddWrappingKeyResult {
113        let mut inner = self.inner.lock();
114        match inner.ciphers.entry(wrapping_key_id) {
115            Entry::Occupied(_) => Err(zx::Status::ALREADY_EXISTS.into_raw()),
116            Entry::Vacant(vacant) => {
117                info!(wrapping_key_id; "Adding wrapping key");
118                vacant.insert(Aes256GcmSiv::new(Key::<Aes256GcmSiv>::from_slice(&key[..])));
119                Ok(())
120            }
121        }
122    }
123
124    pub fn set_active_key(
125        &self,
126        purpose: KeyPurpose,
127        wrapping_key_id: u128,
128    ) -> CryptManagementSetActiveKeyResult {
129        let mut inner = self.inner.lock();
130        if !inner.ciphers.contains_key(&wrapping_key_id) {
131            return Err(zx::Status::NOT_FOUND.into_raw());
132        }
133        match purpose {
134            KeyPurpose::Data => inner.active_data_key = Some(wrapping_key_id),
135            KeyPurpose::Metadata => inner.active_metadata_key = Some(wrapping_key_id),
136            _ => return Err(zx::Status::INVALID_ARGS.into_raw()),
137        }
138        Ok(())
139    }
140
141    fn forget_wrapping_key(&self, wrapping_key_id: u128) -> CryptManagementForgetWrappingKeyResult {
142        info!(wrapping_key_id; "Removing wrapping key");
143        let mut inner = self.inner.lock();
144        if let Some(id) = &inner.active_data_key {
145            if *id == wrapping_key_id {
146                return Err(zx::Status::INVALID_ARGS.into_raw());
147            }
148        }
149        if let Some(id) = &inner.active_metadata_key {
150            if *id == wrapping_key_id {
151                return Err(zx::Status::INVALID_ARGS.into_raw());
152            }
153        }
154        inner.ciphers.remove(&wrapping_key_id);
155        Ok(())
156    }
157
158    pub async fn handle_request(&self, stream: Services) -> Result<(), Error> {
159        match stream {
160            Services::Crypt(mut stream) => {
161                while let Some(request) = stream.try_next().await.context("Reading request")? {
162                    match request {
163                        CryptRequest::CreateKey { owner, purpose, responder } => {
164                            responder
165                                .send(match &self.create_key(owner, purpose) {
166                                    Ok((id, ref wrapped, ref key)) => Ok((id, wrapped, key)),
167                                    Err(e) => Err(*e),
168                                })
169                                .unwrap_or_else(|e| {
170                                    // TODO(https://fxbug.dev/360919323): we can use `:err` when we
171                                    // enable the log kv_std feature.
172                                    error!(
173                                        error:? = e;
174                                        "Failed to send CreateKey response"
175                                    )
176                                });
177                        }
178                        CryptRequest::CreateKeyWithId { owner, wrapping_key_id, responder } => {
179                            responder
180                                .send(
181                                    match self.create_key_with_id(
182                                        owner,
183                                        u128::from_le_bytes(wrapping_key_id),
184                                    ) {
185                                        Ok((ref wrapped, ref key)) => Ok((wrapped, key)),
186                                        Err(e) => Err(e),
187                                    },
188                                )
189                                .unwrap_or_else(|e| {
190                                    // TODO(https://fxbug.dev/360919323): we can use `:err` when we
191                                    // enable the log kv_std feature.
192                                    error!(
193                                        error:? = e;
194                                        "Failed to send CreateKeyWithId response"
195                                    )
196                                });
197                        }
198                        CryptRequest::UnwrapKey { owner, wrapped_key, responder } => {
199                            let response;
200                            responder
201                                .send({
202                                    response = self.unwrap_key(owner, wrapped_key);
203                                    match &response {
204                                        Ok(v) => Ok(&v[..]),
205                                        Err(e) => Err(*e),
206                                    }
207                                })
208                                .unwrap_or_else(|e| {
209                                    // TODO(https://fxbug.dev/360919323): we can use `:err` when we
210                                    // enable the log kv_std feature.
211                                    error!(
212                                        error:? = e;
213                                        "Failed to send UnwrapKey response"
214                                    )
215                                });
216                        }
217                    }
218                }
219            }
220            Services::CryptManagement(mut stream) => {
221                while let Some(request) = stream.try_next().await.context("Reading request")? {
222                    match request {
223                        CryptManagementRequest::AddWrappingKey {
224                            wrapping_key_id,
225                            key,
226                            responder,
227                        } => {
228                            let response =
229                                self.add_wrapping_key(u128::from_le_bytes(wrapping_key_id), key);
230                            responder.send(response).unwrap_or_else(|e| {
231                                // TODO(https://fxbug.dev/360919323): we can use `:err` when we
232                                // enable the log kv_std feature.
233                                error!(
234                                    error:? = e;
235                                    "Failed to send AddWrappingKey response"
236                                )
237                            });
238                        }
239                        CryptManagementRequest::SetActiveKey {
240                            purpose,
241                            wrapping_key_id,
242                            responder,
243                        } => {
244                            let response =
245                                self.set_active_key(purpose, u128::from_le_bytes(wrapping_key_id));
246                            responder.send(response).unwrap_or_else(
247                                // TODO(https://fxbug.dev/360919323): we can use `:err` when we
248                                // enable the log kv_std feature.
249                                |e| error!(error:? = e;"Failed to send SetActiveKey response"),
250                            );
251                        }
252                        CryptManagementRequest::ForgetWrappingKey {
253                            wrapping_key_id,
254                            responder,
255                        } => {
256                            let response =
257                                self.forget_wrapping_key(u128::from_le_bytes(wrapping_key_id));
258                            responder.send(response).unwrap_or_else(|e| {
259                                // TODO(https://fxbug.dev/360919323): we can use `:err` when we
260                                // enable the log kv_std feature.
261                                error!(
262                                    error:? = e;
263                                    "Failed to send ForgetWrappingKey response"
264                                )
265                            });
266                        }
267                    }
268                }
269            }
270        }
271        Ok(())
272    }
273}
274
275#[cfg(test)]
276mod tests {
277    use super::CryptService;
278    use fidl_fuchsia_fxfs::{FxfsWrapped, KeyPurpose, WrappedKey};
279
280    #[test]
281    fn wrap_unwrap_key() {
282        let service = CryptService::new();
283        let key = vec![0xABu8; 32];
284        service.add_wrapping_key(1, key.clone()).expect("add_key failed");
285        service.set_active_key(KeyPurpose::Data, 1).expect("set_active_key failed");
286
287        let (wrapping_key_id, wrapped_key, unwrapped_key) =
288            service.create_key(0, KeyPurpose::Data).expect("create_key failed");
289        let wrapping_key_id_int = u128::from_le_bytes(wrapping_key_id);
290        assert_eq!(wrapping_key_id_int, 1);
291        let unwrap_result = service
292            .unwrap_key(
293                0,
294                WrappedKey::FxfsWrapped(FxfsWrapped {
295                    wrapping_key_id,
296                    wrapped_key: wrapped_key.try_into().unwrap(),
297                }),
298            )
299            .expect("unwrap_key failed");
300        assert_eq!(unwrap_result, unwrapped_key);
301
302        // Do it twice to make sure the service can use the same key repeatedly.
303        let (wrapping_key_id, wrapped_key, unwrapped_key) =
304            service.create_key(1, KeyPurpose::Data).expect("create_key failed");
305        let wrapping_key_id_int = u128::from_le_bytes(wrapping_key_id);
306        assert_eq!(wrapping_key_id_int, 1);
307        let unwrap_result = service
308            .unwrap_key(
309                1,
310                WrappedKey::FxfsWrapped(FxfsWrapped {
311                    wrapping_key_id,
312                    wrapped_key: wrapped_key.try_into().unwrap(),
313                }),
314            )
315            .expect("unwrap_key failed");
316        assert_eq!(unwrap_result, unwrapped_key);
317    }
318
319    #[test]
320    fn wrap_unwrap_key_with_arbitrary_wrapping_key() {
321        let service = CryptService::new();
322        let key = vec![0xABu8; 32];
323        service.add_wrapping_key(2, key.clone()).expect("add_key failed");
324
325        let (wrapped_key, unwrapped_key) =
326            service.create_key_with_id(0, 2).expect("create_key_with_id failed");
327        let unwrap_result = service
328            .unwrap_key(
329                0,
330                WrappedKey::FxfsWrapped(FxfsWrapped {
331                    wrapping_key_id: 2u128.to_le_bytes(),
332                    wrapped_key: wrapped_key.try_into().unwrap(),
333                }),
334            )
335            .expect("unwrap_key failed");
336        assert_eq!(unwrap_result, unwrapped_key);
337
338        // Do it twice to make sure the service can use the same key repeatedly.
339        let (wrapped_key, unwrapped_key) =
340            service.create_key_with_id(1, 2).expect("create_key_with_id failed");
341        let unwrap_result = service
342            .unwrap_key(
343                1,
344                WrappedKey::FxfsWrapped(FxfsWrapped {
345                    wrapping_key_id: 2u128.to_le_bytes(),
346                    wrapped_key: wrapped_key.try_into().unwrap(),
347                }),
348            )
349            .expect("unwrap_key failed");
350        assert_eq!(unwrap_result, unwrapped_key);
351    }
352
353    #[test]
354    fn create_key_with_wrapping_key_that_does_not_exist() {
355        let service = CryptService::new();
356        service
357            .create_key_with_id(0, 2)
358            .expect_err("create_key_with_id should fail if the wrapping key does not exist");
359
360        let wrapping_key = vec![0xABu8; 32];
361        service.add_wrapping_key(2, wrapping_key.clone()).expect("add_key failed");
362
363        let (wrapped_key, unwrapped_key) =
364            service.create_key_with_id(0, 2).expect("create_key_with_id failed");
365        let unwrap_result = service
366            .unwrap_key(
367                0,
368                WrappedKey::FxfsWrapped(FxfsWrapped {
369                    wrapping_key_id: 2u128.to_le_bytes(),
370                    wrapped_key: wrapped_key.try_into().unwrap(),
371                }),
372            )
373            .expect("unwrap_key failed");
374        assert_eq!(unwrap_result, unwrapped_key);
375    }
376
377    #[test]
378    fn unwrap_key_wrong_key() {
379        let service = CryptService::new();
380        let key = vec![0xABu8; 32];
381        service.add_wrapping_key(0, key.clone()).expect("add_key failed");
382        service.set_active_key(KeyPurpose::Data, 0).expect("set_active_key failed");
383
384        let (wrapping_key_id, mut wrapped_key, _) =
385            service.create_key(0, KeyPurpose::Data).expect("create_key failed");
386        for byte in &mut wrapped_key {
387            *byte ^= 0xff;
388        }
389        service
390            .unwrap_key(
391                0,
392                WrappedKey::FxfsWrapped(FxfsWrapped {
393                    wrapping_key_id,
394                    wrapped_key: wrapped_key.try_into().unwrap(),
395                }),
396            )
397            .expect_err("unwrap_key should fail");
398    }
399
400    #[test]
401    fn unwrap_key_wrong_owner() {
402        let service = CryptService::new();
403        let key = vec![0xABu8; 32];
404        service.add_wrapping_key(0, key.clone()).expect("add_key failed");
405        service.set_active_key(KeyPurpose::Data, 0).expect("set_active_key failed");
406
407        let (wrapping_key_id, wrapped_key, _) =
408            service.create_key(0, KeyPurpose::Data).expect("create_key failed");
409        service
410            .unwrap_key(
411                1,
412                WrappedKey::FxfsWrapped(FxfsWrapped {
413                    wrapping_key_id,
414                    wrapped_key: wrapped_key.try_into().unwrap(),
415                }),
416            )
417            .expect_err("unwrap_key should fail");
418    }
419
420    #[test]
421    fn add_forget_key() {
422        let service = CryptService::new();
423        let key = vec![0xABu8; 32];
424        service.add_wrapping_key(0, key.clone()).expect("add_key failed");
425        service.add_wrapping_key(0, key.clone()).expect_err("add_key should fail on a used slot");
426        service.add_wrapping_key(1, key.clone()).expect("add_key failed");
427
428        service.forget_wrapping_key(0).expect("forget_key failed");
429
430        service.add_wrapping_key(0, key.clone()).expect("add_key failed");
431    }
432
433    #[test]
434    fn set_active_key() {
435        let service = CryptService::new();
436        let key = vec![0xABu8; 32];
437
438        service
439            .set_active_key(KeyPurpose::Data, 0)
440            .expect_err("set_active_key should fail when targeting nonexistent keys");
441
442        service.add_wrapping_key(0, key.clone()).expect("add_key failed");
443        service.add_wrapping_key(1, key.clone()).expect("add_key failed");
444
445        service.set_active_key(KeyPurpose::Data, 0).expect("set_active_key failed");
446        service.set_active_key(KeyPurpose::Metadata, 1).expect("set_active_key failed");
447
448        service.forget_wrapping_key(0).expect_err("forget_key should fail on an active key");
449        service.forget_wrapping_key(1).expect_err("forget_key should fail on an active key");
450    }
451}