• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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