1 /*
2  * Copyright (C) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *    http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "aes_common.h"
17 #include <fstream>
18 #include <iostream>
19 #include "securec.h"
20 
21 #include "aes_openssl.h"
22 #include "blob.h"
23 #include "cipher.h"
24 #include "detailed_iv_params.h"
25 #include "detailed_gcm_params.h"
26 #include "detailed_ccm_params.h"
27 #include "log.h"
28 #include "memory.h"
29 #include "sym_common_defines.h"
30 #include "sym_key_generator.h"
31 
32 using namespace std;
33 
PrintfHex(const char * tag,uint8_t * in,int inLen)34 void PrintfHex(const char *tag, uint8_t *in, int inLen)
35 {
36     if (!IS_DEBUG) {
37         return;
38     }
39     printf("%s:\n", tag);
40     for (int i = 0; i < inLen; i++) {
41         printf("%02hhX", in[i]);
42     }
43     printf("\n");
44 }
45 
GenerateSymKey(const char * algoName,HcfSymKey ** key)46 int32_t GenerateSymKey(const char *algoName, HcfSymKey **key)
47 {
48     HcfSymKeyGenerator *generator = nullptr;
49 
50     int32_t ret = HcfSymKeyGeneratorCreate(algoName, &generator);
51     if (ret != 0) {
52         LOGE("HcfSymKeyGeneratorCreate failed!");
53         return ret;
54     }
55 
56     ret = generator->generateSymKey(generator, key);
57     if (ret != 0) {
58         LOGE("generateSymKey failed!");
59     }
60     HcfObjDestroy(reinterpret_cast<HcfObjectBase *>(generator));
61     return ret;
62 }
63 
ConvertSymKey(const char * algoName,HcfSymKey ** key)64 int32_t ConvertSymKey(const char *algoName, HcfSymKey **key)
65 {
66     HcfSymKeyGenerator *generator = nullptr;
67     uint8_t keyMaterial[] = {
68         0xba, 0x3b, 0xc2, 0x71, 0x21, 0x1e, 0x30, 0x56,
69         0xad, 0x47, 0xfc, 0x5a, 0x46, 0x39, 0xee, 0x7c
70     };
71     HcfBlob keyTmpBlob = {.data = reinterpret_cast<uint8_t *>(keyMaterial), .len = 16};
72 
73     int32_t ret = HcfSymKeyGeneratorCreate(algoName, &generator);
74     if (ret != 0) {
75         LOGE("HcfSymKeyGeneratorCreate failed!%d", ret);
76         return ret;
77     }
78 
79     ret = generator->convertSymKey(generator, &keyTmpBlob, key);
80     if (ret != 0) {
81         LOGE("generateSymKey failed!");
82     }
83     PrintfHex("keybinary", keyTmpBlob.data, keyTmpBlob.len);
84     HcfObjDestroy(reinterpret_cast<HcfObjectBase *>(generator));
85     return ret;
86 }
87 
88 /* just rand data fill file for test */
GeneratorFile(const char * fileName,int32_t genFileSize)89 int32_t GeneratorFile(const char *fileName, int32_t genFileSize)
90 {
91     if (genFileSize == 0) {
92         return 0;
93     }
94     std::ifstream file(fileName);
95 
96     if (file.good()) {
97         file.close();
98         return 0;
99     }
100     ofstream outfile(fileName, ios::out|ios::binary|ios::app);
101     if (outfile.is_open()) {
102         uint8_t buffer[FILE_BLOCK_SIZE] = {0};
103         while (genFileSize) {
104             for (uint32_t i = 0; i < FILE_BLOCK_SIZE; i++) {
105                 buffer[i] = (rand() % RAND_MAX_NUM) + 1;
106             }
107             genFileSize -= FILE_BLOCK_SIZE;
108             outfile.write(reinterpret_cast<const char *>(buffer), FILE_BLOCK_SIZE);
109         }
110         outfile.close();
111     }
112     return 0;
113 }
114 
CompareFileContent()115 int32_t CompareFileContent()
116 {
117     int32_t ret = -1;
118     ifstream infile1;
119     ifstream infile2;
120     infile1.open("/data/test_aes.txt", ios::in|ios::binary);
121     infile1.seekg (0, infile1.end);
122     uint32_t length1 = infile1.tellg();
123     infile1.seekg (0, infile1.beg);
124 
125     infile2.open("/data/test_aes_new.txt", ios::in|ios::binary);
126     infile2.seekg (0, infile2.end);
127     uint32_t length2 = infile2.tellg();
128     infile2.seekg (0, infile2.beg);
129     if (length1 != length2) {
130         return ret;
131     }
132     uint8_t buffer1[FILE_BLOCK_SIZE] = {0};
133     uint8_t buffer2[FILE_BLOCK_SIZE] = {0};
134     for (uint32_t i = 0; i < length1 / FILE_BLOCK_SIZE; i++) {
135         infile1.read(reinterpret_cast<char *>(buffer1), FILE_BLOCK_SIZE);
136         infile2.read(reinterpret_cast<char *>(buffer2), FILE_BLOCK_SIZE);
137         ret = memcmp(buffer1, buffer2, FILE_BLOCK_SIZE);
138         if (ret != 0) {
139             goto CLEAR_UP;
140         }
141     }
142 CLEAR_UP:
143     infile1.close();
144     infile2.close();
145     return ret;
146 }
147 
AesMultiBlockEncrypt(HcfCipher * cipher,HcfSymKey * key,HcfParamsSpec * params)148 int32_t AesMultiBlockEncrypt(HcfCipher *cipher, HcfSymKey *key, HcfParamsSpec *params)
149 {
150     HcfBlob output = {};
151     ifstream infile;
152     ofstream outfile;
153     infile.open("/data/test_aes.txt", ios::in|ios::binary);
154     infile.seekg (0, infile.end);
155     uint32_t length = infile.tellg();
156     infile.seekg (0, infile.beg);
157     uint8_t buffer[1024] = {0};
158     outfile.open("/data/test_aes_enc.txt", ios::out|ios::binary);
159     HcfBlob input = {.data = reinterpret_cast<uint8_t *>(buffer), .len = FILE_BLOCK_SIZE};
160     uint32_t count = length / FILE_BLOCK_SIZE;
161 
162     int32_t ret = cipher->init(cipher, ENCRYPT_MODE, reinterpret_cast<HcfKey *>(key), params);
163     if (ret != 0) {
164         LOGE("init failed! %d", ret);
165         goto CLEAR_UP;
166     }
167     for (uint32_t i = 0; i < count; i++) {
168         infile.read(reinterpret_cast<char *>(buffer), FILE_BLOCK_SIZE);
169         ret = cipher->update(cipher, &input, &output);
170         if (ret != 0) {
171             LOGE("update failed!");
172             goto CLEAR_UP;
173         }
174         if (output.data != nullptr && output.len > 0) {
175             outfile.write(reinterpret_cast<const char *>(output.data), output.len);
176         }
177         if (output.data != nullptr) {
178             HcfFree(output.data);
179             output.data = nullptr;
180         }
181     }
182     ret = cipher->doFinal(cipher, nullptr, &output);
183     if (ret != 0) {
184         LOGE("doFinal failed!");
185         goto CLEAR_UP;
186     }
187     if (output.data != nullptr && output.len > 0) {
188         outfile.write(reinterpret_cast<const char *>(output.data), output.len);
189     }
190 
191     if (output.data != nullptr) {
192         HcfFree(output.data);
193         output.data = nullptr;
194     }
195 CLEAR_UP:
196     outfile.close();
197     infile.close();
198 
199     return ret;
200 }
201 
AesMultiBlockDecrypt(HcfCipher * cipher,HcfSymKey * key,HcfParamsSpec * params)202 int32_t AesMultiBlockDecrypt(HcfCipher *cipher, HcfSymKey *key, HcfParamsSpec *params)
203 {
204     HcfBlob output = {};
205     ifstream infile;
206     ofstream outfile;
207     infile.open("/data/test_aes_enc.txt", ios::in|ios::binary);
208     infile.seekg (0, infile.end);
209     uint32_t length = infile.tellg();
210     infile.seekg (0, infile.beg);
211     uint8_t buffer[1024] = {0};
212     outfile.open("/data/test_aes_new.txt", ios::out|ios::binary);
213     HcfBlob input = {.data = reinterpret_cast<uint8_t *>(buffer), .len = FILE_BLOCK_SIZE};
214 
215     uint32_t count = length / FILE_BLOCK_SIZE;
216     int32_t ret = cipher->init(cipher, DECRYPT_MODE, reinterpret_cast<HcfKey *>(key), params);
217     if (ret != 0) {
218         LOGE("init failed! %d", ret);
219         goto CLEAR_UP;
220     }
221     for (uint32_t i = 0; i < count; i++) {
222         infile.read(reinterpret_cast<char *>(buffer), FILE_BLOCK_SIZE);
223         ret = cipher->update(cipher, &input, &output);
224         if (ret != 0) {
225             LOGE("update failed!");
226             goto CLEAR_UP;
227         }
228         if (output.data != nullptr && output.len > 0) {
229             outfile.write(reinterpret_cast<const char *>(output.data), output.len);
230         }
231         if (output.data != nullptr) {
232             HcfFree(output.data);
233             output.data = nullptr;
234         }
235     }
236     ret = cipher->doFinal(cipher, nullptr, &output);
237     if (ret != 0) {
238         LOGE("doFinal failed!");
239         goto CLEAR_UP;
240     }
241     if (output.data != nullptr && output.len > 0) {
242         outfile.write(reinterpret_cast<const char *>(output.data), output.len);
243     }
244 
245     if (output.data != nullptr) {
246         HcfFree(output.data);
247         output.data = nullptr;
248     }
249 CLEAR_UP:
250     outfile.close();
251     infile.close();
252 
253     return ret;
254 }
255 
256 // use ECB, test abnormal input
AesEncryptWithInput(HcfCipher * cipher,HcfSymKey * key,HcfBlob * input,uint8_t * cipherText,int * cipherTextLen)257 int32_t AesEncryptWithInput(HcfCipher *cipher, HcfSymKey *key, HcfBlob *input,
258     uint8_t *cipherText, int *cipherTextLen)
259 {
260     HcfBlob output = { .data = nullptr, .len = 0 };
261     int32_t maxLen = *cipherTextLen;
262     int32_t ret = cipher->init(cipher, ENCRYPT_MODE, &(key->key), nullptr);
263     if (ret != 0) {
264         LOGE("init failed! %d", ret);
265         return ret;
266     }
267 
268     ret = cipher->update(cipher, input, &output);
269     if (ret != 0) {
270         LOGE("update failed!");
271         return ret;
272     }
273     *cipherTextLen = output.len;
274     if (output.data != nullptr) {
275         if (memcpy_s(cipherText, maxLen, output.data, output.len) != EOK) {
276             HcfBlobDataFree(&output);
277             return -1;
278         }
279         HcfBlobDataFree(&output);
280     }
281 
282     ret = cipher->doFinal(cipher, nullptr, &output);
283     if (ret != 0) {
284         LOGE("doFinal failed!");
285         return ret;
286     }
287     if (output.data != nullptr) {
288         if (memcpy_s(cipherText + *cipherTextLen, maxLen - *cipherTextLen, output.data, output.len) != EOK) {
289             HcfBlobDataFree(&output);
290             return -1;
291         }
292         *cipherTextLen += output.len;
293         HcfBlobDataFree(&output);
294     }
295 
296     PrintfHex("ciphertext", cipherText, *cipherTextLen);
297     return 0;
298 }
299 
AesEncrypt(HcfCipher * cipher,HcfSymKey * key,HcfParamsSpec * params,uint8_t * cipherText,int * cipherTextLen)300 int32_t AesEncrypt(HcfCipher *cipher, HcfSymKey *key, HcfParamsSpec *params,
301     uint8_t *cipherText, int *cipherTextLen)
302 {
303     uint8_t plainText[] = "this is test!";
304     HcfBlob input = {.data = reinterpret_cast<uint8_t *>(plainText), .len = 13};
305     HcfBlob output = {};
306     int32_t maxLen = *cipherTextLen;
307     int32_t ret = cipher->init(cipher, ENCRYPT_MODE, reinterpret_cast<HcfKey *>(key), params);
308     if (ret != 0) {
309         LOGE("init failed! %d", ret);
310         return ret;
311     }
312 
313     ret = cipher->update(cipher, &input, &output);
314     if (ret != 0) {
315         LOGE("update failed!");
316         return ret;
317     }
318     *cipherTextLen = output.len;
319     if (output.data != nullptr) {
320         if (memcpy_s(cipherText, maxLen, output.data, output.len) != EOK) {
321             HcfBlobDataFree(&output);
322             return -1;
323         }
324         HcfBlobDataFree(&output);
325     }
326 
327     ret = cipher->doFinal(cipher, nullptr, &output);
328     if (ret != 0) {
329         LOGE("doFinal failed!");
330         return ret;
331     }
332     if (output.data != nullptr) {
333         if (memcpy_s(cipherText + *cipherTextLen, maxLen - *cipherTextLen, output.data, output.len) != EOK) {
334             HcfBlobDataFree(&output);
335             return -1;
336         }
337         *cipherTextLen += output.len;
338         HcfBlobDataFree(&output);
339     }
340 
341     PrintfHex("ciphertext", cipherText, *cipherTextLen);
342     return 0;
343 }
344 
AesDecrypt(HcfCipher * cipher,HcfSymKey * key,HcfParamsSpec * params,uint8_t * cipherText,int cipherTextLen)345 int32_t AesDecrypt(HcfCipher *cipher, HcfSymKey *key, HcfParamsSpec *params,
346     uint8_t *cipherText, int cipherTextLen)
347 {
348     uint8_t plainText[] = "this is test!";
349     HcfBlob input = {.data = reinterpret_cast<uint8_t *>(cipherText), .len = cipherTextLen};
350     HcfBlob output = {};
351     int32_t maxLen = cipherTextLen;
352     int32_t ret = cipher->init(cipher, DECRYPT_MODE, reinterpret_cast<HcfKey *>(key), params);
353     if (ret != 0) {
354         LOGE("init failed! %d", ret);
355         return ret;
356     }
357 
358     ret = cipher->update(cipher, &input, &output);
359     if (ret != 0) {
360         LOGE("update failed!");
361         return ret;
362     }
363     cipherTextLen = output.len;
364     if (output.data != nullptr) {
365         if (memcpy_s(cipherText, maxLen, output.data, output.len) != EOK) {
366             HcfBlobDataFree(&output);
367             return -1;
368         }
369         HcfBlobDataFree(&output);
370     }
371 
372     ret = cipher->doFinal(cipher, nullptr, &output);
373     if (ret != 0) {
374         LOGE("doFinal failed!");
375         return ret;
376     }
377     if (output.data != nullptr) {
378         if (memcpy_s(cipherText + cipherTextLen, maxLen - cipherTextLen, output.data, output.len) != EOK) {
379             HcfBlobDataFree(&output);
380             return -1;
381         }
382         cipherTextLen += output.len;
383         HcfBlobDataFree(&output);
384     }
385 
386     PrintfHex("plainText", cipherText, cipherTextLen);
387     if (cipherTextLen != sizeof(plainText) - 1) {
388         return -1;
389     }
390     return memcmp(cipherText, plainText, cipherTextLen);
391 }
392 
AesNoUpdateEncWithInput(HcfCipher * cipher,HcfSymKey * key,HcfBlob * input,uint8_t * cipherText,int * cipherTextLen)393 int32_t AesNoUpdateEncWithInput(HcfCipher *cipher, HcfSymKey *key, HcfBlob *input,
394     uint8_t *cipherText, int *cipherTextLen)
395 {
396     HcfBlob output = { .data = nullptr, .len = 0 };
397     int32_t maxLen = *cipherTextLen;
398     int32_t ret = cipher->init(cipher, ENCRYPT_MODE, &(key->key), nullptr);
399     if (ret != 0) {
400         LOGE("init failed! %d", ret);
401         return ret;
402     }
403 
404     *cipherTextLen = 0;
405     ret = cipher->doFinal(cipher, input, &output);
406     if (ret != 0) {
407         LOGE("doFinal failed!");
408         return ret;
409     }
410     if (output.data != nullptr) {
411         if (memcpy_s(cipherText, maxLen, output.data, output.len) != EOK) {
412             HcfBlobDataFree(&output);
413             return -1;
414         }
415         *cipherTextLen += output.len;
416         HcfBlobDataFree(&output);
417     }
418 
419     PrintfHex("ciphertext", cipherText, *cipherTextLen);
420     return 0;
421 }
422 
423 // test encrypt and decrypt with null plain text
AesDecryptEmptyMsg(HcfCipher * cipher,HcfSymKey * key,HcfParamsSpec * params,uint8_t * cipherText,int cipherTextLen)424 int32_t AesDecryptEmptyMsg(HcfCipher *cipher, HcfSymKey *key, HcfParamsSpec *params,
425     uint8_t *cipherText, int cipherTextLen)
426 {
427     HcfBlob input = { .data = cipherText, .len = cipherTextLen };
428     HcfBlob output = { .data = nullptr, .len = 0 };
429     int32_t ret = cipher->init(cipher, DECRYPT_MODE, &(key->key), params);
430     if (ret != 0) {
431         LOGE("init failed! %d", ret);
432         return ret;
433     }
434 
435     ret = cipher->doFinal(cipher, &input, &output);
436     if (ret != 0) {
437         LOGE("doFinal failed!");
438         return ret;
439     }
440     if (output.len == 0 && output.data == nullptr) {
441         ret = 0;
442     } else {
443         ret = -1;
444     }
445     HcfBlobDataFree(&output);
446     return ret;
447 }
448 
AesNoUpdateEncrypt(HcfCipher * cipher,HcfSymKey * key,HcfParamsSpec * params,uint8_t * cipherText,int * cipherTextLen)449 int32_t AesNoUpdateEncrypt(HcfCipher *cipher, HcfSymKey *key, HcfParamsSpec *params,
450     uint8_t *cipherText, int *cipherTextLen)
451 {
452     uint8_t plainText[] = "this is test!";
453     HcfBlob input = {.data = reinterpret_cast<uint8_t *>(plainText), .len = 13};
454     HcfBlob output = {};
455     int32_t maxLen = *cipherTextLen;
456     int32_t ret = cipher->init(cipher, ENCRYPT_MODE, reinterpret_cast<HcfKey *>(key), params);
457     if (ret != 0) {
458         LOGE("init failed! %d", ret);
459         return ret;
460     }
461 
462     *cipherTextLen = 0;
463     ret = cipher->doFinal(cipher, &input, &output);
464     if (ret != 0) {
465         LOGE("doFinal failed!");
466         return ret;
467     }
468     if (output.data != nullptr) {
469         if (memcpy_s(cipherText, maxLen, output.data, output.len) != EOK) {
470             HcfBlobDataFree(&output);
471             return -1;
472         }
473         *cipherTextLen += output.len;
474         HcfBlobDataFree(&output);
475     }
476 
477     PrintfHex("ciphertext", cipherText, *cipherTextLen);
478     return 0;
479 }
480 
AesNoUpdateDecrypt(HcfCipher * cipher,HcfSymKey * key,HcfParamsSpec * params,uint8_t * cipherText,int cipherTextLen)481 int32_t AesNoUpdateDecrypt(HcfCipher *cipher, HcfSymKey *key, HcfParamsSpec *params,
482     uint8_t *cipherText, int cipherTextLen)
483 {
484     uint8_t plainText[] = "this is test!";
485     HcfBlob input = {.data = reinterpret_cast<uint8_t *>(cipherText), .len = cipherTextLen};
486     HcfBlob output = {};
487     int32_t maxLen = cipherTextLen;
488     int32_t ret = cipher->init(cipher, DECRYPT_MODE, reinterpret_cast<HcfKey *>(key), params);
489     if (ret != 0) {
490         LOGE("init failed! %d", ret);
491         return ret;
492     }
493 
494     cipherTextLen = 0;
495     ret = cipher->doFinal(cipher, &input, &output);
496     if (ret != 0) {
497         LOGE("doFinal failed!");
498         return ret;
499     }
500     if (output.data != nullptr) {
501         if (memcpy_s(cipherText, maxLen, output.data, output.len) != EOK) {
502             HcfBlobDataFree(&output);
503             return -1;
504         }
505         cipherTextLen += output.len;
506         HcfBlobDataFree(&output);
507     }
508 
509     PrintfHex("plainText", cipherText, cipherTextLen);
510     if (cipherTextLen != sizeof(plainText) - 1) {
511         return -1;
512     }
513     return memcmp(cipherText, plainText, cipherTextLen);
514 }