1 /*
2  * Copyright (C) 2022 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 #define TLOG_TAG "hwaes_bench"
18 #include <stdbool.h>
19 #include <stdlib.h>
20 #include <string.h>
21 
22 #include <lib/hwaes/hwaes.h>
23 #include <lib/hwkey/hwkey.h>
24 #include <sys/auxv.h>
25 #include <sys/mman.h>
26 #include <trusty/memref.h>
27 #include <trusty_benchmark.h>
28 #include <trusty_unittest.h>
29 #include <uapi/err.h>
30 
31 #include "vectors.h"
32 
33 /*
34  * Define to verify crypto operation output matches the expected test vectors.
35  * This adds overhead (memcmp()) to the benchmark, so is not normally desired.
36  * However, it may be useful to verify that the correct cipher operation in
37  * the benchmark.
38  */
39 // #define CHECK_RESULTS
40 
41 /*
42  * Define to make tests at buffer sizes greater than one page.
43  * The driver & hardware must be able to support page crossings for these tests
44  * to execute.
45  */
46 // #define EXTENDED_BUFFERS
47 
48 /* Number of times to run the benchmark function with each parameter */
49 #define RUNS 40
50 
51 #define HWAES_MAX_NUM_HANDLES 8
52 #define AUX_PAGE_SIZE() getauxval(AT_PAGESZ)
53 #define CUR_PARAM params[bench_get_param_idx()]
54 
55 /**
56  * struct hwaes_iov - a wrapper of an array of iovec.
57  * @iov: array of iovec.
58  * @num_iov: number of iovec.
59  * @total_len: total length of the tipc message.
60  */
61 struct hwaes_iov {
62     struct iovec iov[TIPC_MAX_MSG_PARTS];
63     size_t num_iov;
64     size_t total_len;
65 };
66 
67 /**
68  * struct hwaes_shm - a wrapper of an array of shared memory handles.
69  * @handles:     array of shared memory handles.
70  * @num_handles: number of shared memory handles.
71  */
72 struct hwaes_shm {
73     handle_t handles[HWAES_MAX_NUM_HANDLES];
74     size_t num_handles;
75 };
76 /**
77  * struct crypto_hwaes_state - holds the current bench state.
78  * @hwaes_session: handle to an open session with the hwaes secure app.
79  * @shm_hdin: shared memory handle for text in
80  * @shm_hdout: shared memory handle for text out
81  * @args:   parameters to the actual encryption routine
82  * @req_hdr: request structure for hwaes. Holds the command to be sent
83  * @cmd_hdr: request header for HWAES_AES command
84  * @shm_descs: yet another packing of shared memory descriptor
85  * @req_iov:   iovector array of requests
86  */
87 struct crypto_hwaes_state {
88     hwaes_session_t hwaes_session;
89     struct hwcrypt_shm_hd shm_hdin;
90     struct hwcrypt_shm_hd shm_hdout;
91     struct hwcrypt_args args;
92     struct hwaes_req req_hdr;
93     struct hwaes_aes_req cmd_hdr;
94     struct hwaes_shm_desc shm_descs[HWAES_MAX_NUM_HANDLES];
95     struct hwaes_iov req_iov;
96 };
97 
98 static struct crypto_hwaes_state* _state;
99 
100 /**
101  * struct crypto_hwaes_param - Necessary Parameters for hwaes_encrypt.
102  * @key: key to use for encryption
103  * @key_size: byte size of the key
104  * @input: base address of the bytes blob to be encrypted/decrypted
105  * @input_size: size of the bytes blob to be encrypted/decrypted
106  * @output: bytes blob resulting from encryption/decryption
107  * @output_size: size of the bytes blob resulting from encryption/decryption
108  * @iv: initialization vector for encryption/decryption
109  * @iv_size: size of the initialization vector for encryption/decryption
110  * @tag: expected tag output for GCM encryption
111  * @tag_size: size of the expected tag output for GCM encryption
112  * @mode: GMC/CBC AES ecnryption block mode
113  * @encrypt: direction? encrypt or decrypt
114  */
115 struct crypto_hwaes_param {
116     const uint8_t* key;
117     size_t key_size;
118     const uint8_t* input;
119     size_t input_size;
120     const uint8_t* output;
121     size_t output_size;
122     const uint8_t* iv;
123     size_t iv_size;
124     const uint8_t* tag;
125     size_t tag_size;
126     enum hwaes_mode mode;
127     bool encrypt;
128 };
129 
130 /**
131  * params - Array of parameters for the parametric BENCH
132  */
133 static struct crypto_hwaes_param params[] = {
134         /* Key and input sizes are given in bits
135          *                   mode, key, input, direction:
136          */
137         AES_CRYPT_ARGS(CBC, 128, 256, ENCRYPT),   /* 32 bytes */
138         AES_CRYPT_ARGS(CBC, 128, 8192, ENCRYPT),  /*  1Kbytes */
139         AES_CRYPT_ARGS(CBC, 128, 16384, ENCRYPT), /*  2Kbytes */
140         AES_CRYPT_ARGS(CBC, 128, 32768, ENCRYPT), /*  4Kbytes */
141 #if EXTENDED_BUFFERS
142         AES_CRYPT_ARGS(CBC, 128, 65536, ENCRYPT),  /*  8Kbytes */
143         AES_CRYPT_ARGS(CBC, 128, 131072, ENCRYPT), /* 16Kbytes */
144 #endif
145         AES_CRYPT_ARGS(CBC, 128, 256, DECRYPT),   /* 32 bytes */
146         AES_CRYPT_ARGS(CBC, 128, 8192, DECRYPT),  /*  1Kbytes */
147         AES_CRYPT_ARGS(CBC, 128, 16384, DECRYPT), /*  2Kbytes */
148         AES_CRYPT_ARGS(CBC, 128, 32768, DECRYPT), /*  4Kbytes */
149 #if EXTENDED_BUFFERS
150         AES_CRYPT_ARGS(CBC, 128, 65536, DECRYPT),  /*  8Kbytes */
151         AES_CRYPT_ARGS(CBC, 128, 131072, DECRYPT), /* 16Kbytes */
152 #endif
153         AES_CRYPT_ARGS(CBC, 256, 256, ENCRYPT),   /* 32 bytes */
154         AES_CRYPT_ARGS(CBC, 256, 8192, ENCRYPT),  /*  1Kbytes */
155         AES_CRYPT_ARGS(CBC, 256, 16384, ENCRYPT), /*  2Kbytes */
156         AES_CRYPT_ARGS(CBC, 256, 32768, ENCRYPT), /*  4Kbytes */
157 #if EXTENDED_BUFFERS
158         AES_CRYPT_ARGS(CBC, 256, 65536, ENCRYPT),  /*  8Kbytes */
159         AES_CRYPT_ARGS(CBC, 256, 131072, ENCRYPT), /* 16Kbytes */
160 #endif
161         AES_CRYPT_ARGS(CBC, 256, 256, DECRYPT),   /* 32 bytes */
162         AES_CRYPT_ARGS(CBC, 256, 8192, DECRYPT),  /*  1Kbytes */
163         AES_CRYPT_ARGS(CBC, 256, 16384, DECRYPT), /*  2Kbytes */
164         AES_CRYPT_ARGS(CBC, 256, 32768, DECRYPT), /*  4Kbytes */
165 #if EXTENDED_BUFFERS
166         AES_CRYPT_ARGS(CBC, 256, 65536, DECRYPT),  /*  8Kbytes */
167         AES_CRYPT_ARGS(CBC, 256, 131072, DECRYPT), /* 16Kbytes */
168 #endif
169         AES_CRYPT_ARGS(GCM, 128, 256, ENCRYPT),   /* 32 bytes */
170         AES_CRYPT_ARGS(GCM, 128, 8192, ENCRYPT),  /*  1Kbytes */
171         AES_CRYPT_ARGS(GCM, 128, 16384, ENCRYPT), /*  2Kbytes */
172         AES_CRYPT_ARGS(GCM, 128, 32768, ENCRYPT), /*  4Kbytes */
173 #if EXTENDED_BUFFERS
174         AES_CRYPT_ARGS(GCM, 128, 65536, ENCRYPT),  /*  8Kbytes */
175         AES_CRYPT_ARGS(GCM, 128, 131072, ENCRYPT), /* 16Kbytes */
176 #endif
177         AES_CRYPT_ARGS(GCM, 128, 256, DECRYPT),   /* 32 bytes */
178         AES_CRYPT_ARGS(GCM, 128, 8192, DECRYPT),  /*  1Kbytes */
179         AES_CRYPT_ARGS(GCM, 128, 16384, DECRYPT), /*  2Kbytes */
180         AES_CRYPT_ARGS(GCM, 128, 32768, DECRYPT), /*  4Kbytes */
181 #if EXTENDED_BUFFERS
182         AES_CRYPT_ARGS(GCM, 128, 65536, DECRYPT),  /*  8Kbytes */
183         AES_CRYPT_ARGS(GCM, 128, 131072, DECRYPT), /* 16Kbytes */
184 #endif
185         AES_CRYPT_ARGS(GCM, 256, 256, ENCRYPT),   /* 32 bytes */
186         AES_CRYPT_ARGS(GCM, 256, 8192, ENCRYPT),  /*  1Kbytes */
187         AES_CRYPT_ARGS(GCM, 256, 16384, ENCRYPT), /*  2Kbytes */
188         AES_CRYPT_ARGS(GCM, 256, 32768, ENCRYPT), /*  4Kbytes */
189 #if EXTENDED_BUFFERS
190         AES_CRYPT_ARGS(GCM, 256, 65536, ENCRYPT),  /*  8Kbytes */
191         AES_CRYPT_ARGS(GCM, 256, 131072, ENCRYPT), /* 16Kbytes */
192 #endif
193         AES_CRYPT_ARGS(GCM, 256, 256, DECRYPT),   /* 32 bytes */
194         AES_CRYPT_ARGS(GCM, 256, 8192, DECRYPT),  /*  1Kbytes */
195         AES_CRYPT_ARGS(GCM, 256, 16384, DECRYPT), /*  2Kbytes */
196         AES_CRYPT_ARGS(GCM, 256, 32768, DECRYPT), /*  4Kbytes */
197 #if EXTENDED_BUFFERS
198         AES_CRYPT_ARGS(GCM, 256, 65536, DECRYPT),  /*  8Kbytes */
199         AES_CRYPT_ARGS(GCM, 256, 131072, DECRYPT), /* 16Kbytes */
200 #endif
201 };
202 
get_param_name_cb(char * buf,size_t buf_size,size_t param_idx)203 static void get_param_name_cb(char* buf, size_t buf_size, size_t param_idx) {
204     snprintf(buf, buf_size, "%s%sK%zu_%zu",
205              params[param_idx].encrypt ? "ENC_" : "DEC_",
206              params[param_idx].mode == HWAES_CBC_MODE ? "CBC_" : "GCM_",
207              params[param_idx].key_size * 8, params[param_idx].input_size * 8);
208 }
209 
shm_alloc(size_t size,struct hwcrypt_shm_hd * shm_hd)210 static int shm_alloc(size_t size, struct hwcrypt_shm_hd* shm_hd) {
211     memset(shm_hd, 0, sizeof(struct hwcrypt_shm_hd));
212 
213     void* base = memalign(AUX_PAGE_SIZE(), size);
214     if (base == NULL) {
215         return ERR_NO_MEMORY;
216     }
217 
218     handle_t handle =
219             (handle_t)memref_create(base, size, PROT_READ | PROT_WRITE);
220     if (handle < 0) {
221         return ERR_BAD_HANDLE;
222     }
223 
224     shm_hd->handle = handle;
225     shm_hd->base = base;
226     shm_hd->size = size;
227 
228     return NO_ERROR;
229 }
230 
shm_free(struct hwcrypt_shm_hd * shm_hd)231 static void shm_free(struct hwcrypt_shm_hd* shm_hd) {
232     if (shm_hd->base) {
233         close(shm_hd->handle);
234         free((void*)shm_hd->base);
235 
236         shm_hd->base = NULL;
237     }
238 }
239 
BENCH_SETUP(crypto)240 BENCH_SETUP(crypto) {
241     int rc;
242 
243     trusty_bench_get_param_name_cb = &get_param_name_cb;
244 
245     _state = calloc(sizeof(struct crypto_hwaes_state), 1);
246     ASSERT_NE(NULL, _state, "calloc() failed\n");
247 
248     _state->hwaes_session = INVALID_IPC_HANDLE;
249 
250     size_t size = round_up(CUR_PARAM.input_size + GCM_TAG_LEN, AUX_PAGE_SIZE());
251 
252     rc = shm_alloc(size, &_state->shm_hdin);
253     ASSERT_EQ(rc, NO_ERROR);
254     rc = shm_alloc(size, &_state->shm_hdout);
255     ASSERT_EQ(rc, NO_ERROR);
256 
257     /*
258      * Clear the shared memory and fill it with appropriate plaintext/ciphertext
259      */
260     ASSERT_GE(_state->shm_hdin.size, CUR_PARAM.input_size);
261     memset((void*)_state->shm_hdin.base, 0, _state->shm_hdin.size);
262     memcpy((void*)_state->shm_hdin.base, CUR_PARAM.input, CUR_PARAM.input_size);
263 
264     /*
265      * Setup the allocated state and open session with hwaes trusted app server
266      */
267     rc = hwaes_open(&_state->hwaes_session);
268     ASSERT_EQ(rc, NO_ERROR);
269 
270     /*
271      * Pack the required arguments for hwaes_encrypt/hwaes_decrypt.
272      */
273     _state->args = (struct hwcrypt_args){
274             .key =
275                     {
276                             .data_ptr = CUR_PARAM.key,
277                             .len = CUR_PARAM.key_size,
278                     },
279             .iv =
280                     {
281                             .data_ptr = CUR_PARAM.iv,
282                             .len = CUR_PARAM.iv_size,
283                     },
284             .text_in =
285                     {
286                             .data_ptr = (void*)_state->shm_hdin.base,
287                             .len = CUR_PARAM.input_size,
288                             .shm_hd_ptr = &_state->shm_hdin,
289                     },
290             .text_out =
291                     {
292                             .data_ptr = (void*)_state->shm_hdout.base,
293                             .len = CUR_PARAM.output_size,
294                             .shm_hd_ptr = &_state->shm_hdout,
295                     },
296             .key_type = HWAES_PLAINTEXT_KEY,
297             .padding = HWAES_NO_PADDING,
298             .mode = CUR_PARAM.mode,
299     };
300 
301     if (CUR_PARAM.mode == HWAES_GCM_MODE) {
302         _state->args.aad.data_ptr = aad;
303         _state->args.aad.len = sizeof(aad);
304 
305         if (CUR_PARAM.encrypt) {
306             EXPECT_GE(_state->shm_hdout.size,
307                       _state->args.text_out.len + GCM_TAG_LEN);
308 
309             _state->args.tag_out.len = GCM_TAG_LEN;
310             _state->args.tag_out.data_ptr =
311                     (void*)_state->shm_hdout.base + _state->args.text_out.len;
312             _state->args.tag_out.shm_hd_ptr = &_state->shm_hdout;
313         } else {
314             _state->args.tag_in.len = GCM_TAG_LEN;
315             _state->args.tag_in.data_ptr = CUR_PARAM.tag;
316         }
317     }
318 
319     /*
320      * Prepare the command for hwaes server app.
321      */
322     _state->req_hdr = (struct hwaes_req){
323             .cmd = HWAES_AES,
324     };
325     _state->cmd_hdr = (struct hwaes_aes_req){
326             .key =
327                     (struct hwaes_data_desc){
328                             .len = CUR_PARAM.key_size,
329                             .shm_idx = 0,
330                     },
331             .num_handles = 2,
332     };
333     _state->shm_descs[0] =
334             (struct hwaes_shm_desc){.size = _state->shm_hdin.size};
335     _state->shm_descs[1] =
336             (struct hwaes_shm_desc){.size = _state->shm_hdout.size};
337     _state->req_iov = (struct hwaes_iov){
338             .iov =
339                     {
340                             {&_state->req_hdr, sizeof(_state->req_hdr)},
341                             {&_state->cmd_hdr, sizeof(_state->cmd_hdr)},
342                             {&_state->shm_descs,
343                              sizeof(struct hwaes_shm_desc) * 2},
344                     },
345             .num_iov = 3,
346             .total_len = sizeof(_state->req_hdr) + sizeof(_state->cmd_hdr) +
347                          sizeof(struct hwaes_shm_desc) * 2,
348     };
349 
350     return NO_ERROR;
351 
352 test_abort:
353     if (_state) {
354         shm_free(&_state->shm_hdin);
355         shm_free(&_state->shm_hdout);
356 
357         if (_state->hwaes_session != INVALID_IPC_HANDLE) {
358             close(_state->hwaes_session);
359         }
360         free(_state);
361     }
362 
363     return ERR_GENERIC;
364 }
365 
BENCH_TEARDOWN(crypto)366 BENCH_TEARDOWN(crypto) {
367     close(_state->hwaes_session);
368     shm_free(&_state->shm_hdin);
369     shm_free(&_state->shm_hdout);
370     free(_state);
371 }
372 
encrypt(void)373 static int encrypt(void) {
374     int rc = hwaes_encrypt(_state->hwaes_session, &_state->args);
375 
376     ASSERT_EQ(HWAES_NO_ERROR, rc, "encryption failed for param: %zu\n",
377               bench_get_param_idx());
378 
379 #ifdef CHECK_RESULTS
380     ASSERT_EQ(0,
381               memcmp(_state->args.text_out.data_ptr, CUR_PARAM.output,
382                      CUR_PARAM.output_size),
383               "cipher-text mismatch for param: %zu\n", bench_get_param_idx());
384 
385     /* Verify the tag if used (GCM mode) */
386     if (CUR_PARAM.mode == HWAES_GCM_MODE) {
387         ASSERT_EQ(0,
388                   memcmp(_state->args.tag_out.data_ptr, CUR_PARAM.tag,
389                          CUR_PARAM.tag_size),
390                   "tag mismatch for param: %zu\n", bench_get_param_idx());
391     }
392 #endif
393 test_abort:
394     return rc;
395 }
396 
decrypt(void)397 static int decrypt(void) {
398     int rc = hwaes_decrypt(_state->hwaes_session, &_state->args);
399 
400     ASSERT_EQ(HWAES_NO_ERROR, rc, "decryption failed for param: %zu\n",
401               bench_get_param_idx());
402 #ifdef CHECK_RESULTS
403     ASSERT_EQ(0,
404               memcmp(_state->args.text_out.data_ptr, CUR_PARAM.output,
405                      CUR_PARAM.output_size),
406               "cipher-text mismatch for param: %zu\n", bench_get_param_idx());
407 #endif
408 test_abort:
409     return rc;
410 }
411 
BENCH(crypto,hwaes,RUNS,params)412 BENCH(crypto, hwaes, RUNS, params) {
413     return CUR_PARAM.encrypt ? encrypt() : decrypt();
414 }
415 
BENCH_RESULT(crypto,hwaes,Kbit_s)416 BENCH_RESULT(crypto, hwaes, Kbit_s) {
417     return (8000000 * CUR_PARAM.input_size) / bench_get_duration_ns();
418 }
419 
BENCH_RESULT(crypto,hwaes,Mbit_s)420 BENCH_RESULT(crypto, hwaes, Mbit_s) {
421     return (8000 * CUR_PARAM.input_size) / bench_get_duration_ns();
422 }
423 
424 PORT_TEST(hwaes, "com.android.trusty.hwaes.bench")
425