1 /*
2  * Copyright (C) 2023 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 "cipher_sm2_openssl.h"
17 #include <stdbool.h>
18 #include <string.h>
19 #include "log.h"
20 #include "memory.h"
21 #include "openssl_adapter.h"
22 #include "openssl_class.h"
23 #include "openssl_common.h"
24 #include "securec.h"
25 #include "utils.h"
26 
27 typedef struct {
28     HcfCipherGeneratorSpi super;
29 
30     CipherAttr attr;
31 
32     CryptoStatus initFlag;
33 
34     EC_KEY *sm2Key;
35 
36     EVP_MD *sm2Digest;
37 } HcfCipherSm2GeneratorSpiImpl;
38 
EngineGetClass(void)39 static const char *EngineGetClass(void)
40 {
41     return OPENSSL_SM2_CIPHER_CLASS;
42 }
43 
CheckCipherInitParams(enum HcfCryptoMode opMode,HcfKey * key)44 static HcfResult CheckCipherInitParams(enum HcfCryptoMode opMode, HcfKey *key)
45 {
46     switch (opMode) {
47         case ENCRYPT_MODE:
48             if (!HcfIsClassMatch((HcfObjectBase *)key, HCF_OPENSSL_SM2_PUB_KEY_CLASS)) {
49                 LOGE("Class not match");
50                 return HCF_INVALID_PARAMS;
51             }
52             break;
53         case DECRYPT_MODE:
54             if (!HcfIsClassMatch((HcfObjectBase *)key, HCF_OPENSSL_SM2_PRI_KEY_CLASS)) {
55                 LOGE("Class not match");
56                 return HCF_INVALID_PARAMS;
57             }
58             break;
59         default:
60             LOGE("Invalid opMode %d", opMode);
61             return HCF_INVALID_PARAMS;
62     }
63 
64     return HCF_SUCCESS;
65 }
66 
InitSm2Key(HcfCipherSm2GeneratorSpiImpl * impl,HcfKey * key,enum HcfCryptoMode opMode)67 static HcfResult InitSm2Key(HcfCipherSm2GeneratorSpiImpl *impl, HcfKey *key, enum HcfCryptoMode opMode)
68 {
69     if (opMode == ENCRYPT_MODE) {
70         impl->sm2Key = OpensslEcKeyDup(((HcfOpensslSm2PubKey *)key)->ecKey);
71     } else if (opMode == DECRYPT_MODE) {
72         // dup will check if ecKey is NULL
73         impl->sm2Key = OpensslEcKeyDup(((HcfOpensslSm2PriKey *)key)->ecKey);
74     } else {
75         LOGE("OpMode not match.");
76         return HCF_INVALID_PARAMS;
77     }
78     if (impl->sm2Key == NULL) {
79         HcfPrintOpensslError();
80         return HCF_ERR_CRYPTO_OPERATION;
81     }
82     return HCF_SUCCESS;
83 }
84 
GetSm2CipherSpecString(HcfCipherGeneratorSpi * self,CipherSpecItem item,char ** returnString)85 static HcfResult GetSm2CipherSpecString(HcfCipherGeneratorSpi *self, CipherSpecItem item, char **returnString)
86 {
87     if (self == NULL || returnString == NULL) {
88         LOGE("Param is invalid.");
89         return HCF_INVALID_PARAMS;
90     }
91     if (!HcfIsClassMatch((HcfObjectBase *)self, EngineGetClass())) {
92         LOGE("Class not match");
93         return HCF_INVALID_PARAMS;
94     }
95     if (item != SM2_MD_NAME_STR) {
96         LOGE("Invalid input cipher spec");
97         return HCF_INVALID_PARAMS;
98     }
99     // only support sm3
100     return GetSm2SpecStringSm3(returnString);
101 }
102 
GetSm2CipherSpecUint8Array(HcfCipherGeneratorSpi * self,CipherSpecItem item,HcfBlob * returnUint8Array)103 static HcfResult GetSm2CipherSpecUint8Array(HcfCipherGeneratorSpi *self, CipherSpecItem item, HcfBlob *returnUint8Array)
104 {
105     (void)self;
106     (void)item;
107     (void)returnUint8Array;
108     return HCF_NOT_SUPPORT;
109 }
110 
SetSm2CipherSpecUint8Array(HcfCipherGeneratorSpi * self,CipherSpecItem item,HcfBlob blob)111 static HcfResult SetSm2CipherSpecUint8Array(HcfCipherGeneratorSpi *self, CipherSpecItem item, HcfBlob blob)
112 {
113     (void)self;
114     (void)item;
115     (void)blob;
116     return HCF_NOT_SUPPORT;
117 }
118 
EngineInit(HcfCipherGeneratorSpi * self,enum HcfCryptoMode opMode,HcfKey * key,HcfParamsSpec * params)119 static HcfResult EngineInit(HcfCipherGeneratorSpi *self, enum HcfCryptoMode opMode,
120     HcfKey *key, HcfParamsSpec *params)
121 {
122     (void)params;
123     if (self == NULL || key == NULL) {
124         LOGE("Param is invalid.");
125         return HCF_INVALID_PARAMS;
126     }
127     if (!HcfIsClassMatch((HcfObjectBase *)self, self->base.getClass())) {
128         LOGE("Class not match");
129         return HCF_INVALID_PARAMS;
130     }
131     HcfCipherSm2GeneratorSpiImpl *impl = (HcfCipherSm2GeneratorSpiImpl *)self;
132     if (impl->initFlag != UNINITIALIZED) {
133         LOGE("The cipher has been initialize, don't init again.");
134         return HCF_INVALID_PARAMS;
135     }
136     // check opMode is matched with Key
137     if (CheckCipherInitParams(opMode, key) != HCF_SUCCESS) {
138         LOGE("OpMode dismatch with keyType.");
139         return HCF_INVALID_PARAMS;
140     }
141     impl->attr.mode = (int32_t)opMode;
142     if (InitSm2Key(impl, key, opMode) != HCF_SUCCESS) {
143         LOGD("[error] InitSm2Key fail");
144         return HCF_ERR_CRYPTO_OPERATION;
145     }
146     impl->initFlag = INITIALIZED;
147     return HCF_SUCCESS;
148 }
149 
EngineUpdate(HcfCipherGeneratorSpi * self,HcfBlob * input,HcfBlob * output)150 static HcfResult EngineUpdate(HcfCipherGeneratorSpi *self, HcfBlob *input, HcfBlob *output)
151 {
152     LOGD("[error] Openssl don't support update");
153     (void)self;
154     (void)input;
155     (void)output;
156     return HCF_NOT_SUPPORT;
157 }
158 
GetTextLen(HcfCipherSm2GeneratorSpiImpl * impl,HcfBlob * input,int32_t mode)159 static size_t GetTextLen(HcfCipherSm2GeneratorSpiImpl *impl, HcfBlob *input, int32_t mode)
160 {
161     size_t textLen = 0;
162     if (mode == ENCRYPT_MODE) {
163         if (OpensslSm2CipherTextSize(impl->sm2Key, impl->sm2Digest, input->len, &textLen) != HCF_OPENSSL_SUCCESS) {
164             LOGD("[error] Failed to get ciphertext size!");
165             HcfPrintOpensslError();
166             return 0;
167         }
168     } else if (mode == DECRYPT_MODE) {
169         if (OpensslSm2PlainTextSize(input->data, input->len, &textLen) != HCF_OPENSSL_SUCCESS) {
170             LOGD("[error] Failed to get plaintext size!");
171             HcfPrintOpensslError();
172             return 0;
173         }
174     } else {
175         LOGD("[error] invalid ops!");
176     }
177     return textLen;
178 }
179 
DoSm2EncryptAndDecrypt(HcfCipherSm2GeneratorSpiImpl * impl,HcfBlob * input,HcfBlob * output,int32_t mode,size_t textLen)180 static HcfResult DoSm2EncryptAndDecrypt(HcfCipherSm2GeneratorSpiImpl *impl, HcfBlob *input, HcfBlob *output,
181     int32_t mode, size_t textLen)
182 {
183     uint8_t *outputText = (uint8_t *)HcfMalloc(sizeof(uint8_t) * textLen, 0);
184     if (outputText == NULL) {
185         LOGE("Failed to allocate plaintext memory!");
186         return HCF_ERR_MALLOC;
187     }
188     int32_t ret = HCF_OPENSSL_SUCCESS;
189     if (mode == ENCRYPT_MODE) {
190         ret = OpensslOsslSm2Encrypt(impl->sm2Key, impl->sm2Digest, input->data, input->len, outputText, &textLen);
191     } else if (mode == DECRYPT_MODE) {
192         ret = OpensslOsslSm2Decrypt(impl->sm2Key, impl->sm2Digest, input->data, input->len, outputText, &textLen);
193     } else {
194         LOGE("OpMode is invalid.");
195         HcfFree(outputText);
196         return HCF_INVALID_PARAMS;
197     }
198     if (ret != HCF_OPENSSL_SUCCESS) {
199         LOGD("[error] SM2 openssl error");
200         HcfFree(outputText);
201         HcfPrintOpensslError();
202         return HCF_ERR_CRYPTO_OPERATION;
203     }
204     output->data = outputText;
205     output->len = textLen;
206     return HCF_SUCCESS;
207 }
208 
DoSm2Crypt(HcfCipherSm2GeneratorSpiImpl * impl,HcfBlob * input,HcfBlob * output,int32_t mode)209 static HcfResult DoSm2Crypt(HcfCipherSm2GeneratorSpiImpl *impl, HcfBlob *input, HcfBlob *output, int32_t mode)
210 {
211     size_t textLen = GetTextLen(impl, input, mode);
212     if (textLen == 0) {
213         LOGD("[error] textLen is 0");
214         return HCF_ERR_CRYPTO_OPERATION;
215     }
216     if (DoSm2EncryptAndDecrypt(impl, input, output, mode, textLen) != HCF_SUCCESS) {
217         return HCF_ERR_CRYPTO_OPERATION;
218     }
219     return HCF_SUCCESS;
220 }
221 
EngineDoFinal(HcfCipherGeneratorSpi * self,HcfBlob * input,HcfBlob * output)222 static HcfResult EngineDoFinal(HcfCipherGeneratorSpi *self, HcfBlob *input, HcfBlob *output)
223 {
224     if (self == NULL || input == NULL || input->data == NULL || output == NULL) {
225         LOGE("Param is invalid.");
226         return HCF_INVALID_PARAMS;
227     }
228 
229     if (!HcfIsClassMatch((HcfObjectBase *)self, self->base.getClass())) {
230         LOGE("Class not match");
231         return HCF_INVALID_PARAMS;
232     }
233 
234     HcfCipherSm2GeneratorSpiImpl *impl = (HcfCipherSm2GeneratorSpiImpl *)self;
235     if (impl->initFlag != INITIALIZED) {
236         LOGE("SM2Cipher has not been init");
237         return HCF_INVALID_PARAMS;
238     }
239     CipherAttr attr = impl->attr;
240     output->len = 0;
241     output->data = NULL;
242     HcfResult ret = DoSm2Crypt(impl, input, output, attr.mode);
243     if (ret != HCF_SUCCESS) {
244         LOGD("[error] GetOutLen fail.");
245         return HCF_ERR_CRYPTO_OPERATION;
246     }
247     return HCF_SUCCESS;
248 }
249 
EngineDestroySpiImpl(HcfObjectBase * generator)250 static void EngineDestroySpiImpl(HcfObjectBase *generator)
251 {
252     if (generator == NULL) {
253         return;
254     }
255     if (!HcfIsClassMatch(generator, generator->getClass())) {
256         LOGE("Class not match");
257         return;
258     }
259     HcfCipherSm2GeneratorSpiImpl *impl = (HcfCipherSm2GeneratorSpiImpl *)generator;
260     impl->sm2Digest = NULL;
261     if (impl->sm2Key != NULL) {
262         OpensslEcKeyFree(impl->sm2Key);
263         impl->sm2Key = NULL;
264     }
265     HcfFree(impl);
266     impl = NULL;
267 }
268 
HcfCipherSm2CipherSpiCreate(CipherAttr * params,HcfCipherGeneratorSpi ** generator)269 HcfResult HcfCipherSm2CipherSpiCreate(CipherAttr *params, HcfCipherGeneratorSpi **generator)
270 {
271     if (generator == NULL || params == NULL) {
272         LOGE("Invalid input parameter.");
273         return HCF_INVALID_PARAMS;
274     }
275     HcfCipherSm2GeneratorSpiImpl *returnImpl = (HcfCipherSm2GeneratorSpiImpl *)HcfMalloc(
276         sizeof(HcfCipherSm2GeneratorSpiImpl), 0);
277     if (returnImpl == NULL) {
278         LOGE("Malloc sm2 cipher fail.");
279         return HCF_ERR_MALLOC;
280     }
281     (void)memcpy_s(&returnImpl->attr, sizeof(CipherAttr), params, sizeof(CipherAttr));
282 
283     EVP_MD *getMD = NULL;
284     HcfResult ret = GetOpensslDigestAlg(returnImpl->attr.md, &getMD);
285     if (ret != HCF_SUCCESS || getMD == NULL) {
286         LOGE("get md failed");
287         HcfFree(returnImpl);
288         return HCF_INVALID_PARAMS;
289     }
290     returnImpl->sm2Digest = getMD;
291 
292     returnImpl->super.init = EngineInit;
293     returnImpl->super.update = EngineUpdate;
294     returnImpl->super.doFinal = EngineDoFinal;
295     returnImpl->super.getCipherSpecString = GetSm2CipherSpecString;
296     returnImpl->super.getCipherSpecUint8Array = GetSm2CipherSpecUint8Array;
297     returnImpl->super.setCipherSpecUint8Array = SetSm2CipherSpecUint8Array;
298     returnImpl->super.base.destroy = EngineDestroySpiImpl;
299     returnImpl->super.base.getClass = EngineGetClass;
300     returnImpl->initFlag = UNINITIALIZED;
301     *generator = (HcfCipherGeneratorSpi *)returnImpl;
302     LOGD("Sm2 Cipher create success.");
303     return HCF_SUCCESS;
304 }