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 HcfFree(cipherTextBlob);
85 DestroySm2CipherTextSpec(tempSpec);
86 return false;
87 }
88 tempSpec->cipherTextData = *cipherTextBlob;
89 tempSpec->hashData = *hashDataBlob;
90 *returnSpec = tempSpec;
91 HcfFree(cipherTextBlob);
92 HcfFree(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 DestroySm2CipherTextSpec(spec);
148 napi_throw(env, GenerateBusinessError(env, res, "gen cipher text by spec fail."));
149 return nullptr;
150 }
151 napi_value instance = ConvertBlobToNapiValue(env, output);
152 HcfBlobDataFree(output);
153 HcfFree(output);
154 DestroySm2CipherTextSpec(spec);
155 return instance;
156 }
157
CheckSm2CipherTextSpec(Sm2CipherTextSpec * spec)158 static bool CheckSm2CipherTextSpec(Sm2CipherTextSpec *spec)
159 {
160 if (spec == nullptr) {
161 LOGE("Invalid spec!");
162 return false;
163 }
164 if (spec->xCoordinate.data == nullptr || spec->xCoordinate.len == 0) {
165 LOGE("Invalid xCoordinate!");
166 return false;
167 }
168 if (spec->yCoordinate.data == nullptr || spec->yCoordinate.len == 0) {
169 LOGE("Invalid yCoordinate!");
170 return false;
171 }
172 if (spec->cipherTextData.data == nullptr || spec->cipherTextData.len == 0) {
173 LOGE("Invalid cipherTextData!");
174 return false;
175 }
176 if (spec->hashData.data == nullptr || spec->hashData.len == 0) {
177 LOGE("Invalid hashData!");
178 return false;
179 }
180 return true;
181 }
182
BuildBlobNapiValue(napi_env env,HcfBlob * blob,const char * name,napi_value * instance)183 static bool BuildBlobNapiValue(napi_env env, HcfBlob *blob, const char *name, napi_value *instance)
184 {
185 napi_value napiData = ConvertObjectBlobToNapiValue(env, blob);
186 napi_status status = napi_set_named_property(env, *instance, name, napiData);
187 if (status != napi_ok) {
188 LOGE("Build blob[napi_value] failed!");
189 return false;
190 }
191 return true;
192 }
193
BuildSm2CipherTextSpecToNapiValue(napi_env env,Sm2CipherTextSpec * spec,napi_value * instance)194 static bool BuildSm2CipherTextSpecToNapiValue(napi_env env, Sm2CipherTextSpec *spec, napi_value *instance)
195 {
196 if (!BuildSetNamedProperty(env, &(spec->xCoordinate), SM2_UTIL_PARAM_X_COORDINATE.c_str(), instance)) {
197 LOGE("Build xCoordinate failed!");
198 return false;
199 }
200 if (!BuildSetNamedProperty(env, &(spec->yCoordinate), SM2_UTIL_PARAM_Y_COORDINATE.c_str(), instance)) {
201 LOGE("Build yCoordinate failed!");
202 return false;
203 }
204 if (!BuildBlobNapiValue(env, &(spec->cipherTextData), SM2_UTIL_PARAM_CIPHER_TEXT_DATA.c_str(), instance)) {
205 LOGE("Build cipherTextData failed!");
206 return false;
207 }
208 if (!BuildBlobNapiValue(env, &(spec->hashData), SM2_UTIL_PARAM_HASH_DATA.c_str(), instance)) {
209 LOGE("Build hashData failed!");
210 return false;
211 }
212 return true;
213 }
214
ConvertSm2CipherTextSpecToNapiValue(napi_env env,Sm2CipherTextSpec * spec)215 static napi_value ConvertSm2CipherTextSpecToNapiValue(napi_env env, Sm2CipherTextSpec *spec)
216 {
217 if (!CheckSm2CipherTextSpec(spec)) {
218 LOGE("Invalid spec!");
219 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "Invalid spec!"));
220 return NapiGetNull(env);
221 }
222 napi_value instance;
223 napi_status status = napi_create_object(env, &instance);
224 if (status != napi_ok) {
225 LOGE("Create object failed!");
226 napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "create object failed!"));
227 return NapiGetNull(env);
228 }
229 if (!BuildSm2CipherTextSpecToNapiValue(env, spec, &instance)) {
230 LOGE("Build object failed!");
231 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "build object failed!"));
232 return NapiGetNull(env);
233 }
234 return instance;
235 }
236
JsGetCipherTextSpec(napi_env env,napi_callback_info info)237 napi_value NapiSm2CryptoUtil::JsGetCipherTextSpec(napi_env env, napi_callback_info info)
238 {
239 size_t expectedArgc = PARAMS_NUM_TWO;
240 size_t argc = ARGS_SIZE_TWO;
241 napi_value argv[ARGS_SIZE_TWO] = { nullptr };
242 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
243 // second attribute mode can be null
244 if ((argc != expectedArgc) && (argc != (expectedArgc - 1))) {
245 LOGE("The input args num is invalid.");
246 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "The input args num is invalid."));
247 return nullptr;
248 }
249 HcfBlob *cipherText = GetBlobFromNapiDataBlob(env, argv[0]);
250 if (cipherText == nullptr) {
251 LOGE("Failed to get cipherText.");
252 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to get cipherText."));
253 return nullptr;
254 }
255 std::string dataMode;
256 if (argc == expectedArgc) {
257 if (!DealMode(env, argv[1], dataMode)) {
258 LOGE("Failed to get mode.");
259 HcfBlobDataFree(cipherText);
260 HcfFree(cipherText);
261 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to get mode."));
262 return nullptr;
263 }
264 }
265 Sm2CipherTextSpec *returnSpec = nullptr;
266 HcfResult res = HcfGetCipherTextSpec(cipherText, dataMode.c_str(), &returnSpec);
267 if (res != HCF_SUCCESS) {
268 LOGE("Get cipher text spec fail.");
269 HcfBlobDataFree(cipherText);
270 HcfFree(cipherText);
271 napi_throw(env, GenerateBusinessError(env, res, "get cipher text spec fail."));
272 return nullptr;
273 }
274 napi_value instance = ConvertSm2CipherTextSpecToNapiValue(env, returnSpec);
275 DestroySm2CipherTextSpec(returnSpec);
276 HcfBlobDataFree(cipherText);
277 HcfFree(cipherText);
278 return instance;
279 }
280
Sm2CryptoUtilConstructor(napi_env env,napi_callback_info info)281 napi_value NapiSm2CryptoUtil::Sm2CryptoUtilConstructor(napi_env env, napi_callback_info info)
282 {
283 napi_value thisVar = nullptr;
284 size_t argc = ARGS_SIZE_ONE;
285 napi_value argv[ARGS_SIZE_ONE] = { nullptr };
286 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
287 return thisVar;
288 }
289
Sm2CryptoUtilConstructorClass(napi_env env)290 napi_value NapiSm2CryptoUtil::Sm2CryptoUtilConstructorClass(napi_env env)
291 {
292 napi_value cons = nullptr;
293 napi_property_descriptor clzDes[] = {
294 DECLARE_NAPI_STATIC_FUNCTION("genCipherTextBySpec", NapiSm2CryptoUtil::JsGenCipherTextBySpec),
295 DECLARE_NAPI_STATIC_FUNCTION("getCipherTextSpec", NapiSm2CryptoUtil::JsGetCipherTextSpec),
296 };
297 NAPI_CALL(env, napi_define_class(env, "SM2CryptoUtil", NAPI_AUTO_LENGTH,
298 NapiSm2CryptoUtil::Sm2CryptoUtilConstructor,
299 nullptr, sizeof(clzDes) / sizeof(clzDes[0]), clzDes, &cons));
300 return cons;
301 }
302
DefineNapiSm2CryptoUtilJSClass(napi_env env,napi_value exports)303 void NapiSm2CryptoUtil::DefineNapiSm2CryptoUtilJSClass(napi_env env, napi_value exports)
304 {
305 napi_set_named_property(env, exports, "SM2CryptoUtil", NapiSm2CryptoUtil::Sm2CryptoUtilConstructorClass(env));
306 }
307 } // CryptoFramework
308 } // OHOS
309