• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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