1 /*
2 * Copyright (C) 2022 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_rand.h"
17
18 #include "securec.h"
19 #include "log.h"
20 #include "memory.h"
21
22 #include "napi_utils.h"
23 #include "napi_crypto_framework_defines.h"
24
25 namespace OHOS {
26 namespace CryptoFramework {
27 thread_local napi_ref NapiRand::classRef_ = nullptr;
28
29 struct RandCtx {
30 napi_env env = nullptr;
31
32 CfAsyncType asyncType = ASYNC_TYPE_CALLBACK;
33 napi_ref callback = nullptr;
34 napi_deferred deferred = nullptr;
35 napi_value promise = nullptr;
36 napi_async_work asyncWork = nullptr;
37
38 NapiRand *randClass = nullptr;
39 uint32_t numBytes = 0;
40 HcfBlob *seedBlob = nullptr;
41
42 HcfResult errCode = HCF_SUCCESS;
43 const char *errMsg = nullptr;
44 HcfBlob *randBlob = nullptr;
45 };
46
FreeCryptoFwkCtx(napi_env env,RandCtx * context)47 static void FreeCryptoFwkCtx(napi_env env, RandCtx *context)
48 {
49 if (context == nullptr) {
50 return;
51 }
52 if (context->asyncWork != nullptr) {
53 napi_delete_async_work(env, context->asyncWork);
54 context->asyncWork = nullptr;
55 }
56
57 if (context->callback != nullptr) {
58 napi_delete_reference(env, context->callback);
59 context->callback = nullptr;
60 }
61 if (context->seedBlob != nullptr) {
62 HcfFree(context->seedBlob->data);
63 context->seedBlob->data = nullptr;
64 context->seedBlob->len = 0;
65 }
66 if (context->randBlob != nullptr) {
67 HcfFree(context->randBlob->data);
68 context->randBlob->data = nullptr;
69 context->randBlob->len = 0;
70 }
71 HcfFree(context);
72 }
73
ReturnCallbackResult(napi_env env,RandCtx * context,napi_value result)74 static void ReturnCallbackResult(napi_env env, RandCtx *context, napi_value result)
75 {
76 napi_value businessError = nullptr;
77 if (context->errCode != HCF_SUCCESS) {
78 businessError = GenerateBusinessError(env, context->errCode, context->errMsg, false);
79 }
80 napi_value params[ARGS_SIZE_TWO] = { businessError, result };
81
82 napi_value func = nullptr;
83 napi_get_reference_value(env, context->callback, &func);
84
85 napi_value recv = nullptr;
86 napi_value callFuncRet = nullptr;
87 napi_get_undefined(env, &recv);
88 napi_call_function(env, recv, func, ARGS_SIZE_TWO, params, &callFuncRet);
89 }
90
ReturnPromiseResult(napi_env env,RandCtx * context,napi_value result)91 static void ReturnPromiseResult(napi_env env, RandCtx *context, napi_value result)
92 {
93 if (context->errCode == HCF_SUCCESS) {
94 napi_resolve_deferred(env, context->deferred, result);
95 } else {
96 napi_reject_deferred(env, context->deferred,
97 GenerateBusinessError(env, context->errCode, context->errMsg, false));
98 }
99 }
100
CreateCallbackAndPromise(napi_env env,RandCtx * context,size_t argc,size_t maxCount,napi_value callbackValue)101 static bool CreateCallbackAndPromise(napi_env env, RandCtx *context, size_t argc,
102 size_t maxCount, napi_value callbackValue)
103 {
104 context->asyncType = (argc == maxCount) ? ASYNC_TYPE_CALLBACK : ASYNC_TYPE_PROMISE;
105 if (context->asyncType == ASYNC_TYPE_CALLBACK) {
106 if (!GetCallbackFromJSParams(env, callbackValue, &context->callback, false)) {
107 LOGE("get callback failed!");
108 return false;
109 }
110 } else {
111 napi_create_promise(env, &context->deferred, &context->promise);
112 }
113 return true;
114 }
115
NapiRand(HcfRand * randObj)116 NapiRand::NapiRand(HcfRand *randObj)
117 {
118 this->randObj_ = randObj;
119 }
120
~NapiRand()121 NapiRand::~NapiRand()
122 {
123 HcfObjDestroy(this->randObj_);
124 }
125
GenerateRandomExecute(napi_env env,void * data)126 static void GenerateRandomExecute(napi_env env, void *data)
127 {
128 RandCtx *context = static_cast<RandCtx *>(data);
129 NapiRand *randClass = context->randClass;
130 HcfRand *randObj = randClass->GetRand();
131 HcfBlob *randBlob = reinterpret_cast<HcfBlob *>(HcfMalloc(sizeof(HcfBlob), 0));
132 if (randBlob == nullptr) {
133 LOGE("randBlob is null!");
134 context->errCode = HCF_ERR_MALLOC;
135 context->errMsg = "malloc data blob failed";
136 return;
137 }
138 uint32_t numBytes = context->numBytes;
139 context->errCode = randObj->generateRandom(randObj, numBytes, randBlob);
140 if (context->errCode != HCF_SUCCESS) {
141 LOGE("generateRandom failed!");
142 context->errMsg = "generateRandom failed";
143 return;
144 }
145 context->randBlob = randBlob;
146 }
147
GenerateRandomComplete(napi_env env,napi_status status,void * data)148 static void GenerateRandomComplete(napi_env env, napi_status status, void *data)
149 {
150 RandCtx *context = static_cast<RandCtx *>(data);
151 napi_value returnRandBlob = ConvertBlobToNapiValue(env, context->randBlob);
152 if (returnRandBlob == nullptr) {
153 LOGE("returnOutBlob is nullptr!");
154 returnRandBlob = NapiGetNull(env);
155 }
156 if (context->asyncType == ASYNC_TYPE_CALLBACK) {
157 ReturnCallbackResult(env, context, returnRandBlob);
158 } else {
159 ReturnPromiseResult(env, context, returnRandBlob);
160 }
161 FreeCryptoFwkCtx(env, context);
162 }
163
GenerateRandom(napi_env env,napi_callback_info info)164 napi_value NapiRand::GenerateRandom(napi_env env, napi_callback_info info)
165 {
166 size_t expectedArgsCount = ARGS_SIZE_TWO;
167 size_t argc = expectedArgsCount;
168 napi_value argv[ARGS_SIZE_TWO] = { nullptr };
169 napi_value thisVar = nullptr;
170 napi_value ret = NapiGetNull(env);
171 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
172 if ((argc != expectedArgsCount) && (argc != expectedArgsCount - CALLBACK_SIZE)) {
173 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "invalid params count", false));
174 LOGE("The arguments count is not expected!");
175 return ret;
176 }
177 RandCtx *context = static_cast<RandCtx *>(HcfMalloc(sizeof(RandCtx), 0));
178 if (context == nullptr) {
179 napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "malloc context failed", false));
180 LOGE("malloc context failed!");
181 return ret;
182 }
183 context->randClass = this;
184 if (!GetUint32FromJSParams(env, argv[PARAM0], context->numBytes, false)) {
185 LOGE("get numBytes failed!");
186 FreeCryptoFwkCtx(env, context);
187 return ret;
188 }
189 if (!CreateCallbackAndPromise(env, context, argc, ARGS_SIZE_TWO, argv[PARAM1])) {
190 FreeCryptoFwkCtx(env, context);
191 return nullptr;
192 }
193 napi_create_async_work(
194 env, nullptr, GetResourceName(env, "GenerateRandom"),
195 GenerateRandomExecute,
196 GenerateRandomComplete,
197 static_cast<void *>(context),
198 &context->asyncWork);
199 napi_queue_async_work(env, context->asyncWork);
200 if (context->asyncType == ASYNC_TYPE_PROMISE) {
201 return context->promise;
202 } else {
203 return NapiGetNull(env);
204 }
205 }
206
SetSeed(napi_env env,napi_callback_info info)207 napi_value NapiRand::SetSeed(napi_env env, napi_callback_info info)
208 {
209 size_t expectedArgsCount = ARGS_SIZE_ONE;
210 size_t argc = expectedArgsCount;
211 napi_value argv[ARGS_SIZE_ONE] = { nullptr };
212 napi_value thisVar = nullptr;
213 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
214 if (argc != expectedArgsCount) {
215 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "invalid params count", false));
216 LOGE("The arguments count is not expected!");
217 return nullptr;
218 }
219 HcfBlob *seedBlob = GetBlobFromNapiValue(env, argv[PARAM0]);
220 HcfRand *randObj = GetRand();
221 HcfResult res = randObj->setSeed(randObj, seedBlob);
222 if (res != HCF_SUCCESS) {
223 napi_throw(env, GenerateBusinessError(env, res, "set seed failed.", false));
224 LOGE("set seed failed.");
225 }
226 return nullptr;
227 }
228
NapiGenerateRandom(napi_env env,napi_callback_info info)229 static napi_value NapiGenerateRandom(napi_env env, napi_callback_info info)
230 {
231 LOGI("enter NapiCreateRand ...");
232 napi_value thisVar = nullptr;
233 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
234 NapiRand *randObj = nullptr;
235 napi_unwrap(env, thisVar, reinterpret_cast<void **>(&randObj));
236 if (randObj == nullptr) {
237 LOGE("randObj is nullptr!");
238 return NapiGetNull(env);
239 }
240 return randObj->GenerateRandom(env, info);
241 }
242
NapiSetSeed(napi_env env,napi_callback_info info)243 static napi_value NapiSetSeed(napi_env env, napi_callback_info info)
244 {
245 LOGI("enter NapiSetSeed ...");
246 napi_value thisVar = nullptr;
247 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
248 NapiRand *randObj = nullptr;
249 napi_unwrap(env, thisVar, reinterpret_cast<void **>(&randObj));
250 if (randObj == nullptr) {
251 LOGE("randObj is nullptr!");
252 return nullptr;
253 }
254 return randObj->SetSeed(env, info);
255 }
256
RandConstructor(napi_env env,napi_callback_info info)257 napi_value NapiRand::RandConstructor(napi_env env, napi_callback_info info)
258 {
259 napi_value thisVar = nullptr;
260 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
261 return thisVar;
262 }
263
CreateRand(napi_env env,napi_callback_info info)264 napi_value NapiRand::CreateRand(napi_env env, napi_callback_info info)
265 {
266 HcfRand *randObj = nullptr;
267 HcfResult res = HcfRandCreate(&randObj);
268 if (res != HCF_SUCCESS) {
269 napi_throw(env, GenerateBusinessError(env, res, "create C obj failed.", false));
270 LOGE("create c randObj failed.");
271 return nullptr;
272 }
273 napi_value instance = nullptr;
274 napi_value constructor = nullptr;
275 napi_get_reference_value(env, classRef_, &constructor);
276 napi_new_instance(env, constructor, 0, nullptr, &instance);
277 NapiRand *randNapiObj = new (std::nothrow) NapiRand(randObj);
278 if (randNapiObj == nullptr) {
279 LOGE("create napi obj failed");
280 return nullptr;
281 }
282 napi_wrap(
283 env, instance, randNapiObj,
284 [](napi_env env, void *data, void *hint) {
285 NapiRand *rand = static_cast<NapiRand *>(data);
286 delete rand;
287 return;
288 },
289 nullptr,
290 nullptr);
291 return instance;
292 }
293
DefineRandJSClass(napi_env env,napi_value exports)294 void NapiRand::DefineRandJSClass(napi_env env, napi_value exports)
295 {
296 napi_property_descriptor desc[] = {
297 DECLARE_NAPI_FUNCTION("createRandom", CreateRand),
298 };
299 napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
300 napi_property_descriptor classDesc[] = {
301 DECLARE_NAPI_FUNCTION("generateRandom", NapiGenerateRandom),
302 DECLARE_NAPI_FUNCTION("setSeed", NapiSetSeed),
303 };
304 napi_value constructor = nullptr;
305 napi_define_class(env, "Random", NAPI_AUTO_LENGTH, RandConstructor, nullptr,
306 sizeof(classDesc) / sizeof(classDesc[0]), classDesc, &constructor);
307 napi_create_reference(env, constructor, 1, &classRef_);
308 }
309 } // CryptoFramework
310 } // OHOS
311