• 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_cipher.h"
17 #include "napi_key.h"
18 #include "securec.h"
19 #include "log.h"
20 #include "memory.h"
21 
22 #include "cipher.h"
23 #include "napi_utils.h"
24 #include "napi_crypto_framework_defines.h"
25 #include "detailed_iv_params.h"
26 #include "detailed_gcm_params.h"
27 #include "detailed_ccm_params.h"
28 
29 namespace OHOS {
30 namespace CryptoFramework {
31 thread_local napi_ref NapiCipher::classRef_ = nullptr;
32 
33 struct CipherFwkCtxT {
34     napi_env env = nullptr;
35     AsyncType asyncType = ASYNC_CALLBACK;
36     napi_ref callback = nullptr;
37     napi_deferred deferred = nullptr;
38     napi_value promise = nullptr;
39     napi_async_work asyncWork = nullptr;
40 
41     HcfCipher *cipher = nullptr;
42     HcfKey *key = nullptr;
43     HcfParamsSpec *paramsSpec = nullptr;
44     HcfBlob input = { .data = nullptr, .len = 0 };
45     HcfBlob output = { .data = nullptr, .len = 0 };
46     enum HcfCryptoMode opMode = ENCRYPT_MODE;
47 
48     int32_t errCode = 0;
49     const char *errMsg = nullptr;
50 };
51 
52 using CipherFwkCtx = CipherFwkCtxT *;
53 
FreeParamsSpec(HcfParamsSpec * paramsSpec)54 static void FreeParamsSpec(HcfParamsSpec *paramsSpec)
55 {
56     if (paramsSpec == nullptr) {
57         return;
58     }
59     if (IV_PARAMS_SPEC.compare(paramsSpec->getType()) == 0) {
60         HcfIvParamsSpec *iv = reinterpret_cast<HcfIvParamsSpec *>(paramsSpec);
61         HcfFree(iv->iv.data);
62         iv->iv.data = nullptr;
63         iv->iv.len = 0;
64     }
65     if (GCM_PARAMS_SPEC.compare(paramsSpec->getType()) == 0) {
66         HcfGcmParamsSpec *gcm = reinterpret_cast<HcfGcmParamsSpec *>(paramsSpec);
67         HcfFree(gcm->iv.data);
68         HcfFree(gcm->aad.data);
69         HcfFree(gcm->tag.data);
70         gcm->iv.len = 0;
71         gcm->aad.len = 0;
72         gcm->tag.len = 0;
73         gcm->iv.data = nullptr;
74         gcm->aad.data = nullptr;
75         gcm->tag.data = nullptr;
76     }
77     if (CCM_PARAMS_SPEC.compare(paramsSpec->getType()) == 0) {
78         HcfCcmParamsSpec *ccm = reinterpret_cast<HcfCcmParamsSpec *>(paramsSpec);
79         HcfFree(ccm->iv.data);
80         HcfFree(ccm->aad.data);
81         HcfFree(ccm->tag.data);
82         ccm->iv.len = 0;
83         ccm->aad.len = 0;
84         ccm->tag.len = 0;
85         ccm->iv.data = nullptr;
86         ccm->aad.data = nullptr;
87         ccm->tag.data = nullptr;
88     }
89     HcfFree(paramsSpec);
90 }
91 
FreeCipherFwkCtx(napi_env env,CipherFwkCtx & context)92 static void FreeCipherFwkCtx(napi_env env, CipherFwkCtx &context)
93 {
94     if (context == nullptr) {
95         return;
96     }
97 
98     if (context->asyncWork != nullptr) {
99         napi_delete_async_work(env, context->asyncWork);
100         context->asyncWork = nullptr;
101     }
102 
103     if (context->callback != nullptr) {
104         napi_delete_reference(env, context->callback);
105         context->callback = nullptr;
106     }
107     if (context->input.data != nullptr) {
108         HcfFree(context->input.data);
109         context->input.data = nullptr;
110         context->input.len = 0;
111     }
112     if (context->output.data != nullptr) {
113         HcfFree(context->output.data);
114         context->output.data = nullptr;
115         context->output.len = 0;
116     }
117     FreeParamsSpec(context->paramsSpec);
118     context->paramsSpec = nullptr;
119 
120     context->cipher = nullptr;
121     context->key = nullptr;
122     context->errMsg = nullptr;
123     HcfFree(context);
124     context = nullptr;
125 }
126 
BuildContextForInit(napi_env env,napi_callback_info info,CipherFwkCtx context)127 bool BuildContextForInit(napi_env env, napi_callback_info info, CipherFwkCtx context)
128 {
129     napi_value thisVar = nullptr;
130     NapiCipher *napiCipher = nullptr;
131     NapiKey *napiKey = nullptr;
132     size_t expectedArgc = ARGS_SIZE_FOUR;
133     size_t argc = ARGS_SIZE_FOUR;
134     napi_value argv[ARGS_SIZE_FOUR] = { nullptr };
135     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
136     if (argc != expectedArgc && argc != expectedArgc - 1) {
137         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "init failed for wrong argument num.", false));
138         LOGE("wrong argument num. require 3 or 4 arguments. [Argc]: %zu!", argc);
139         return false;
140     }
141     context->asyncType = (argc == expectedArgc) ? ASYNC_CALLBACK : ASYNC_PROMISE;
142 
143     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCipher));
144     if (status != napi_ok) {
145         LOGE("failed to unwrap napi napiCipher obj!");
146         return false;
147     }
148     context->cipher = napiCipher->GetCipher();
149 
150     // get opMode, type is uint32
151     size_t index = ARGS_SIZE_ZERO;
152     if (napi_get_value_uint32(env, argv[index++], reinterpret_cast<uint32_t *>(&(context->opMode))) != napi_ok) {
153         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "get opMode failed!", false));
154         LOGE("get opMode failed!");
155         return false;
156     }
157 
158     // get key, unwrap from JS
159     status = napi_unwrap(env, argv[index++], reinterpret_cast<void **>(&napiKey));
160     if (status != napi_ok) {
161         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to unwrap napi napiSymKey obj!", false));
162         LOGE("failed to unwrap napi napiSymKey obj!");
163         return false;
164     }
165     context->key = napiKey->GetHcfKey();
166 
167     // get paramsSpec, unwrap from JS
168     napi_valuetype valueType;
169     napi_typeof(env, argv[index], &valueType);
170     if (valueType != napi_null) {
171         if (!GetParamsSpecFromNapiValue(env, argv[index], context->opMode, &context->paramsSpec)) {
172             napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to get valid params spec!", false));
173             LOGE("GetParamsSpecFromNapiValue failed!");
174             return false;
175         }
176     }
177     index++;
178 
179     if (context->asyncType == ASYNC_PROMISE) {
180         napi_create_promise(env, &context->deferred, &context->promise);
181         return true;
182     } else {
183         return GetCallbackFromJSParams(env, argv[index], &context->callback, false);
184     }
185 }
186 
BuildContextForUpdate(napi_env env,napi_callback_info info,CipherFwkCtx context)187 bool BuildContextForUpdate(napi_env env, napi_callback_info info, CipherFwkCtx context)
188 {
189     napi_value thisVar = nullptr;
190     NapiCipher *napiCipher = nullptr;
191     size_t expectedArgc = ARGS_SIZE_TWO;
192     size_t argc = ARGS_SIZE_TWO;
193     napi_value argv[ARGS_SIZE_TWO] = { nullptr };
194     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
195     if (argc != expectedArgc && argc != expectedArgc - 1) {
196         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "update failed for wrong argument num.", false));
197         LOGE("wrong argument num. require 1 or 2 arguments. [Argc]: %zu!", argc);
198         return false;
199     }
200     context->asyncType = (argc == expectedArgc) ? ASYNC_CALLBACK : ASYNC_PROMISE;
201 
202     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCipher));
203     if (status != napi_ok) {
204         LOGE("failed to unwrap napi napiCipher obj!");
205         return false;
206     }
207     context->cipher = napiCipher->GetCipher();
208 
209     // get input, type is blob
210     size_t index = ARGS_SIZE_ZERO;
211     HcfBlob *input = nullptr;
212     input = GetBlobFromNapiValue(env, argv[index++]);
213     if (input == nullptr) {
214         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "update failed for invalid input blob.", false));
215         LOGE("GetBlobFromNapiValue failed!");
216         return false;
217     }
218     context->input.data = input->data;
219     context->input.len = input->len;
220     HcfFree(input);
221     if (context->asyncType == ASYNC_PROMISE) {
222         napi_create_promise(env, &context->deferred, &context->promise);
223         return true;
224     } else {
225         return GetCallbackFromJSParams(env, argv[index], &context->callback, false);
226     }
227 }
228 
BuildContextForFinal(napi_env env,napi_callback_info info,CipherFwkCtx context)229 bool BuildContextForFinal(napi_env env, napi_callback_info info, CipherFwkCtx context)
230 {
231     napi_value thisVar = nullptr;
232     NapiCipher *napiCipher = nullptr;
233     size_t expectedArgc = ARGS_SIZE_TWO;
234     size_t argc = ARGS_SIZE_TWO;
235     napi_value argv[ARGS_SIZE_TWO] = { nullptr };
236     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
237     if (argc != expectedArgc && argc != expectedArgc - 1) {
238         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS,
239             "doFinal failed for invalid input blob.", false));
240         LOGE("wrong argument num. require 1 or 2 arguments. [Argc]: %zu!", argc);
241         return false;
242     }
243     context->asyncType = (argc == expectedArgc) ? ASYNC_CALLBACK : ASYNC_PROMISE;
244 
245     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCipher));
246     if (status != napi_ok) {
247         LOGE("failed to unwrap napi napiCipher obj!");
248         return false;
249     }
250     context->cipher = napiCipher->GetCipher();
251 
252     // get input, type is blob
253     size_t index = ARGS_SIZE_ZERO;
254     napi_valuetype valueType;
255     napi_typeof(env, argv[index], &valueType);
256     if (valueType != napi_null) {
257         HcfBlob *input = nullptr;
258         input = GetBlobFromNapiValue(env, argv[index]);
259         if (input == nullptr) {
260             napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS,
261                 "doFinal failed for invalid input blob.", false));
262             LOGE("GetBlobFromNapiValue failed!");
263             return false;
264         }
265         context->input.data = input->data;
266         context->input.len = input->len;
267         HcfFree(input);
268     }
269     index++;
270     if (context->asyncType == ASYNC_PROMISE) {
271         napi_create_promise(env, &context->deferred, &context->promise);
272         return true;
273     } else {
274         return GetCallbackFromJSParams(env, argv[index], &context->callback, false);
275     }
276 }
277 
ReturnCallbackResult(napi_env env,CipherFwkCtx context,napi_value result)278 static void ReturnCallbackResult(napi_env env, CipherFwkCtx context, napi_value result)
279 {
280     napi_value businessError = nullptr;
281     if (context->errCode != HCF_SUCCESS) {
282         businessError = GenerateBusinessError(env, context->errCode, context->errMsg, false);
283     }
284     napi_value params[ARGS_SIZE_TWO] = { businessError, result };
285 
286     napi_value func = nullptr;
287     napi_get_reference_value(env, context->callback, &func);
288 
289     napi_value recv = nullptr;
290     napi_value callFuncRet = nullptr;
291     napi_get_undefined(env, &recv);
292     napi_call_function(env, recv, func, ARGS_SIZE_TWO, params, &callFuncRet);
293 }
294 
ReturnPromiseResult(napi_env env,CipherFwkCtx context,napi_value result)295 static void ReturnPromiseResult(napi_env env, CipherFwkCtx context, napi_value result)
296 {
297     if (context->errCode == HCF_SUCCESS) {
298         napi_resolve_deferred(env, context->deferred, result);
299     } else {
300         napi_reject_deferred(env, context->deferred,
301             GenerateBusinessError(env, context->errCode, context->errMsg, false));
302     }
303 }
304 
305 // init execute
AsyncInitProcess(napi_env env,void * data)306 void AsyncInitProcess(napi_env env, void *data)
307 {
308     if (data == nullptr) {
309         return;
310     }
311     CipherFwkCtx context = static_cast<CipherFwkCtx>(data);
312     HcfCipher *cipher = context->cipher;
313     HcfParamsSpec *params = context->paramsSpec;
314     HcfKey *key = context->key;
315 
316     HcfResult res = cipher->init(cipher, context->opMode, key, params);
317     if (res != HCF_SUCCESS) {
318         LOGE("init ret:%d", res);
319         context->errCode = res;
320         context->errMsg = "init failed.";
321         return;
322     }
323     context->errCode = HCF_SUCCESS;
324 }
325 
326 // update execute
AsyncUpdateProcess(napi_env env,void * data)327 void AsyncUpdateProcess(napi_env env, void *data)
328 {
329     if (data == nullptr) {
330         return;
331     }
332     CipherFwkCtx context = static_cast<CipherFwkCtx>(data);
333     HcfCipher *cipher = context->cipher;
334     HcfResult res = cipher->update(cipher, &context->input, &context->output);
335     if (res != HCF_SUCCESS) {
336         LOGE("Update ret:%d!", res);
337         context->errCode = res;
338         context->errMsg = "update failed.";
339         return;
340     }
341     context->errCode = HCF_SUCCESS;
342 }
343 
AsyncDoFinalProcess(napi_env env,void * data)344 void AsyncDoFinalProcess(napi_env env, void *data)
345 {
346     if (data == nullptr) {
347         return;
348     }
349     CipherFwkCtx context = static_cast<CipherFwkCtx>(data);
350     HcfCipher *cipher = context->cipher;
351 
352     HcfResult res = cipher->doFinal(cipher, &context->input, &context->output);
353     if (res != HCF_SUCCESS) {
354         LOGE("doFinal ret:%d!", res);
355         context->errCode = res;
356         context->errMsg = "doFinal failed.";
357         return;
358     }
359     context->errCode = HCF_SUCCESS;
360 }
361 
GetNapiNull(napi_env env)362 napi_value GetNapiNull(napi_env env)
363 {
364     napi_value output = nullptr;
365     napi_status status = napi_get_null(env, &output);
366     if (status != napi_ok) {
367         LOGE("create null napi value failed");
368     }
369     return output;
370 }
371 
AsyncInitReturn(napi_env env,napi_status status,void * data)372 void AsyncInitReturn(napi_env env, napi_status status, void *data)
373 {
374     CipherFwkCtx context = static_cast<CipherFwkCtx>(data);
375     napi_value result = GetNapiNull(env);
376 
377     if (context->asyncType == ASYNC_CALLBACK) {
378         ReturnCallbackResult(env, context, result);
379     } else {
380         ReturnPromiseResult(env, context, result);
381     }
382     FreeCipherFwkCtx(env, context);
383 }
384 
AsyncUpdateReturn(napi_env env,napi_status status,void * data)385 void AsyncUpdateReturn(napi_env env, napi_status status, void *data)
386 {
387     CipherFwkCtx context = static_cast<CipherFwkCtx>(data);
388     napi_value instance = ConvertBlobToNapiValue(env, &context->output);
389     if (instance == nullptr) {
390         LOGE("May be nullptr!");
391         instance = GetNapiNull(env);
392     }
393 
394     if (context->asyncType == ASYNC_CALLBACK) {
395         ReturnCallbackResult(env, context, instance);
396     } else {
397         ReturnPromiseResult(env, context, instance);
398     }
399     FreeCipherFwkCtx(env, context);
400 }
401 
AsyncDoFinalReturn(napi_env env,napi_status status,void * data)402 void AsyncDoFinalReturn(napi_env env, napi_status status, void *data)
403 {
404     CipherFwkCtx context = static_cast<CipherFwkCtx>(data);
405     napi_value instance = ConvertBlobToNapiValue(env, &context->output);
406     if (instance == nullptr) {
407         LOGE("Maybe in decrypt mode, or CCM crypto maybe occur!");
408         instance = GetNapiNull(env);
409     }
410 
411     if (context->asyncType == ASYNC_CALLBACK) {
412         ReturnCallbackResult(env, context, instance);
413     } else {
414         ReturnPromiseResult(env, context, instance);
415     }
416     FreeCipherFwkCtx(env, context);
417 }
418 
NewAsyncInit(napi_env env,CipherFwkCtx context)419 napi_value NewAsyncInit(napi_env env, CipherFwkCtx context)
420 {
421     napi_value resourceName = nullptr;
422     napi_create_string_utf8(env, "init", NAPI_AUTO_LENGTH, &resourceName);
423 
424     napi_create_async_work(
425         env, nullptr, resourceName,
426         [](napi_env env, void *data) {
427             AsyncInitProcess(env, data);
428             return;
429         },
430         [](napi_env env, napi_status status, void *data) {
431             AsyncInitReturn(env, status, data);
432             return;
433         },
434         static_cast<void *>(context),
435         &context->asyncWork);
436 
437     napi_queue_async_work(env, context->asyncWork);
438     if (context->asyncType == ASYNC_PROMISE) {
439         return context->promise;
440     } else {
441         return NapiGetNull(env);
442     }
443 }
444 
NewAsyncUpdate(napi_env env,CipherFwkCtx context)445 napi_value NewAsyncUpdate(napi_env env, CipherFwkCtx context)
446 {
447     napi_value resourceName = nullptr;
448     napi_create_string_utf8(env, "update", NAPI_AUTO_LENGTH, &resourceName);
449 
450     napi_create_async_work(
451         env, nullptr, resourceName,
452         [](napi_env env, void *data) {
453             AsyncUpdateProcess(env, data);
454             return;
455         },
456         [](napi_env env, napi_status status, void *data) {
457             AsyncUpdateReturn(env, status, data);
458             return;
459         },
460         static_cast<void *>(context),
461         &context->asyncWork);
462 
463     napi_queue_async_work(env, context->asyncWork);
464     if (context->asyncType == ASYNC_PROMISE) {
465         return context->promise;
466     } else {
467         return NapiGetNull(env);
468     }
469 }
470 
NewAsyncDoFinal(napi_env env,CipherFwkCtx context)471 napi_value NewAsyncDoFinal(napi_env env, CipherFwkCtx context)
472 {
473     napi_value resourceName = nullptr;
474     napi_create_string_utf8(env, "doFinal", NAPI_AUTO_LENGTH, &resourceName);
475 
476     napi_create_async_work(
477         env, nullptr, resourceName,
478         [](napi_env env, void *data) {
479             AsyncDoFinalProcess(env, data);
480             return;
481         },
482         [](napi_env env, napi_status status, void *data) {
483             AsyncDoFinalReturn(env, status, data);
484             return;
485         },
486         static_cast<void *>(context),
487         &context->asyncWork);
488 
489     napi_queue_async_work(env, context->asyncWork);
490     if (context->asyncType == ASYNC_PROMISE) {
491         return context->promise;
492     } else {
493         return NapiGetNull(env);
494     }
495 }
496 
NapiCipher(HcfCipher * cipher)497 NapiCipher::NapiCipher(HcfCipher *cipher)
498 {
499     this->cipher_ = cipher;
500 }
501 
~NapiCipher()502 NapiCipher::~NapiCipher()
503 {
504     HcfObjDestroy(this->cipher_);
505 }
506 
GetCipher() const507 HcfCipher *NapiCipher::GetCipher() const
508 {
509     return this->cipher_;
510 }
511 
JsCipherInit(napi_env env,napi_callback_info info)512 napi_value NapiCipher::JsCipherInit(napi_env env, napi_callback_info info)
513 {
514     CipherFwkCtx context = static_cast<CipherFwkCtx>(HcfMalloc(sizeof(CipherFwkCtxT), 0));
515     if (context == nullptr) {
516         LOGE("create context fail!");
517         return nullptr;
518     }
519 
520     if (!BuildContextForInit(env, info, context)) {
521         LOGE("build context for init fail!");
522         FreeCipherFwkCtx(env, context);
523         return nullptr;
524     }
525 
526     return NewAsyncInit(env, context);
527 }
528 
JsCipherUpdate(napi_env env,napi_callback_info info)529 napi_value NapiCipher::JsCipherUpdate(napi_env env, napi_callback_info info)
530 {
531     CipherFwkCtx context = static_cast<CipherFwkCtx>(HcfMalloc(sizeof(CipherFwkCtxT), 0));
532     if (context == nullptr) {
533         LOGE("create context fail!");
534         return nullptr;
535     }
536 
537     if (!BuildContextForUpdate(env, info, context)) {
538         LOGE("build context for update fail!");
539         FreeCipherFwkCtx(env, context);
540         return nullptr;
541     }
542 
543     return NewAsyncUpdate(env, context);
544 }
545 
JsCipherDoFinal(napi_env env,napi_callback_info info)546 napi_value NapiCipher::JsCipherDoFinal(napi_env env, napi_callback_info info)
547 {
548     CipherFwkCtx context = static_cast<CipherFwkCtx>(HcfMalloc(sizeof(CipherFwkCtxT), 0));
549     if (context == nullptr) {
550         LOGE("create context fail!");
551         return nullptr;
552     }
553 
554     if (!BuildContextForFinal(env, info, context)) {
555         LOGE("build context for final fail!");
556         FreeCipherFwkCtx(env, context);
557         return nullptr;
558     }
559     return NewAsyncDoFinal(env, context);
560 }
561 
JsGetAlgorithm(napi_env env,napi_callback_info info)562 napi_value NapiCipher::JsGetAlgorithm(napi_env env, napi_callback_info info)
563 {
564     napi_value thisVar = nullptr;
565     NapiCipher *napiCipher = nullptr;
566 
567     NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr));
568 
569     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCipher));
570     if (status != napi_ok) {
571         LOGE("failed to unwrap napiCipher obj!");
572         return nullptr;
573     }
574 
575     HcfCipher *cipher = napiCipher->GetCipher();
576     if (cipher == nullptr) {
577         LOGE("failed to get cipher obj!");
578         return nullptr;
579     }
580 
581     // execute C function
582     const char *algo = cipher->getAlgorithm(cipher);
583     napi_value instance = nullptr;
584     napi_create_string_utf8(env, algo, NAPI_AUTO_LENGTH, &instance);
585     return instance;
586 }
587 
CipherConstructor(napi_env env,napi_callback_info info)588 napi_value NapiCipher::CipherConstructor(napi_env env, napi_callback_info info)
589 {
590     napi_value thisVar = nullptr;
591     NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr));
592 
593     return thisVar;
594 }
595 
CreateCipher(napi_env env,napi_callback_info info)596 napi_value NapiCipher::CreateCipher(napi_env env, napi_callback_info info)
597 {
598     size_t expectedArgc = ARGS_SIZE_ONE;
599     size_t argc = ARGS_SIZE_ONE;
600     napi_value argv[ARGS_SIZE_ONE] = { nullptr };
601     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
602 
603     if (argc != expectedArgc) {
604         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "The input args num is invalid.", false));
605         LOGE("The input args num is invalid.");
606         return nullptr;
607     }
608 
609     // create instance according to input js object
610     napi_value instance = nullptr;
611     napi_value constructor = nullptr;
612     NAPI_CALL(env, napi_get_reference_value(env, classRef_, &constructor));
613     NAPI_CALL(env, napi_new_instance(env, constructor, argc, argv, &instance));
614 
615     // parse input string
616     std::string algoName;
617     if (!GetStringFromJSParams(env, argv[ARGS_SIZE_ZERO], algoName, false)) {
618         LOGE("GetStringFromJSParams failed!");
619         return nullptr;
620     }
621 
622     // execute C function, generate C object
623     HcfCipher *cipher = nullptr;
624     HcfResult res = HcfCipherCreate(algoName.c_str(), &cipher);
625     if (res != HCF_SUCCESS) {
626         napi_throw(env, GenerateBusinessError(env, res, "create C cipher fail!", false));
627         LOGE("create C cipher fail!");
628         return nullptr;
629     }
630     NapiCipher *napiCipher = new (std::nothrow) NapiCipher(cipher);
631     if (napiCipher == nullptr) {
632         LOGE("new napiCipher failed!");
633         HcfObjDestroy(cipher);
634         return nullptr;
635     }
636 
637     napi_status status = napi_wrap(env, instance, napiCipher,
638         [](napi_env env, void *data, void *hint) {
639             NapiCipher *napiCipher = static_cast<NapiCipher *>(data);
640             delete napiCipher;
641             return;
642         },
643         nullptr,
644         nullptr);
645     if (status != napi_ok) {
646         LOGE("failed to wrap napiCipher obj!");
647         delete napiCipher;
648         return nullptr;
649     }
650     return instance;
651 }
652 
DefineCipherJSClass(napi_env env,napi_value exports)653 void NapiCipher::DefineCipherJSClass(napi_env env, napi_value exports)
654 {
655     napi_property_descriptor desc[] = {
656         DECLARE_NAPI_FUNCTION("createCipher", CreateCipher),
657     };
658     napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
659 
660     napi_property_descriptor classDesc[] = {
661         DECLARE_NAPI_FUNCTION("init", NapiCipher::JsCipherInit),
662         DECLARE_NAPI_FUNCTION("update", NapiCipher::JsCipherUpdate),
663         DECLARE_NAPI_FUNCTION("doFinal", NapiCipher::JsCipherDoFinal),
664         { .utf8name = "algName", .getter = NapiCipher::JsGetAlgorithm },
665     };
666     napi_value constructor = nullptr;
667     napi_define_class(env, "Cipher", NAPI_AUTO_LENGTH, NapiCipher::CipherConstructor, nullptr,
668         sizeof(classDesc) / sizeof(classDesc[0]), classDesc, &constructor);
669     napi_create_reference(env, constructor, 1, &classRef_);
670 }
671 } // CryptoFramework
672 } // OHOS