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