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