fxfs_insecure_crypto/
lib.rs

1// Copyright 2023 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 async_trait::async_trait;
8use fuchsia_sync::Mutex;
9use fxfs_crypto::{Crypt, KeyPurpose, UnwrappedKey, WrappedKey, WrappedKeyBytes};
10use log::error;
11use rand::rngs::StdRng;
12use rand::{RngCore, SeedableRng};
13use rustc_hash::FxHashMap as HashMap;
14use std::sync::atomic::{AtomicBool, Ordering};
15use zx_status as zx;
16
17pub const DATA_KEY: [u8; 32] = [
18    0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11,
19    0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
20];
21pub const METADATA_KEY: [u8; 32] = [
22    0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
23    0xef, 0xee, 0xed, 0xec, 0xeb, 0xea, 0xe9, 0xe8, 0xe7, 0xe6, 0xe5, 0xe4, 0xe3, 0xe2, 0xe1, 0xe0,
24];
25
26/// This struct provides the `Crypt` trait without any strong security.
27///
28/// It is intended for use only in test code where actual security is inconsequential.
29#[derive(Default)]
30pub struct InsecureCrypt {
31    ciphers: Mutex<HashMap<u128, Aes256GcmSiv>>,
32    active_data_key: Option<u128>,
33    active_metadata_key: Option<u128>,
34    shutdown: AtomicBool,
35}
36impl InsecureCrypt {
37    pub fn new() -> Self {
38        Self {
39            ciphers: Mutex::new(HashMap::from_iter([
40                (0, Aes256GcmSiv::new(Key::<Aes256GcmSiv>::from_slice(&DATA_KEY))),
41                (1, Aes256GcmSiv::new(Key::<Aes256GcmSiv>::from_slice(&METADATA_KEY))),
42            ])),
43            active_data_key: Some(0),
44            active_metadata_key: Some(1),
45            ..Default::default()
46        }
47    }
48
49    /// Simulates a crypt instance prematurely terminating.  All requests will fail.
50    pub fn shutdown(&self) {
51        self.shutdown.store(true, Ordering::Relaxed);
52    }
53
54    pub fn add_wrapping_key(&self, id: u128, key: [u8; 32]) {
55        self.ciphers.lock().insert(id, Aes256GcmSiv::new(Key::<Aes256GcmSiv>::from_slice(&key)));
56    }
57
58    pub fn remove_wrapping_key(&self, id: u128) {
59        let _key = self.ciphers.lock().remove(&id);
60    }
61}
62
63#[async_trait]
64impl Crypt for InsecureCrypt {
65    async fn create_key(
66        &self,
67        owner: u64,
68        purpose: KeyPurpose,
69    ) -> Result<(WrappedKey, UnwrappedKey), zx::Status> {
70        if self.shutdown.load(Ordering::Relaxed) {
71            error!("Crypt was shut down");
72            return Err(zx::Status::INTERNAL);
73        }
74        let wrapping_key_id = match purpose {
75            KeyPurpose::Data => self.active_data_key.as_ref(),
76            KeyPurpose::Metadata => self.active_metadata_key.as_ref(),
77        }
78        .ok_or(zx::Status::INVALID_ARGS)?;
79        let ciphers = self.ciphers.lock();
80        let cipher = ciphers.get(wrapping_key_id).ok_or(zx::Status::NOT_FOUND)?;
81        let mut nonce = Nonce::default();
82        nonce.as_mut_slice()[..8].copy_from_slice(&owner.to_le_bytes());
83
84        let mut key = [0u8; 32];
85        StdRng::from_entropy().fill_bytes(&mut key);
86
87        let wrapped: Vec<u8> = cipher.encrypt(&nonce, &key[..]).map_err(|e| {
88            error!("Failed to wrap key: {:?}", e);
89            zx::Status::INTERNAL
90        })?;
91        let wrapped = WrappedKeyBytes::try_from(wrapped).map_err(|_| zx::Status::INTERNAL)?;
92        Ok((WrappedKey { wrapping_key_id: *wrapping_key_id, key: wrapped }, UnwrappedKey::new(key)))
93    }
94
95    async fn create_key_with_id(
96        &self,
97        owner: u64,
98        wrapping_key_id: u128,
99    ) -> Result<(WrappedKey, UnwrappedKey), zx::Status> {
100        if self.shutdown.load(Ordering::Relaxed) {
101            error!("Crypt was shut down");
102            return Err(zx::Status::INTERNAL);
103        }
104        let ciphers = self.ciphers.lock();
105        let cipher = ciphers.get(&(wrapping_key_id as u128)).ok_or(zx::Status::NOT_FOUND)?;
106        let mut nonce = Nonce::default();
107        nonce.as_mut_slice()[..8].copy_from_slice(&owner.to_le_bytes());
108
109        let mut key = [0u8; 32];
110        StdRng::from_entropy().fill_bytes(&mut key);
111
112        let wrapped: Vec<u8> = cipher.encrypt(&nonce, &key[..]).map_err(|e| {
113            error!("Failed to wrap key: {:?}", e);
114            zx::Status::INTERNAL
115        })?;
116        let wrapped = WrappedKeyBytes::try_from(wrapped).map_err(|_| zx::Status::BAD_STATE)?;
117        Ok((
118            WrappedKey { wrapping_key_id: wrapping_key_id as u128, key: wrapped },
119            UnwrappedKey::new(key),
120        ))
121    }
122    async fn unwrap_key(
123        &self,
124        wrapped_key: &WrappedKey,
125        owner: u64,
126    ) -> Result<UnwrappedKey, zx::Status> {
127        if self.shutdown.load(Ordering::Relaxed) {
128            error!("Crypt was shut down");
129            return Err(zx::Status::INTERNAL);
130        }
131        let ciphers = self.ciphers.lock();
132        let cipher = ciphers.get(&wrapped_key.wrapping_key_id).ok_or(zx::Status::NOT_FOUND)?;
133        let mut nonce = Nonce::default();
134        nonce.as_mut_slice()[..8].copy_from_slice(&owner.to_le_bytes());
135        Ok(UnwrappedKey::new(
136            cipher
137                .decrypt(&nonce, &wrapped_key.key.0[..])
138                .map_err(|e| {
139                    error!("unwrap keys failed: {:?}", e);
140                    zx::Status::INTERNAL
141                })?
142                .try_into()
143                .map_err(|_| {
144                    error!("Unexpected wrapped key length");
145                    zx::Status::INTERNAL
146                })?,
147        ))
148    }
149}