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