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 }