1 /* 2 * Copyright (C) 2023 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 #[cfg(test)] 17 mod tests { 18 pub(crate) const RUST_HWCRYPTO_SERVICE_PORT: &str = "com.android.trusty.rust.hwcryptohal.V1"; 19 20 use android_hardware_security_see_hwcrypto::aidl::android::hardware::security::see::hwcrypto::{ 21 types::{ 22 AesCipherMode::AesCipherMode, AesKey::AesKey, 23 CipherModeParameters::CipherModeParameters, ExplicitKeyMaterial::ExplicitKeyMaterial, 24 KeyLifetime::KeyLifetime, KeyType::KeyType, KeyUse::KeyUse, 25 OperationData::OperationData, SymmetricCryptoParameters::SymmetricCryptoParameters, 26 SymmetricOperation::SymmetricOperation, 27 SymmetricOperationParameters::SymmetricOperationParameters, 28 }, 29 CryptoOperation::CryptoOperation, 30 CryptoOperationErrorAdditionalInfo::CryptoOperationErrorAdditionalInfo, 31 CryptoOperationSet::CryptoOperationSet, 32 ICryptoOperationContext::ICryptoOperationContext, 33 IHwCryptoKey::IHwCryptoKey, 34 KeyPolicy::KeyPolicy, 35 OperationParameters::OperationParameters, 36 }; 37 use binder::Strong; 38 use rpcbinder::RpcSession; 39 use std::collections::HashMap; 40 use test::expect; 41 use trusty_std::ffi::{CString, FallibleCString}; 42 43 #[derive(Debug, Clone, PartialEq)] 44 enum OPERATION { 45 ENCRYPT, 46 DECRYPT, 47 } 48 49 #[derive(Debug, Clone, PartialEq)] 50 enum MODE { 51 CBC, 52 CTR, 53 } 54 55 #[derive(Debug)] 56 struct Vector { 57 op: Option<OPERATION>, 58 mode: Option<MODE>, 59 key_length: Option<u16>, 60 iv_size: Option<u16>, 61 payload_size: Option<u16>, 62 params: HashMap<String, String>, 63 } 64 65 #[test] aes_vector_test()66 fn aes_vector_test() { 67 run_aes_vectors(parse_vectors(include_str!("vectors/CAVP/KAT_AES/CBCGFSbox128.rsp"))); 68 run_aes_vectors(parse_vectors(include_str!("vectors/CAVP/KAT_AES/CBCGFSbox256.rsp"))); 69 run_aes_vectors(parse_vectors(include_str!("vectors/CAVP/KAT_AES/CBCKeySbox128.rsp"))); 70 run_aes_vectors(parse_vectors(include_str!("vectors/CAVP/KAT_AES/CBCKeySbox256.rsp"))); 71 run_aes_vectors(parse_vectors(include_str!("vectors/CAVP/KAT_AES/CBCVarKey128.rsp"))); 72 run_aes_vectors(parse_vectors(include_str!("vectors/CAVP/KAT_AES/CBCVarKey256.rsp"))); 73 run_aes_vectors(parse_vectors(include_str!("vectors/CAVP/KAT_AES/CBCVarTxt128.rsp"))); 74 run_aes_vectors(parse_vectors(include_str!("vectors/CAVP/KAT_AES/CBCVarTxt256.rsp"))); 75 76 run_aes_vectors(parse_vectors(include_str!("vectors/CAVP/aesmmt/CBCMMT128.rsp"))); 77 run_aes_vectors(parse_vectors(include_str!("vectors/CAVP/aesmmt/CBCMMT256.rsp"))); 78 79 run_aes_vectors(parse_vectors(include_str!("vectors/NIST/CTR/ctr_128.rsp"))); 80 run_aes_vectors(parse_vectors(include_str!("vectors/NIST/CTR/ctr_256.rsp"))); 81 } 82 hex_to_bytes(s: &str) -> Option<Vec<u8>>83 fn hex_to_bytes(s: &str) -> Option<Vec<u8>> { 84 if s.len() % 2 == 0 { 85 (0..s.len()) 86 .step_by(2) 87 .map(|i| s.get(i..i + 2).and_then(|sub| u8::from_str_radix(sub, 16).ok())) 88 .collect() 89 } else { 90 None 91 } 92 } 93 parse_vectors(raw: &str) -> Vec<Vector>94 fn parse_vectors(raw: &str) -> Vec<Vector> { 95 let mut vectors: Vec<Vector> = Vec::new(); 96 97 let mut params: HashMap<String, String> = HashMap::new(); 98 let mut mode: Option<MODE> = None; 99 let mut op: Option<OPERATION> = None; 100 let mut key_length: Option<u16> = None; 101 let mut iv_size: Option<u16> = None; 102 let mut payload_size: Option<u16>; 103 104 for line in raw.lines() { 105 // Check for header settings 106 if line.contains("test data for") { 107 let parts: Vec<&str> = line.split("test data for").collect(); 108 let mode_str = parts[1].trim(); 109 110 match mode_str { 111 "CBC" => { 112 mode = Some(MODE::CBC); 113 iv_size = Some(128); 114 } 115 "CTR" => { 116 mode = Some(MODE::CTR); 117 iv_size = Some(128); 118 } 119 _ => { 120 mode = None; 121 iv_size = None; 122 } 123 }; 124 } 125 126 // Check for key length 127 if line.contains("Key Length") { 128 let parts: Vec<&str> = line.split(":").collect(); 129 key_length = Some(parts[1].trim().parse::<u16>().unwrap()); 130 } 131 132 // Check for encrypt or decrypt 133 if line.contains("[ENCRYPT]") { 134 op = Some(OPERATION::ENCRYPT); 135 } 136 137 if line.contains("[DECRYPT]") { 138 op = Some(OPERATION::DECRYPT); 139 } 140 141 // Check for vector components 142 if line.contains("=") { 143 let words: Vec<_> = line.split_whitespace().filter(|s| s != &"=").collect(); 144 params.insert(words[0].to_string(), words[1].to_string()); 145 } 146 147 // Check for vector completion 148 if line.trim().len() == 0 && params.len() > 0 { 149 // Vector complete, add to array 150 payload_size = Some((params["PLAINTEXT"].len() * 4).try_into().unwrap()); 151 152 let current_vector = Vector { 153 op: op.clone(), 154 mode: mode.clone(), 155 key_length: key_length.clone(), 156 iv_size: iv_size.clone(), 157 payload_size: payload_size.clone(), 158 params: params.clone(), 159 }; 160 params.clear(); 161 vectors.push(current_vector); 162 } 163 } 164 165 // Add last vector to array if not yet added 166 if params.len() > 0 { 167 payload_size = Some((params["PLAINTEXT"].len() * 4).try_into().unwrap()); 168 169 let current_vector = Vector { 170 op: op.clone(), 171 mode: mode.clone(), 172 key_length: key_length.clone(), 173 iv_size: iv_size.clone(), 174 payload_size: payload_size.clone(), 175 params: params.clone(), 176 }; 177 params.clear(); 178 vectors.push(current_vector); 179 } 180 181 vectors 182 } 183 get_key_type(key_length: &u16, mode: &MODE) -> Option<KeyType>184 fn get_key_type(key_length: &u16, mode: &MODE) -> Option<KeyType> { 185 match key_length { 186 128 => match mode { 187 MODE::CBC => Some(KeyType::AES_128_CBC_NO_PADDING), 188 MODE::CTR => Some(KeyType::AES_128_CTR), 189 }, 190 256 => match mode { 191 MODE::CBC => Some(KeyType::AES_256_CBC_NO_PADDING), 192 MODE::CTR => Some(KeyType::AES_256_CTR), 193 }, 194 _ => None, 195 } 196 } 197 run_aes_vectors(vectors: Vec<Vector>)198 fn run_aes_vectors(vectors: Vec<Vector>) { 199 let port = 200 CString::try_new(RUST_HWCRYPTO_SERVICE_PORT).expect("Failed to allocate port name"); 201 let hw_crypto: Strong<dyn IHwCryptoKey> = 202 RpcSession::new().setup_trusty_client(port.as_c_str()).expect("Failed to connect"); 203 let hw_crypto_ops = 204 hw_crypto.getHwCryptoOperations().expect("couldn't get key crypto ops."); 205 206 let mut current_key: Vec<u8> = Vec::new(); 207 let mut current_iv: Vec<u8> = Vec::new(); 208 let mut new_iv: bool; 209 210 let mut context: Option<Strong<dyn ICryptoOperationContext>> = None; 211 212 for v in vectors { 213 if v.params.contains_key("IV") { 214 current_key = hex_to_bytes(v.params["KEY"].as_str()).expect("Bad hex value"); 215 expect!( 216 current_key.len() * 8 == v.key_length.unwrap() as usize, 217 "Invalid key length" 218 ); 219 220 current_iv = hex_to_bytes(v.params["IV"].as_str()).expect("Bad hex value"); 221 expect!(current_iv.len() * 8 == v.iv_size.unwrap() as usize, "Invalid IV length"); 222 223 new_iv = true; 224 context = None; 225 } else { 226 new_iv = false; 227 } 228 229 let plaintext: Vec<u8> = 230 hex_to_bytes(v.params["PLAINTEXT"].as_str()).expect("Bad hex value"); 231 let ciphertext: Vec<u8> = 232 hex_to_bytes(v.params["CIPHERTEXT"].as_str()).expect("Bad hex value"); 233 234 expect!(plaintext.len() * 8 == v.payload_size.unwrap() as usize, "Invalid data length"); 235 expect!( 236 ciphertext.len() * 8 == v.payload_size.unwrap() as usize, 237 "Invalid data length" 238 ); 239 240 let policy = KeyPolicy { 241 usage: KeyUse::ENCRYPT_DECRYPT, 242 keyLifetime: KeyLifetime::PORTABLE, 243 keyPermissions: Vec::new(), 244 keyType: get_key_type(&((current_key.len() * 8) as u16), &v.mode.as_ref().unwrap()) 245 .expect("Invalid key size or mode"), 246 keyManagementKey: false, 247 }; 248 249 let aes_key_material: ExplicitKeyMaterial = match current_key.len() * 8 { 250 128 => ExplicitKeyMaterial::Aes(AesKey::Aes128( 251 current_key.clone().try_into().expect("Bad key"), 252 )), 253 256 => ExplicitKeyMaterial::Aes(AesKey::Aes256( 254 current_key.clone().try_into().expect("Bad key"), 255 )), 256 _ => panic!("Unsupported key length"), 257 }; 258 259 let key = hw_crypto 260 .importClearKey(&aes_key_material, &policy) 261 .expect("Couldn't import clear key"); 262 263 let parameters = match v.mode.clone().unwrap() { 264 MODE::CBC => { 265 SymmetricCryptoParameters::Aes(AesCipherMode::Cbc(CipherModeParameters { 266 nonce: current_iv.clone().try_into().expect("Failed to set IV"), 267 })) 268 } 269 MODE::CTR => { 270 SymmetricCryptoParameters::Aes(AesCipherMode::Ctr(CipherModeParameters { 271 nonce: current_iv.clone().try_into().expect("Failed to set IV"), 272 })) 273 } 274 }; 275 276 let direction = match v.op.as_ref().unwrap() { 277 OPERATION::ENCRYPT => SymmetricOperation::ENCRYPT, 278 OPERATION::DECRYPT => SymmetricOperation::DECRYPT, 279 }; 280 281 let sym_op_params = 282 SymmetricOperationParameters { key: Some(key.clone()), direction, parameters }; 283 let op_params = OperationParameters::SymmetricCrypto(sym_op_params); 284 285 let mut cmd_list = Vec::<CryptoOperation>::new(); 286 let data_output = OperationData::DataBuffer(Vec::new()); 287 288 // Build command list 289 cmd_list.push(CryptoOperation::DataOutput(data_output)); 290 291 if v.mode.clone().unwrap() != MODE::CTR || new_iv { 292 cmd_list.push(CryptoOperation::SetOperationParameters(op_params)); 293 // For CTR, only do this when IV changes 294 } 295 296 let input_data = match v.op.as_ref().unwrap() { 297 OPERATION::ENCRYPT => OperationData::DataBuffer(plaintext.clone()), 298 OPERATION::DECRYPT => OperationData::DataBuffer(ciphertext.clone()), 299 }; 300 cmd_list.push(CryptoOperation::DataInput(input_data)); 301 302 if v.mode.clone().unwrap() != MODE::CTR { 303 cmd_list.push(CryptoOperation::Finish(None)); // For CTR, don't do this 304 } 305 306 if v.mode.clone().unwrap() != MODE::CTR { 307 // Clear context unless processing CTR vectors 308 context = None; 309 } 310 311 let crypto_op_set = 312 CryptoOperationSet { context: context.clone(), operations: cmd_list }; 313 let mut crypto_sets = Vec::new(); 314 crypto_sets.push(crypto_op_set); 315 let mut additional_error_info = 316 CryptoOperationErrorAdditionalInfo { failingCommandIndex: 0 }; 317 318 let mut op_result = hw_crypto_ops 319 .processCommandList(&mut crypto_sets, &mut additional_error_info) 320 .expect("couldn't process commands"); 321 322 // Capture context to be used with CTR vectors whenever we have a new IV 323 if new_iv { 324 context = op_result.remove(0).context; 325 } 326 327 // Verify results 328 let CryptoOperation::DataOutput(OperationData::DataBuffer(processed_data)) = 329 crypto_sets.remove(0).operations.remove(0) 330 else { 331 panic!("not reachable, we created this object above on the test"); 332 }; 333 334 match v.op.as_ref().unwrap() { 335 OPERATION::ENCRYPT => { 336 expect!(processed_data.to_vec() == ciphertext, "Known answer mismatch") 337 } 338 OPERATION::DECRYPT => { 339 expect!(processed_data.to_vec() == plaintext, "Known answer mismatch") 340 } 341 }; 342 } 343 } 344 } 345