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 <fstream>
17 #include <iostream>
18 #include "securec.h"
19 #include "aes_openssl.h"
20 #include "aes_common.h"
21 #include "blob.h"
22 #include "cipher.h"
23 #include "detailed_iv_params.h"
24 #include "detailed_gcm_params.h"
25 #include "detailed_ccm_params.h"
26 #include "log.h"
27 #include "memory.h"
28 #include "sym_common_defines.h"
29 #include "sym_key_generator.h"
30 #include "sm4_common.h"
31 #include "sm4_openssl.h"
32 
33 using namespace std;
34 
GenerateSm4SymKey(HcfSymKey ** key)35 HcfResult GenerateSm4SymKey(HcfSymKey **key)
36 {
37     HcfSymKeyGenerator *generator = nullptr;
38 
39     HcfResult ret = HcfSymKeyGeneratorCreate("SM4_128", &generator);
40     if (ret != HCF_SUCCESS || generator == nullptr) {
41         LOGE("HcfSymKeyGeneratorCreate failed!");
42         return ret;
43     }
44 
45     ret = generator->generateSymKey(generator, key);
46     if (ret != HCF_SUCCESS) {
47         LOGE("generateSymKey failed!");
48     }
49     HcfObjDestroy(generator);
50     return ret;
51 }
52 
GenerateSymKeyForSm4(const char * algoName,HcfSymKey ** key)53 int32_t GenerateSymKeyForSm4(const char *algoName, HcfSymKey **key)
54 {
55     HcfSymKeyGenerator *generator = nullptr;
56 
57     int32_t ret = HcfSymKeyGeneratorCreate(algoName, &generator);
58     if (ret != 0 || generator == nullptr) {
59         LOGE("HcfSymKeyGeneratorCreate failed!");
60         return ret;
61     }
62 
63     ret = generator->generateSymKey(generator, key);
64     if (ret != 0) {
65         LOGE("generateSymKey failed!");
66     }
67     HcfObjDestroy(reinterpret_cast<HcfObjectBase *>(generator));
68     return ret;
69 }
70 
71 
72 // use ECB, test abnormal input
Sm4EncryptWithInput(HcfCipher * cipher,HcfSymKey * key,HcfBlob * input,uint8_t * cipherText,int * cipherTextLen)73 int32_t Sm4EncryptWithInput(HcfCipher *cipher, HcfSymKey *key, HcfBlob *input,
74     uint8_t *cipherText, int *cipherTextLen)
75 {
76     HcfBlob output = { .data = nullptr, .len = 0 };
77     int32_t maxLen = *cipherTextLen;
78     int32_t ret = cipher->init(cipher, ENCRYPT_MODE, &(key->key), nullptr);
79     if (ret != 0) {
80         LOGE("init failed! %d", ret);
81         return ret;
82     }
83 
84     ret = cipher->update(cipher, input, &output);
85     if (ret != 0) {
86         LOGE("update failed!");
87         return ret;
88     }
89     *cipherTextLen = output.len;
90     if (output.data != nullptr) {
91         if (memcpy_s(cipherText, maxLen, output.data, output.len) != EOK) {
92             HcfBlobDataFree(&output);
93             return -1;
94         }
95         HcfBlobDataFree(&output);
96     }
97 
98     ret = cipher->doFinal(cipher, nullptr, &output);
99     if (ret != 0) {
100         LOGE("doFinal failed!");
101         return ret;
102     }
103     if (output.data != nullptr) {
104         if (memcpy_s(cipherText + *cipherTextLen, maxLen - *cipherTextLen, output.data, output.len) != EOK) {
105             HcfBlobDataFree(&output);
106             return -1;
107         }
108         *cipherTextLen += output.len;
109         HcfBlobDataFree(&output);
110     }
111 
112     return 0;
113 }
114 
115 // test encrypt and decrypt with null plain text
Sm4DecryptEmptyMsg(HcfCipher * cipher,HcfSymKey * key,HcfParamsSpec * params,uint8_t * cipherText,int cipherTextLen)116 int32_t Sm4DecryptEmptyMsg(HcfCipher *cipher, HcfSymKey *key, HcfParamsSpec *params,
117     uint8_t *cipherText, int cipherTextLen)
118 {
119     HcfBlob input = { .data = cipherText, .len = cipherTextLen };
120     HcfBlob output = { .data = nullptr, .len = 0 };
121     int32_t ret = cipher->init(cipher, DECRYPT_MODE, &(key->key), params);
122     if (ret != 0) {
123         LOGE("init failed! %d", ret);
124         return ret;
125     }
126 
127     ret = cipher->doFinal(cipher, &input, &output);
128     if (ret != 0) {
129         LOGE("doFinal failed!");
130         return ret;
131     }
132     if (output.len == 0 && output.data == nullptr) {
133         ret = 0;
134     } else {
135         ret = -1;
136     }
137     HcfBlobDataFree(&output);
138     return ret;
139 }
140 
141 
Sm4Encrypt(HcfCipher * cipher,HcfSymKey * key,HcfParamsSpec * params,uint8_t * cipherText,int * cipherTextLen)142 int32_t Sm4Encrypt(HcfCipher *cipher, HcfSymKey *key, HcfParamsSpec *params,
143     uint8_t *cipherText, int *cipherTextLen)
144 {
145     uint8_t plainText[] = "this is test!";
146     HcfBlob input = {.data = reinterpret_cast<uint8_t *>(plainText), .len = 13};
147     HcfBlob output = {};
148     int32_t maxLen = *cipherTextLen;
149     int32_t ret = cipher->init(cipher, ENCRYPT_MODE, reinterpret_cast<HcfKey *>(key), params);
150     if (ret != 0) {
151         LOGE("init failed! ");
152         return ret;
153     }
154 
155     ret = cipher->update(cipher, &input, &output);
156     if (ret != 0) {
157         LOGE("update failed!");
158         return ret;
159     }
160     *cipherTextLen = output.len;
161     if (output.data != nullptr) {
162         if (memcpy_s(cipherText, maxLen, output.data, output.len) != EOK) {
163             HcfBlobDataFree(&output);
164             return -1;
165         }
166         HcfBlobDataFree(&output);
167     }
168 
169     ret = cipher->doFinal(cipher, nullptr, &output);
170     if (ret != 0) {
171         LOGE("doFinal failed!");
172         return ret;
173     }
174     if (output.data != nullptr) {
175         if (memcpy_s(cipherText + *cipherTextLen, maxLen - *cipherTextLen, output.data, output.len) != EOK) {
176             HcfBlobDataFree(&output);
177             return -1;
178         }
179         *cipherTextLen += output.len;
180         HcfBlobDataFree(&output);
181     }
182     return 0;
183 }
184 
Sm4Decrypt(HcfCipher * cipher,HcfSymKey * key,HcfParamsSpec * params,uint8_t * cipherText,int cipherTextLen)185 int32_t Sm4Decrypt(HcfCipher *cipher, HcfSymKey *key, HcfParamsSpec *params,
186     uint8_t *cipherText, int cipherTextLen)
187 {
188     uint8_t plainText[] = "this is test!";
189     HcfBlob input = {.data = reinterpret_cast<uint8_t *>(cipherText), .len = cipherTextLen};
190     HcfBlob output = {};
191     int32_t maxLen = cipherTextLen;
192     int32_t ret = cipher->init(cipher, DECRYPT_MODE, reinterpret_cast<HcfKey *>(key), params);
193     if (ret != 0) {
194         LOGE("init failed! ");
195         return ret;
196     }
197 
198     ret = cipher->update(cipher, &input, &output);
199     if (ret != 0) {
200         LOGE("update failed!");
201         return ret;
202     }
203     cipherTextLen = output.len;
204     if (output.data != nullptr) {
205         if (memcpy_s(cipherText, maxLen, output.data, output.len) != EOK) {
206             HcfBlobDataFree(&output);
207             return -1;
208         }
209         HcfBlobDataFree(&output);
210     }
211 
212     ret = cipher->doFinal(cipher, nullptr, &output);
213     if (ret != 0) {
214         LOGE("doFinal failed!");
215         return ret;
216     }
217     if (output.data != nullptr) {
218         if (memcpy_s(cipherText + cipherTextLen, maxLen - cipherTextLen, output.data, output.len) != EOK) {
219             HcfBlobDataFree(&output);
220             return -1;
221         }
222         cipherTextLen += output.len;
223         HcfBlobDataFree(&output);
224     }
225 
226     if (cipherTextLen != sizeof(plainText) - 1) {
227         return -1;
228     }
229     return memcmp(cipherText, plainText, cipherTextLen);
230 }
231 
Sm4NoUpdateEncrypt(HcfCipher * cipher,HcfSymKey * key,HcfParamsSpec * params,uint8_t * cipherText,int * cipherTextLen)232 int32_t Sm4NoUpdateEncrypt(HcfCipher *cipher, HcfSymKey *key, HcfParamsSpec *params,
233     uint8_t *cipherText, int *cipherTextLen)
234 {
235     uint8_t plainText[] = "this is test!";
236     HcfBlob input = {.data = reinterpret_cast<uint8_t *>(plainText), .len = 13};
237     HcfBlob output = {};
238     int32_t maxLen = *cipherTextLen;
239     int32_t ret = cipher->init(cipher, ENCRYPT_MODE, reinterpret_cast<HcfKey *>(key), params);
240     if (ret != 0) {
241         LOGE("init failed! ");
242         return ret;
243     }
244 
245     *cipherTextLen = 0;
246     ret = cipher->doFinal(cipher, &input, &output);
247     if (ret != 0) {
248         LOGE("doFinal failed!");
249         return ret;
250     }
251     if (output.data != nullptr) {
252         if (memcpy_s(cipherText, maxLen, output.data, output.len) != EOK) {
253             HcfBlobDataFree(&output);
254             return -1;
255         }
256         *cipherTextLen += output.len;
257         HcfBlobDataFree(&output);
258     }
259     return 0;
260 }
261 
Sm4NoUpdateDecrypt(HcfCipher * cipher,HcfSymKey * key,HcfParamsSpec * params,uint8_t * cipherText,int cipherTextLen)262 int32_t Sm4NoUpdateDecrypt(HcfCipher *cipher, HcfSymKey *key, HcfParamsSpec *params,
263     uint8_t *cipherText, int cipherTextLen)
264 {
265     uint8_t plainText[] = "this is test!";
266     HcfBlob input = {.data = reinterpret_cast<uint8_t *>(cipherText), .len = cipherTextLen};
267     HcfBlob output = {};
268     int32_t maxLen = cipherTextLen;
269     int32_t ret = cipher->init(cipher, DECRYPT_MODE, reinterpret_cast<HcfKey *>(key), params);
270     if (ret != 0) {
271         LOGE("init failed! ");
272         return ret;
273     }
274 
275     cipherTextLen = 0;
276     ret = cipher->doFinal(cipher, &input, &output);
277     if (ret != 0) {
278         LOGE("doFinal failed!");
279         return ret;
280     }
281     if (output.data != nullptr) {
282         if (memcpy_s(cipherText, maxLen, output.data, output.len) != EOK) {
283             HcfBlobDataFree(&output);
284             return -1;
285         }
286         cipherTextLen += output.len;
287         HcfBlobDataFree(&output);
288     }
289 
290     if (cipherTextLen != sizeof(plainText) - 1) {
291         return -1;
292     }
293     return memcmp(cipherText, plainText, cipherTextLen);
294 }
295 
GetMockClass(void)296 const char *GetMockClass(void)
297 {
298     return "HcfMock";
299 }
300 
301 HcfObjectBase obj = {
302     .getClass = GetMockClass,
303     .destroy = nullptr
304 };