| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| use crate::crypto_provider::{ |
| mundane_provider::MundaneSoftwareProvider, AsymmetricProviderKey, CryptoProvider, |
| CryptoProviderError, ProviderKey, SealingProviderKey, |
| }; |
| use bincode; |
| use crypto::{aead::AeadDecryptor, aead::AeadEncryptor, aes::KeySize, aes_gcm::AesGcm}; |
| use fidl_fuchsia_kms::{AsymmetricKeyAlgorithm, KeyProvider}; |
| use mundane; |
| use serde::{Deserialize, Serialize}; |
| use serde_json; |
| use std::convert::{TryFrom, TryInto}; |
| |
| const AES_KEY_SIZE: usize = 32; |
| const AES_IV_SIZE: usize = 12; |
| const AES_TAG_SIZE: usize = 16; |
| |
| /// SoftwareProvider is a software based provider that supports symmetric and asymmetric operations. |
| /// |
| /// SoftwareProvider uses MundaneSoftwareProvider for asymmetric operations and uses rust crypto |
| /// aes_gcm crate for sealing/unsealing operation. The key data is the plain text key material, so |
| /// its security depends on the security of the KMS module. |
| #[derive(Debug, Clone)] |
| pub struct SoftwareProvider { |
| mundane_provider: MundaneSoftwareProvider, |
| } |
| |
| impl SoftwareProvider { |
| pub fn new() -> Self { |
| SoftwareProvider { mundane_provider: MundaneSoftwareProvider {} } |
| } |
| } |
| |
| #[derive(Serialize, Deserialize, Debug)] |
| struct AesKey { |
| key: [u8; AES_KEY_SIZE], |
| } |
| |
| #[derive(Serialize, Deserialize, Debug)] |
| struct EncryptedData { |
| iv: [u8; AES_IV_SIZE], |
| cipher_text: Vec<u8>, |
| tag: [u8; AES_TAG_SIZE], |
| } |
| |
| #[derive(Debug)] |
| struct SoftwareSealingKey { |
| key_data: Vec<u8>, |
| inner_key: AesKey, |
| } |
| |
| impl SoftwareSealingKey { |
| pub fn new(inner_key: AesKey) -> Result<Self, CryptoProviderError> { |
| let key_data = serde_json::to_vec(&inner_key).map_err(|err| { |
| CryptoProviderError::new(&format!( |
| "failed to marshal software sealing key as JSON: {:?}", |
| err |
| )) |
| })?; |
| Ok(SoftwareSealingKey { key_data, inner_key }) |
| } |
| } |
| |
| impl ProviderKey for SoftwareSealingKey { |
| fn delete(&mut self) -> Result<(), CryptoProviderError> { |
| Ok(()) |
| } |
| fn get_key_data(&self) -> Vec<u8> { |
| self.key_data.clone() |
| } |
| fn get_key_provider(&self) -> KeyProvider { |
| (SoftwareProvider::new()).get_name() |
| } |
| } |
| |
| impl SealingProviderKey for SoftwareSealingKey { |
| fn encrypt(&self, data: &[u8]) -> Result<Vec<u8>, CryptoProviderError> { |
| let inner_key = &self.inner_key; |
| let mut iv = [0; AES_IV_SIZE]; |
| mundane::bytes::rand(&mut iv); |
| // We use empty Additional Authentication Data (AAD). |
| let mut key = AesGcm::new(KeySize::KeySize256, &inner_key.key, &iv, &[]); |
| let mut cipher_text = vec![0; data.len()]; |
| let mut tag = [0; AES_TAG_SIZE]; |
| key.encrypt(data, &mut cipher_text, &mut tag); |
| let output = |
| bincode::serialize(&EncryptedData { iv, cipher_text, tag }).map_err(|err| { |
| CryptoProviderError::new(&format!("failed to serialize encrypted data: {:?}", err)) |
| })?; |
| Ok(output) |
| } |
| |
| fn decrypt(&self, data: &[u8]) -> Result<Vec<u8>, CryptoProviderError> { |
| let inner_key = &self.inner_key; |
| let encrypted_data: EncryptedData = bincode::deserialize(data).map_err(|err| { |
| CryptoProviderError::new(&format!("failed to deserialize encrypted data: {:?}", err)) |
| })?; |
| // We use empty Additional Authentication Data (AAD). |
| let mut key = AesGcm::new(KeySize::KeySize256, &inner_key.key, &encrypted_data.iv, &[]); |
| let mut plain_text = vec![0; encrypted_data.cipher_text.len()]; |
| if !key.decrypt(&encrypted_data.cipher_text, &mut plain_text, &encrypted_data.tag) { |
| Err(CryptoProviderError::new("failed to decrypt data")) |
| } else { |
| Ok(plain_text) |
| } |
| } |
| } |
| |
| #[derive(Debug)] |
| pub struct SoftwareAsymmetricPrivateKey { |
| mundane_key: Box<dyn AsymmetricProviderKey>, |
| } |
| |
| impl ProviderKey for SoftwareAsymmetricPrivateKey { |
| fn delete(&mut self) -> Result<(), CryptoProviderError> { |
| self.mundane_key.delete() |
| } |
| fn get_key_data(&self) -> Vec<u8> { |
| self.mundane_key.get_key_data() |
| } |
| fn get_key_provider(&self) -> KeyProvider { |
| SoftwareProvider::new().get_name() |
| } |
| } |
| |
| impl AsymmetricProviderKey for SoftwareAsymmetricPrivateKey { |
| fn sign(&self, data: &[u8]) -> Result<Vec<u8>, CryptoProviderError> { |
| self.mundane_key.sign(data) |
| } |
| |
| fn get_der_public_key(&self) -> Result<Vec<u8>, CryptoProviderError> { |
| self.mundane_key.get_der_public_key() |
| } |
| |
| fn get_key_algorithm(&self) -> AsymmetricKeyAlgorithm { |
| self.mundane_key.get_key_algorithm() |
| } |
| } |
| |
| impl CryptoProvider for SoftwareProvider { |
| fn supported_asymmetric_algorithms(&self) -> &'static [AsymmetricKeyAlgorithm] { |
| self.mundane_provider.supported_asymmetric_algorithms() |
| } |
| |
| fn get_name(&self) -> KeyProvider { |
| KeyProvider::SoftwareProvider |
| } |
| fn box_clone(&self) -> Box<dyn CryptoProvider> { |
| Box::new(SoftwareProvider::new()) |
| } |
| fn generate_asymmetric_key( |
| &self, |
| key_algorithm: AsymmetricKeyAlgorithm, |
| key_name: &str, |
| ) -> Result<Box<dyn AsymmetricProviderKey>, CryptoProviderError> { |
| let mundane_key = self.mundane_provider.generate_asymmetric_key(key_algorithm, key_name)?; |
| Ok(Box::new(SoftwareAsymmetricPrivateKey { mundane_key })) |
| } |
| fn import_asymmetric_key( |
| &self, |
| key_data: &[u8], |
| key_algorithm: AsymmetricKeyAlgorithm, |
| key_name: &str, |
| ) -> Result<Box<dyn AsymmetricProviderKey>, CryptoProviderError> { |
| let mundane_key = |
| self.mundane_provider.import_asymmetric_key(key_data, key_algorithm, key_name)?; |
| Ok(Box::new(SoftwareAsymmetricPrivateKey { mundane_key })) |
| } |
| |
| fn parse_asymmetric_key( |
| &self, |
| key_data: &[u8], |
| key_algorithm: AsymmetricKeyAlgorithm, |
| ) -> Result<Box<dyn AsymmetricProviderKey>, CryptoProviderError> { |
| let mundane_key = self.mundane_provider.parse_asymmetric_key(key_data, key_algorithm)?; |
| Ok(Box::new(SoftwareAsymmetricPrivateKey { mundane_key })) |
| } |
| fn generate_sealing_key( |
| &self, |
| _key_name: &str, |
| ) -> Result<Box<dyn SealingProviderKey>, CryptoProviderError> { |
| let mut key = [0; AES_KEY_SIZE]; |
| mundane::bytes::rand(&mut key); |
| let inner_key = AesKey { key }; |
| let sealing_key = SoftwareSealingKey::new(inner_key)?; |
| Ok(Box::new(sealing_key)) |
| } |
| fn parse_sealing_key( |
| &self, |
| key_data: &[u8], |
| ) -> Result<Box<dyn SealingProviderKey>, CryptoProviderError> { |
| let inner_key = serde_json::from_slice(key_data).map_err(|err| { |
| CryptoProviderError::new(&format!("failed to parse key data: {:?}", err)) |
| })?; |
| Ok(Box::new(SoftwareSealingKey { key_data: key_data.to_vec(), inner_key })) |
| } |
| |
| fn calculate_sealed_data_size( |
| &self, |
| original_data_size: u64, |
| ) -> Result<u64, CryptoProviderError> { |
| let data_size = usize::try_from(original_data_size).map_err(|err| { |
| CryptoProviderError::new(&format!( |
| "failed to convert original data size to usize: {:?}", |
| err |
| )) |
| })?; |
| let fake_encrypted_data = EncryptedData { |
| iv: [0; AES_IV_SIZE], |
| cipher_text: vec![0; data_size], |
| tag: [0; AES_TAG_SIZE], |
| }; |
| let fake_sealed_data = bincode::serialize(&fake_encrypted_data).map_err(|err| { |
| CryptoProviderError::new(&format!( |
| "failed to serialize encrypted data to calculate size: {:?}", |
| err |
| )) |
| })?; |
| usize::try_into(fake_sealed_data.len()).map_err(|err| { |
| CryptoProviderError::new(&format!( |
| "failed to convert sealed data size to u64: {:?}", |
| err |
| )) |
| }) |
| } |
| } |
| |
| #[cfg(test)] |
| mod tests { |
| use super::*; |
| use crate::common; |
| static TEST_KEY_NAME: &str = "TestKey"; |
| |
| #[test] |
| fn test_generate_sealing_key_different_each_time() { |
| let software_provider = SoftwareProvider::new(); |
| let sealing_key_one = software_provider.generate_sealing_key(TEST_KEY_NAME).unwrap(); |
| let sealing_key_two = software_provider.generate_sealing_key(TEST_KEY_NAME).unwrap(); |
| // Generating two different sealing key should get different key data. |
| assert_ne!(sealing_key_one.get_key_data(), sealing_key_two.get_key_data()); |
| } |
| |
| #[test] |
| // We need to make sure we use different iv for each encryption, so encrypting same data |
| // multiple times would generate different result. |
| fn test_sealed_data_different_each_time() { |
| let software_provider = SoftwareProvider::new(); |
| let sealing_key = software_provider.generate_sealing_key(TEST_KEY_NAME).unwrap(); |
| let data = common::generate_random_data(256); |
| let encrypted_data_one = sealing_key.encrypt(&data).unwrap(); |
| let encrypted_data_two = sealing_key.encrypt(&data).unwrap(); |
| assert_ne!(encrypted_data_one, encrypted_data_two); |
| } |
| |
| #[test] |
| fn test_sealing_key_encrypt_decrypt() { |
| let software_provider = SoftwareProvider::new(); |
| let sealing_key = software_provider.generate_sealing_key(TEST_KEY_NAME).unwrap(); |
| let data = common::generate_random_data(256); |
| let encrypted_data = sealing_key.encrypt(&data).unwrap(); |
| let decrypted_data = sealing_key.decrypt(&encrypted_data).unwrap(); |
| // Decrypt an encrypted data should get the original data. |
| assert_eq!(data, decrypted_data); |
| } |
| |
| #[test] |
| fn test_parse_sealing_key() { |
| let software_provider = SoftwareProvider::new(); |
| let sealing_key = software_provider.generate_sealing_key(TEST_KEY_NAME).unwrap(); |
| let data = common::generate_random_data(256); |
| let encrypted_data = sealing_key.encrypt(&data).unwrap(); |
| let key_data = sealing_key.get_key_data(); |
| // Generate a new sealing key using the same key data. |
| let new_sealing_key = software_provider.parse_sealing_key(&key_data).unwrap(); |
| assert_eq!(key_data, new_sealing_key.get_key_data()); |
| // The encrypted data encrypted by the previous key should be decrypted by the new key. |
| let decrypted_data = new_sealing_key.decrypt(&encrypted_data).unwrap(); |
| assert_eq!(data, decrypted_data); |
| } |
| |
| #[test] |
| fn test_caculate_sealed_data_size() { |
| let software_provider = SoftwareProvider::new(); |
| let sealing_key = software_provider.generate_sealing_key(TEST_KEY_NAME).unwrap(); |
| let data = common::generate_random_data(256); |
| let encrypted_data = sealing_key.encrypt(&data).unwrap(); |
| // Calculating sealed data size for MAX_DATA_SIZE should be OK. |
| let sealed_data_size = software_provider.calculate_sealed_data_size(256).unwrap(); |
| assert_eq!(encrypted_data.len(), sealed_data_size as usize); |
| } |
| } |