1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 //! Implementation of the `IHwCryptoOperations` AIDL interface. It can be use to retrieve the 18 //! key generation interface and to process cryptographic operations. 19 20 use android_hardware_security_see_hwcrypto::aidl::android::hardware::security::see::hwcrypto::{ 21 CryptoOperationErrorAdditionalInfo::CryptoOperationErrorAdditionalInfo, 22 CryptoOperationResult::CryptoOperationResult, CryptoOperationSet::CryptoOperationSet, 23 IHwCryptoOperations::BnHwCryptoOperations, IHwCryptoOperations::IHwCryptoOperations, 24 }; 25 use android_hardware_security_see_hwcrypto::binder; 26 use hwcryptohal_common::hwcrypto_err; 27 28 use crate::cmd_processing::CmdProcessorContext; 29 use crate::crypto_operation_context::{BinderCryptoOperationContext, CryptoOperationContext}; 30 31 /// The `IHwCryptoOperations` implementation. 32 pub struct HwCryptoOperations; 33 34 impl binder::Interface for HwCryptoOperations {} 35 36 impl HwCryptoOperations { new_binder() -> binder::Strong<dyn IHwCryptoOperations>37 pub(crate) fn new_binder() -> binder::Strong<dyn IHwCryptoOperations> { 38 let hwcrypto_operations = HwCryptoOperations; 39 BnHwCryptoOperations::new_binder(hwcrypto_operations, binder::BinderFeatures::default()) 40 } 41 } 42 43 impl IHwCryptoOperations for HwCryptoOperations { processCommandList( &self, command_lists: &mut std::vec::Vec<CryptoOperationSet>, _additional_error_info: &mut CryptoOperationErrorAdditionalInfo, ) -> binder::Result<Vec<CryptoOperationResult>>44 fn processCommandList( 45 &self, 46 command_lists: &mut std::vec::Vec<CryptoOperationSet>, 47 _additional_error_info: &mut CryptoOperationErrorAdditionalInfo, 48 ) -> binder::Result<Vec<CryptoOperationResult>> { 49 let mut results = Vec::<CryptoOperationResult>::new(); 50 for command_list in command_lists { 51 results.try_reserve(1).map_err(|e| { 52 hwcrypto_err!(ALLOCATION_ERROR, "couldn't grow result vector: {:?}", e) 53 })?; 54 results.push(CryptoOperationResult { context: None }); 55 match &command_list.context { 56 None => { 57 let mut cmd_processor = CmdProcessorContext::new(); 58 cmd_processor.process_all_steps(&mut command_list.operations)?; 59 if !cmd_processor.is_destroyed() { 60 let operation_context = CryptoOperationContext::new_binder(cmd_processor); 61 (*results 62 .last_mut() 63 .expect("shouldn't happen, we pushed an element before match")) 64 .context = Some(operation_context); 65 } 66 } 67 Some(operation_context) => { 68 BinderCryptoOperationContext::from(operation_context.clone()) 69 .process_all_steps(&mut command_list.operations)?; 70 } 71 } 72 } 73 Ok(results) 74 } 75 } 76 77 #[cfg(test)] 78 mod tests { 79 use super::*; 80 use crate::hwcrypto_ipc_server::RUST_SERVICE_PORT; 81 use android_hardware_security_see_hwcrypto::aidl::android::hardware::security::see::hwcrypto::{ 82 types::{ 83 AesCipherMode::AesCipherMode, CipherModeParameters::CipherModeParameters, 84 HmacOperationParameters::HmacOperationParameters, KeyLifetime::KeyLifetime, 85 KeyType::KeyType, KeyUse::KeyUse, OperationData::OperationData, 86 SymmetricCryptoParameters::SymmetricCryptoParameters, 87 SymmetricOperation::SymmetricOperation, 88 SymmetricOperationParameters::SymmetricOperationParameters, 89 }, 90 CryptoOperation::CryptoOperation, 91 IHwCryptoKey::{ 92 DerivedKey::DerivedKey, DerivedKeyParameters::DerivedKeyParameters, 93 DerivedKeyPolicy::DerivedKeyPolicy, DeviceKeyId::DeviceKeyId, 94 DiceBoundDerivationKey::DiceBoundDerivationKey, 95 DiceCurrentBoundKeyResult::DiceCurrentBoundKeyResult, IHwCryptoKey, KeySlot::KeySlot, 96 }, 97 KeyPolicy::KeyPolicy, 98 OperationParameters::OperationParameters, 99 }; 100 use binder::Strong; 101 use rpcbinder::RpcSession; 102 use test::{assert_ok, expect, expect_eq}; 103 104 #[test] aes_simple_test_from_binder()105 fn aes_simple_test_from_binder() { 106 let hw_device_key: Strong<dyn IHwCryptoKey> = 107 RpcSession::new().setup_trusty_client(RUST_SERVICE_PORT).expect("Failed to connect"); 108 let derivation_key = DiceBoundDerivationKey::KeyId(DeviceKeyId::DEVICE_BOUND_KEY); 109 let key_and_policy = 110 assert_ok!(hw_device_key.deriveCurrentDicePolicyBoundKey(&derivation_key)); 111 let DiceCurrentBoundKeyResult { diceBoundKey: key, dicePolicyForKeyVersion: policy } = 112 key_and_policy; 113 expect!(key.is_some(), "should have received a key"); 114 expect!(policy.len() > 0, "should have received a DICE policy"); 115 116 let hw_crypto = hw_device_key.getHwCryptoOperations().expect("Failed to get crypto ops."); 117 let usage = KeyUse::ENCRYPT_DECRYPT; 118 let key_type = KeyType::AES_256_CBC_PKCS7_PADDING; 119 let policy = KeyPolicy { 120 usage, 121 keyLifetime: KeyLifetime::HARDWARE, 122 keyPermissions: Vec::new(), 123 keyType: key_type, 124 keyManagementKey: false, 125 }; 126 127 let cbor_policy = hwcryptohal_common::policy::cbor_serialize_key_policy(&policy) 128 .expect("couldn't serialize policy"); 129 let key_policy = DerivedKeyPolicy::OpaqueKey(cbor_policy); 130 let params = DerivedKeyParameters { 131 derivationKey: key, 132 keyPolicy: key_policy, 133 context: "context".as_bytes().to_vec(), 134 }; 135 let derived_key = assert_ok!(hw_device_key.deriveKey(¶ms)); 136 let key = match derived_key { 137 DerivedKey::Opaque(key) => key.expect("key shouldn't be NULL"), 138 DerivedKey::ExplicitKey(_) => panic!("wrong type of key received"), 139 }; 140 141 let nonce = [0u8; 16]; 142 let parameters = SymmetricCryptoParameters::Aes(AesCipherMode::Cbc(CipherModeParameters { 143 nonce: nonce.into(), 144 })); 145 let direction = SymmetricOperation::ENCRYPT; 146 let sym_op_params = 147 SymmetricOperationParameters { key: Some(key.clone()), direction, parameters }; 148 let op_params = OperationParameters::SymmetricCrypto(sym_op_params); 149 let mut cmd_list = Vec::<CryptoOperation>::new(); 150 let data_output = OperationData::DataBuffer(Vec::new()); 151 cmd_list.push(CryptoOperation::DataOutput(data_output)); 152 cmd_list.push(CryptoOperation::SetOperationParameters(op_params)); 153 let input_data = OperationData::DataBuffer("string to be encrypted".as_bytes().to_vec()); 154 cmd_list.push(CryptoOperation::DataInput(input_data)); 155 let crypto_op_set = CryptoOperationSet { context: None, operations: cmd_list }; 156 let mut crypto_sets = Vec::new(); 157 crypto_sets.push(crypto_op_set); 158 let mut additional_error_info = 159 CryptoOperationErrorAdditionalInfo { failingCommandIndex: 0 }; 160 let mut op_result = hw_crypto 161 .processCommandList(&mut crypto_sets, &mut additional_error_info) 162 .expect("couldn't process commands"); 163 // Extracting the vector from the command list because of ownership 164 let CryptoOperation::DataOutput(OperationData::DataBuffer(encrypted_data)) = 165 crypto_sets.remove(0).operations.remove(0) 166 else { 167 panic!("not reachable, we created this object above on the test"); 168 }; 169 let context = op_result.remove(0).context; 170 // Separating the finish call on a different command set to test the returned context 171 let mut cmd_list = Vec::<CryptoOperation>::new(); 172 let data_output = OperationData::DataBuffer(encrypted_data); 173 cmd_list.push(CryptoOperation::DataOutput(data_output)); 174 cmd_list.push(CryptoOperation::Finish(None)); 175 let crypto_op_set = CryptoOperationSet { context, operations: cmd_list }; 176 let mut crypto_sets = Vec::new(); 177 crypto_sets.push(crypto_op_set); 178 hw_crypto 179 .processCommandList(&mut crypto_sets, &mut additional_error_info) 180 .expect("couldn't process commands"); 181 let CryptoOperation::DataOutput(OperationData::DataBuffer(encrypted_data)) = 182 crypto_sets.remove(0).operations.remove(0) 183 else { 184 panic!("not reachable, we created this object above on the test"); 185 }; 186 187 //// Decrypting 188 let parameters = SymmetricCryptoParameters::Aes(AesCipherMode::Cbc(CipherModeParameters { 189 nonce: nonce.into(), 190 })); 191 let direction = SymmetricOperation::DECRYPT; 192 let sym_op_params = SymmetricOperationParameters { key: Some(key), direction, parameters }; 193 let op_params = OperationParameters::SymmetricCrypto(sym_op_params); 194 let mut cmd_list = Vec::<CryptoOperation>::new(); 195 let data_output = OperationData::DataBuffer(Vec::new()); 196 cmd_list.push(CryptoOperation::DataOutput(data_output)); 197 cmd_list.push(CryptoOperation::SetOperationParameters(op_params)); 198 cmd_list.push(CryptoOperation::DataInput(OperationData::DataBuffer(encrypted_data))); 199 cmd_list.push(CryptoOperation::Finish(None)); 200 let crypto_op_set = CryptoOperationSet { context: None, operations: cmd_list }; 201 let mut crypto_sets = Vec::new(); 202 crypto_sets.push(crypto_op_set); 203 hw_crypto 204 .processCommandList(&mut crypto_sets, &mut additional_error_info) 205 .expect("couldn't process commands"); 206 // Extracting the vector from the command list because of ownership 207 let CryptoOperation::DataOutput(OperationData::DataBuffer(decrypted_data)) = 208 crypto_sets.remove(0).operations.remove(0) 209 else { 210 panic!("not reachable, we created this object above on the test"); 211 }; 212 let decrypted_msg = 213 String::from_utf8(decrypted_data).expect("couldn't decode received message"); 214 expect_eq!(decrypted_msg, "string to be encrypted", "couldn't retrieve original message"); 215 } 216 217 #[test] hmac_simple_test_from_binder()218 fn hmac_simple_test_from_binder() { 219 let hw_key: Strong<dyn IHwCryptoKey> = 220 RpcSession::new().setup_trusty_client(RUST_SERVICE_PORT).expect("Failed to connect"); 221 222 let key = 223 hw_key.getKeyslotData(KeySlot::KEYMINT_SHARED_HMAC_KEY).expect("couldn't get key"); 224 225 let hw_crypto = hw_key.getHwCryptoOperations().expect("Failed to get crypto ops."); 226 227 let hmac_parameters = HmacOperationParameters { key: Some(key.clone()) }; 228 let op_parameters = OperationParameters::Hmac(hmac_parameters); 229 let mut cmd_list = Vec::<CryptoOperation>::new(); 230 let data_output = OperationData::DataBuffer(Vec::new()); 231 cmd_list.push(CryptoOperation::DataOutput(data_output)); 232 cmd_list.push(CryptoOperation::SetOperationParameters(op_parameters)); 233 let input_data = OperationData::DataBuffer("text to be mac'ed".as_bytes().to_vec()); 234 cmd_list.push(CryptoOperation::DataInput(input_data)); 235 cmd_list.push(CryptoOperation::Finish(None)); 236 let crypto_op_set = CryptoOperationSet { context: None, operations: cmd_list }; 237 let mut crypto_sets = Vec::new(); 238 crypto_sets.push(crypto_op_set); 239 let mut additional_error_info = 240 CryptoOperationErrorAdditionalInfo { failingCommandIndex: 0 }; 241 hw_crypto 242 .processCommandList(&mut crypto_sets, &mut additional_error_info) 243 .expect("couldn't process commands"); 244 // Extracting the vector from the command list because of ownership 245 let CryptoOperation::DataOutput(OperationData::DataBuffer(mac)) = 246 crypto_sets.remove(0).operations.remove(0) 247 else { 248 panic!("not reachable, we created this object above on the test"); 249 }; 250 251 //Getting a second mac to compare 252 let hmac_parameters = HmacOperationParameters { key: Some(key) }; 253 let op_parameters = OperationParameters::Hmac(hmac_parameters); 254 let mut cmd_list = Vec::<CryptoOperation>::new(); 255 let data_output = OperationData::DataBuffer(Vec::new()); 256 cmd_list.push(CryptoOperation::DataOutput(data_output)); 257 cmd_list.push(CryptoOperation::SetOperationParameters(op_parameters)); 258 let input_data = OperationData::DataBuffer("text to be mac'ed".as_bytes().to_vec()); 259 cmd_list.push(CryptoOperation::DataInput(input_data)); 260 cmd_list.push(CryptoOperation::Finish(None)); 261 let crypto_op_set = CryptoOperationSet { context: None, operations: cmd_list }; 262 let mut crypto_sets = Vec::new(); 263 crypto_sets.push(crypto_op_set); 264 let mut additional_error_info = 265 CryptoOperationErrorAdditionalInfo { failingCommandIndex: 0 }; 266 hw_crypto 267 .processCommandList(&mut crypto_sets, &mut additional_error_info) 268 .expect("couldn't process commands"); 269 // Extracting the vector from the command list because of ownership 270 let CryptoOperation::DataOutput(OperationData::DataBuffer(mac2)) = 271 crypto_sets.remove(0).operations.remove(0) 272 else { 273 panic!("not reachable, we created this object above on the test"); 274 }; 275 expect_eq!(mac, mac2, "got a different mac"); 276 } 277 } 278