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