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
33using namespace std;
34
35HcfResult 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
53int32_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
73int32_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
116int32_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
142int32_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
185int32_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
232int32_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
262int32_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
296const char *GetMockClass(void)
297{
298    return "HcfMock";
299}
300
301HcfObjectBase obj = {
302    .getClass = GetMockClass,
303    .destroy = nullptr
304};