1 /*
2 * Copyright (C) 2022-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 "napi_sm2_crypto_util.h"
17
18 #include <string>
19 #include "securec.h"
20 #include "log.h"
21 #include "memory.h"
22 #include "napi_crypto_framework_defines.h"
23 #include "napi_utils.h"
24
25 namespace OHOS {
26 namespace CryptoFramework {
NapiSm2CryptoUtil()27 NapiSm2CryptoUtil::NapiSm2CryptoUtil() {}
~NapiSm2CryptoUtil()28 NapiSm2CryptoUtil::~NapiSm2CryptoUtil() {}
29
GetBlobFromNapi(napi_env env,napi_value arg,const std::string & name)30 static HcfBlob *GetBlobFromNapi(napi_env env, napi_value arg, const std::string &name)
31 {
32 // get uint8Array attribute
33 napi_value data = nullptr;
34 napi_valuetype valueType = napi_undefined;
35 napi_status status = napi_get_named_property(env, arg, name.c_str(), &data);
36 napi_typeof(env, data, &valueType);
37 if ((status != napi_ok) || (data == nullptr) || (valueType == napi_undefined)) {
38 LOGE("failed to get valid salt");
39 return nullptr;
40 }
41 return GetBlobFromNapiUint8Arr(env, data);
42 }
43
GetSm2CipherTextSpecFromNapiValue(napi_env env,napi_value arg,Sm2CipherTextSpec ** returnSpec)44 static bool GetSm2CipherTextSpecFromNapiValue(napi_env env, napi_value arg, Sm2CipherTextSpec **returnSpec)
45 {
46 if ((env == nullptr) || (arg == nullptr) || (returnSpec == nullptr)) {
47 LOGE("Invalid params.");
48 return false;
49 }
50 Sm2CipherTextSpec *tempSpec = static_cast<Sm2CipherTextSpec *>(HcfMalloc(sizeof(Sm2CipherTextSpec), 0));
51 if (tempSpec == nullptr) {
52 LOGE("Malloc failed!");
53 return false;
54 }
55 napi_value xCoordinate = GetDetailAsyKeySpecValue(env, arg, SM2_UTIL_PARAM_X_COORDINATE);
56 napi_value yCoordinate = GetDetailAsyKeySpecValue(env, arg, SM2_UTIL_PARAM_Y_COORDINATE);
57 if ((xCoordinate == nullptr) || (yCoordinate == nullptr)) {
58 LOGE("Invalid params!");
59 DestroySm2CipherTextSpec(tempSpec);
60 return false;
61 }
62 bool ret = GetBigIntFromNapiValue(env, xCoordinate, &tempSpec->xCoordinate);
63 if (!ret) {
64 LOGE("Failed to get valid x coordinate.");
65 DestroySm2CipherTextSpec(tempSpec);
66 return false;
67 }
68 ret = GetBigIntFromNapiValue(env, yCoordinate, &tempSpec->yCoordinate);
69 if (!ret) {
70 LOGE("Failed to get valid y coordinate.");
71 DestroySm2CipherTextSpec(tempSpec);
72 return false;
73 }
74 HcfBlob *cipherTextBlob = GetBlobFromNapi(env, arg, SM2_UTIL_PARAM_CIPHER_TEXT_DATA);
75 if (cipherTextBlob == nullptr) {
76 LOGE("Failed to get valid cipherTextData.");
77 DestroySm2CipherTextSpec(tempSpec);
78 return false;
79 }
80 HcfBlob *hashDataBlob = GetBlobFromNapi(env, arg, SM2_UTIL_PARAM_HASH_DATA);
81 if (hashDataBlob == nullptr) {
82 LOGE("Failed to get valid hashData.");
83 HcfBlobDataFree(cipherTextBlob);
84 HCF_FREE_PTR(cipherTextBlob);
85 DestroySm2CipherTextSpec(tempSpec);
86 return false;
87 }
88 tempSpec->cipherTextData = *cipherTextBlob;
89 tempSpec->hashData = *hashDataBlob;
90 *returnSpec = tempSpec;
91 HCF_FREE_PTR(cipherTextBlob);
92 HCF_FREE_PTR(hashDataBlob);
93 return true;
94 }
95
DealMode(napi_env env,napi_value arg,std::string & returnStr)96 static bool DealMode(napi_env env, napi_value arg, std::string &returnStr)
97 {
98 napi_valuetype valueType;
99 napi_typeof(env, arg, &valueType);
100 if (valueType == napi_null || valueType == napi_undefined) {
101 return true;
102 }
103 if (!GetStringFromJSParams(env, arg, returnStr)) {
104 return false;
105 }
106 return true;
107 }
108
JsGenCipherTextBySpec(napi_env env,napi_callback_info info)109 napi_value NapiSm2CryptoUtil::JsGenCipherTextBySpec(napi_env env, napi_callback_info info)
110 {
111 size_t expectedArgc = PARAMS_NUM_TWO;
112 size_t argc = ARGS_SIZE_TWO;
113 napi_value argv[ARGS_SIZE_TWO] = { nullptr };
114 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
115 // second attribute mode can be null
116 if ((argc != expectedArgc) && (argc != (expectedArgc - 1))) {
117 LOGE("The input args num is invalid.");
118 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "The input args num is invalid."));
119 return nullptr;
120 }
121 Sm2CipherTextSpec *spec = nullptr;
122 if (!GetSm2CipherTextSpecFromNapiValue(env, argv[0], &spec)) {
123 LOGE("Failed to get spec.");
124 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to get spec."));
125 return nullptr;
126 }
127 std::string dataMode;
128 if (argc == expectedArgc) {
129 if (!DealMode(env, argv[1], dataMode)) {
130 LOGE("Failed to get mode.");
131 DestroySm2CipherTextSpec(spec);
132 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to get mode."));
133 return nullptr;
134 }
135 }
136 HcfBlob *output = static_cast<HcfBlob *>(HcfMalloc(sizeof(HcfBlob), 0));
137 if (output == NULL) {
138 LOGE("Failed to allocate HcfBlob memory!");
139 DestroySm2CipherTextSpec(spec);
140 napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "Failed to allocate memory."));
141 return nullptr;
142 }
143 HcfResult res = HcfGenCipherTextBySpec(spec, dataMode.c_str(), output);
144 if (res != HCF_SUCCESS) {
145 LOGE("Gen cipher text by spec fail.");
146 HcfFree(output);
147 output = nullptr;
148 DestroySm2CipherTextSpec(spec);
149 napi_throw(env, GenerateBusinessError(env, res, "gen cipher text by spec fail."));
150 return nullptr;
151 }
152 napi_value instance = ConvertBlobToNapiValue(env, output);
153 HcfBlobDataFree(output);
154 HcfFree(output);
155 output = nullptr;
156 DestroySm2CipherTextSpec(spec);
157 return instance;
158 }
159
CheckSm2CipherTextSpec(Sm2CipherTextSpec * spec)160 static bool CheckSm2CipherTextSpec(Sm2CipherTextSpec *spec)
161 {
162 if (spec == nullptr) {
163 LOGE("Invalid spec!");
164 return false;
165 }
166 if (spec->xCoordinate.data == nullptr || spec->xCoordinate.len == 0) {
167 LOGE("Invalid xCoordinate!");
168 return false;
169 }
170 if (spec->yCoordinate.data == nullptr || spec->yCoordinate.len == 0) {
171 LOGE("Invalid yCoordinate!");
172 return false;
173 }
174 if (spec->cipherTextData.data == nullptr || spec->cipherTextData.len == 0) {
175 LOGE("Invalid cipherTextData!");
176 return false;
177 }
178 if (spec->hashData.data == nullptr || spec->hashData.len == 0) {
179 LOGE("Invalid hashData!");
180 return false;
181 }
182 return true;
183 }
184
BuildBlobNapiValue(napi_env env,HcfBlob * blob,const char * name,napi_value * instance)185 static bool BuildBlobNapiValue(napi_env env, HcfBlob *blob, const char *name, napi_value *instance)
186 {
187 napi_value napiData = ConvertObjectBlobToNapiValue(env, blob);
188 napi_status status = napi_set_named_property(env, *instance, name, napiData);
189 if (status != napi_ok) {
190 LOGE("Build blob[napi_value] failed!");
191 return false;
192 }
193 return true;
194 }
195
BuildSm2CipherTextSpecToNapiValue(napi_env env,Sm2CipherTextSpec * spec,napi_value * instance)196 static bool BuildSm2CipherTextSpecToNapiValue(napi_env env, Sm2CipherTextSpec *spec, napi_value *instance)
197 {
198 if (!BuildSetNamedProperty(env, &(spec->xCoordinate), SM2_UTIL_PARAM_X_COORDINATE.c_str(), instance)) {
199 LOGE("Build xCoordinate failed!");
200 return false;
201 }
202 if (!BuildSetNamedProperty(env, &(spec->yCoordinate), SM2_UTIL_PARAM_Y_COORDINATE.c_str(), instance)) {
203 LOGE("Build yCoordinate failed!");
204 return false;
205 }
206 if (!BuildBlobNapiValue(env, &(spec->cipherTextData), SM2_UTIL_PARAM_CIPHER_TEXT_DATA.c_str(), instance)) {
207 LOGE("Build cipherTextData failed!");
208 return false;
209 }
210 if (!BuildBlobNapiValue(env, &(spec->hashData), SM2_UTIL_PARAM_HASH_DATA.c_str(), instance)) {
211 LOGE("Build hashData failed!");
212 return false;
213 }
214 return true;
215 }
216
ConvertSm2CipherTextSpecToNapiValue(napi_env env,Sm2CipherTextSpec * spec)217 static napi_value ConvertSm2CipherTextSpecToNapiValue(napi_env env, Sm2CipherTextSpec *spec)
218 {
219 if (!CheckSm2CipherTextSpec(spec)) {
220 LOGE("Invalid spec!");
221 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "Invalid spec!"));
222 return NapiGetNull(env);
223 }
224 napi_value instance;
225 napi_status status = napi_create_object(env, &instance);
226 if (status != napi_ok) {
227 LOGE("Create object failed!");
228 napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "create object failed!"));
229 return NapiGetNull(env);
230 }
231 if (!BuildSm2CipherTextSpecToNapiValue(env, spec, &instance)) {
232 LOGE("Build object failed!");
233 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "build object failed!"));
234 return NapiGetNull(env);
235 }
236 return instance;
237 }
238
JsGetCipherTextSpec(napi_env env,napi_callback_info info)239 napi_value NapiSm2CryptoUtil::JsGetCipherTextSpec(napi_env env, napi_callback_info info)
240 {
241 size_t expectedArgc = PARAMS_NUM_TWO;
242 size_t argc = ARGS_SIZE_TWO;
243 napi_value argv[ARGS_SIZE_TWO] = { nullptr };
244 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
245 // second attribute mode can be null
246 if ((argc != expectedArgc) && (argc != (expectedArgc - 1))) {
247 LOGE("The input args num is invalid.");
248 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "The input args num is invalid."));
249 return nullptr;
250 }
251 HcfBlob *cipherText = GetBlobFromNapiDataBlob(env, argv[0]);
252 if (cipherText == nullptr) {
253 LOGE("Failed to get cipherText.");
254 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to get cipherText."));
255 return nullptr;
256 }
257 std::string dataMode;
258 if (argc == expectedArgc) {
259 if (!DealMode(env, argv[1], dataMode)) {
260 LOGE("Failed to get mode.");
261 HcfBlobDataFree(cipherText);
262 HcfFree(cipherText);
263 cipherText = nullptr;
264 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to get mode."));
265 return nullptr;
266 }
267 }
268 Sm2CipherTextSpec *returnSpec = nullptr;
269 HcfResult res = HcfGetCipherTextSpec(cipherText, dataMode.c_str(), &returnSpec);
270 if (res != HCF_SUCCESS) {
271 LOGE("Get cipher text spec fail.");
272 HcfBlobDataFree(cipherText);
273 HcfFree(cipherText);
274 cipherText = nullptr;
275 napi_throw(env, GenerateBusinessError(env, res, "get cipher text spec fail."));
276 return nullptr;
277 }
278 napi_value instance = ConvertSm2CipherTextSpecToNapiValue(env, returnSpec);
279 DestroySm2CipherTextSpec(returnSpec);
280 HcfBlobDataFree(cipherText);
281 HcfFree(cipherText);
282 cipherText = nullptr;
283 return instance;
284 }
285
Sm2CryptoUtilConstructor(napi_env env,napi_callback_info info)286 napi_value NapiSm2CryptoUtil::Sm2CryptoUtilConstructor(napi_env env, napi_callback_info info)
287 {
288 napi_value thisVar = nullptr;
289 size_t argc = ARGS_SIZE_ONE;
290 napi_value argv[ARGS_SIZE_ONE] = { nullptr };
291 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
292 return thisVar;
293 }
294
Sm2CryptoUtilConstructorClass(napi_env env)295 napi_value NapiSm2CryptoUtil::Sm2CryptoUtilConstructorClass(napi_env env)
296 {
297 napi_value cons = nullptr;
298 napi_property_descriptor clzDes[] = {
299 DECLARE_NAPI_STATIC_FUNCTION("genCipherTextBySpec", NapiSm2CryptoUtil::JsGenCipherTextBySpec),
300 DECLARE_NAPI_STATIC_FUNCTION("getCipherTextSpec", NapiSm2CryptoUtil::JsGetCipherTextSpec),
301 };
302 NAPI_CALL(env, napi_define_class(env, "SM2CryptoUtil", NAPI_AUTO_LENGTH,
303 NapiSm2CryptoUtil::Sm2CryptoUtilConstructor,
304 nullptr, sizeof(clzDes) / sizeof(clzDes[0]), clzDes, &cons));
305 return cons;
306 }
307
DefineNapiSm2CryptoUtilJSClass(napi_env env,napi_value exports)308 void NapiSm2CryptoUtil::DefineNapiSm2CryptoUtilJSClass(napi_env env, napi_value exports)
309 {
310 napi_set_named_property(env, exports, "SM2CryptoUtil", NapiSm2CryptoUtil::Sm2CryptoUtilConstructorClass(env));
311 }
312 } // CryptoFramework
313 } // OHOS
314