• 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_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     HcfResult errCode = HCF_SUCCESS;
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         LOGE("wrong argument num. require 3 or 4 arguments. [Argc]: %zu!", argc);
138         return false;
139     }
140     context->asyncType = isCallback(env, argv[expectedArgc - 1], argc, expectedArgc) ? ASYNC_CALLBACK : ASYNC_PROMISE;
141 
142     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCipher));
143     if (status != napi_ok || napiCipher == nullptr) {
144         LOGE("failed to unwrap napi napiCipher obj!");
145         return false;
146     }
147     context->cipher = napiCipher->GetCipher();
148 
149     // get opMode, type is uint32
150     size_t index = 0;
151     if (napi_get_value_uint32(env, argv[index++], reinterpret_cast<uint32_t *>(&(context->opMode))) != napi_ok) {
152         LOGE("get opMode failed!");
153         return false;
154     }
155 
156     // get key, unwrap from JS
157     status = napi_unwrap(env, argv[index++], reinterpret_cast<void **>(&napiKey));
158     if (status != napi_ok || napiKey == nullptr) {
159         LOGE("failed to unwrap napi napiSymKey obj!");
160         return false;
161     }
162     context->key = napiKey->GetHcfKey();
163 
164     // get paramsSpec, unwrap from JS
165     napi_valuetype valueType;
166     napi_typeof(env, argv[index], &valueType);
167     if (valueType != napi_null) {
168         if (!GetParamsSpecFromNapiValue(env, argv[index], context->opMode, &context->paramsSpec)) {
169             LOGE("GetParamsSpecFromNapiValue failed!");
170             return false;
171         }
172     }
173     index++;
174 
175     if (context->asyncType == ASYNC_PROMISE) {
176         napi_create_promise(env, &context->deferred, &context->promise);
177         return true;
178     } else {
179         return GetCallbackFromJSParams(env, argv[index], &context->callback);
180     }
181 }
182 
BuildContextForUpdate(napi_env env,napi_callback_info info,CipherFwkCtx context)183 bool BuildContextForUpdate(napi_env env, napi_callback_info info, CipherFwkCtx context)
184 {
185     napi_value thisVar = nullptr;
186     NapiCipher *napiCipher = nullptr;
187     size_t expectedArgc = ARGS_SIZE_TWO;
188     size_t argc = ARGS_SIZE_TWO;
189     napi_value argv[ARGS_SIZE_TWO] = { nullptr };
190     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
191     // argc : in & out, receives the actual count of arguments
192     if (argc != expectedArgc && argc != expectedArgc - 1) {
193         LOGE("wrong argument num. require 1 or 2 arguments. [Argc]: %zu!", argc);
194         return false;
195     }
196     context->asyncType = isCallback(env, argv[expectedArgc - 1], argc, expectedArgc) ? ASYNC_CALLBACK : ASYNC_PROMISE;
197 
198     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCipher));
199     if (status != napi_ok || napiCipher == nullptr) {
200         LOGE("failed to unwrap napi napiCipher obj!");
201         return false;
202     }
203     context->cipher = napiCipher->GetCipher();
204 
205     // get input, type is blob
206     size_t index = 0;
207     HcfBlob *input = nullptr;
208     input = GetBlobFromNapiValue(env, argv[index++]);
209     if (input == nullptr) {
210         LOGE("GetBlobFromNapiValue failed!");
211         return false;
212     }
213     context->input.data = input->data;
214     context->input.len = input->len;
215     HcfFree(input);
216     if (context->asyncType == ASYNC_PROMISE) {
217         napi_create_promise(env, &context->deferred, &context->promise);
218         return true;
219     } else {
220         return GetCallbackFromJSParams(env, argv[index], &context->callback);
221     }
222 }
223 
BuildContextForFinal(napi_env env,napi_callback_info info,CipherFwkCtx context)224 bool BuildContextForFinal(napi_env env, napi_callback_info info, CipherFwkCtx context)
225 {
226     napi_value thisVar = nullptr;
227     NapiCipher *napiCipher = nullptr;
228     size_t expectedArgc = ARGS_SIZE_TWO;
229     size_t argc = ARGS_SIZE_TWO;
230     napi_value argv[ARGS_SIZE_TWO] = { nullptr };
231     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
232     if (argc != expectedArgc && argc != expectedArgc - 1) {
233         LOGE("wrong argument num. require 1 or 2 arguments. [Argc]: %zu!", argc);
234         return false;
235     }
236     context->asyncType = isCallback(env, argv[expectedArgc - 1], argc, expectedArgc) ? ASYNC_CALLBACK : ASYNC_PROMISE;
237 
238     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCipher));
239     if (status != napi_ok || napiCipher == nullptr) {
240         LOGE("failed to unwrap napi napiCipher obj!");
241         return false;
242     }
243     context->cipher = napiCipher->GetCipher();
244 
245     // get input, type is blob
246     size_t index = 0;
247     napi_valuetype valueType;
248     napi_typeof(env, argv[index], &valueType);
249     if (valueType != napi_null) {
250         HcfBlob *input = nullptr;
251         input = GetBlobFromNapiValue(env, argv[index]);
252         if (input == nullptr) {
253             LOGE("GetBlobFromNapiValue failed!");
254             return false;
255         }
256         context->input.data = input->data;
257         context->input.len = input->len;
258         HcfFree(input);
259     }
260     index++;
261     if (context->asyncType == ASYNC_PROMISE) {
262         napi_create_promise(env, &context->deferred, &context->promise);
263         return true;
264     } else {
265         return GetCallbackFromJSParams(env, argv[index], &context->callback);
266     }
267 }
268 
ReturnCallbackResult(napi_env env,CipherFwkCtx context,napi_value result)269 static void ReturnCallbackResult(napi_env env, CipherFwkCtx context, napi_value result)
270 {
271     napi_value businessError = nullptr;
272     if (context->errCode != HCF_SUCCESS) {
273         businessError = GenerateBusinessError(env, context->errCode, context->errMsg);
274     }
275     napi_value params[ARGS_SIZE_TWO] = { businessError, result };
276 
277     napi_value func = nullptr;
278     napi_get_reference_value(env, context->callback, &func);
279 
280     napi_value recv = nullptr;
281     napi_value callFuncRet = nullptr;
282     napi_get_undefined(env, &recv);
283     napi_call_function(env, recv, func, ARGS_SIZE_TWO, params, &callFuncRet);
284 }
285 
ReturnPromiseResult(napi_env env,CipherFwkCtx context,napi_value result)286 static void ReturnPromiseResult(napi_env env, CipherFwkCtx context, napi_value result)
287 {
288     if (context->errCode == HCF_SUCCESS) {
289         napi_resolve_deferred(env, context->deferred, result);
290     } else {
291         napi_reject_deferred(env, context->deferred,
292             GenerateBusinessError(env, context->errCode, context->errMsg));
293     }
294 }
295 
296 // init execute
AsyncInitProcess(napi_env env,void * data)297 void AsyncInitProcess(napi_env env, void *data)
298 {
299     CipherFwkCtx context = static_cast<CipherFwkCtx>(data);
300     HcfCipher *cipher = context->cipher;
301     HcfParamsSpec *params = context->paramsSpec;
302     HcfKey *key = context->key;
303 
304     context->errCode = cipher->init(cipher, context->opMode, key, params);
305     if (context->errCode != HCF_SUCCESS) {
306         LOGE("init ret:%d", context->errCode);
307         context->errMsg = "init failed.";
308     }
309 }
310 
311 // update execute
AsyncUpdateProcess(napi_env env,void * data)312 void AsyncUpdateProcess(napi_env env, void *data)
313 {
314     CipherFwkCtx context = static_cast<CipherFwkCtx>(data);
315     HcfCipher *cipher = context->cipher;
316     context->errCode = cipher->update(cipher, &context->input, &context->output);
317     if (context->errCode != HCF_SUCCESS) {
318         LOGE("Update ret:%d!", context->errCode);
319         context->errMsg = "update failed.";
320     }
321 }
322 
AsyncDoFinalProcess(napi_env env,void * data)323 void AsyncDoFinalProcess(napi_env env, void *data)
324 {
325     CipherFwkCtx context = static_cast<CipherFwkCtx>(data);
326     HcfCipher *cipher = context->cipher;
327 
328     context->errCode = cipher->doFinal(cipher, &context->input, &context->output);
329     if (context->errCode != HCF_SUCCESS) {
330         LOGE("doFinal ret:%d!", context->errCode);
331         context->errMsg = "doFinal failed.";
332     }
333 }
334 
AsyncInitReturn(napi_env env,napi_status status,void * data)335 void AsyncInitReturn(napi_env env, napi_status status, void *data)
336 {
337     CipherFwkCtx context = static_cast<CipherFwkCtx>(data);
338     napi_value result = NapiGetNull(env);
339 
340     if (context->asyncType == ASYNC_CALLBACK) {
341         ReturnCallbackResult(env, context, result);
342     } else {
343         ReturnPromiseResult(env, context, result);
344     }
345     FreeCipherFwkCtx(env, context);
346 }
347 
AsyncUpdateReturn(napi_env env,napi_status status,void * data)348 void AsyncUpdateReturn(napi_env env, napi_status status, void *data)
349 {
350     CipherFwkCtx context = static_cast<CipherFwkCtx>(data);
351     napi_value instance = ConvertBlobToNapiValue(env, &context->output);
352     if (instance == nullptr) {
353         LOGE("May be nullptr!");
354         instance = NapiGetNull(env);
355     }
356 
357     if (context->asyncType == ASYNC_CALLBACK) {
358         ReturnCallbackResult(env, context, instance);
359     } else {
360         ReturnPromiseResult(env, context, instance);
361     }
362     FreeCipherFwkCtx(env, context);
363 }
364 
AsyncDoFinalReturn(napi_env env,napi_status status,void * data)365 void AsyncDoFinalReturn(napi_env env, napi_status status, void *data)
366 {
367     CipherFwkCtx context = static_cast<CipherFwkCtx>(data);
368     napi_value instance = ConvertBlobToNapiValue(env, &context->output);
369     if (instance == nullptr) {
370         LOGE("Maybe in decrypt mode, or CCM crypto maybe occur!");
371         instance = NapiGetNull(env);
372     }
373 
374     if (context->asyncType == ASYNC_CALLBACK) {
375         ReturnCallbackResult(env, context, instance);
376     } else {
377         ReturnPromiseResult(env, context, instance);
378     }
379     FreeCipherFwkCtx(env, context);
380 }
381 
NewAsyncInit(napi_env env,CipherFwkCtx context)382 napi_value NewAsyncInit(napi_env env, CipherFwkCtx context)
383 {
384     napi_value resourceName = nullptr;
385     napi_create_string_utf8(env, "init", NAPI_AUTO_LENGTH, &resourceName);
386 
387     napi_create_async_work(
388         env, nullptr, resourceName,
389         [](napi_env env, void *data) {
390             AsyncInitProcess(env, data);
391             return;
392         },
393         [](napi_env env, napi_status status, void *data) {
394             AsyncInitReturn(env, status, data);
395             return;
396         },
397         static_cast<void *>(context),
398         &context->asyncWork);
399 
400     napi_queue_async_work(env, context->asyncWork);
401     if (context->asyncType == ASYNC_PROMISE) {
402         return context->promise;
403     } else {
404         return NapiGetNull(env);
405     }
406 }
407 
NewAsyncUpdate(napi_env env,CipherFwkCtx context)408 napi_value NewAsyncUpdate(napi_env env, CipherFwkCtx context)
409 {
410     napi_value resourceName = nullptr;
411     napi_create_string_utf8(env, "update", NAPI_AUTO_LENGTH, &resourceName);
412 
413     napi_create_async_work(
414         env, nullptr, resourceName,
415         [](napi_env env, void *data) {
416             AsyncUpdateProcess(env, data);
417             return;
418         },
419         [](napi_env env, napi_status status, void *data) {
420             AsyncUpdateReturn(env, status, data);
421             return;
422         },
423         static_cast<void *>(context),
424         &context->asyncWork);
425 
426     napi_queue_async_work(env, context->asyncWork);
427     if (context->asyncType == ASYNC_PROMISE) {
428         return context->promise;
429     } else {
430         return NapiGetNull(env);
431     }
432 }
433 
NewAsyncDoFinal(napi_env env,CipherFwkCtx context)434 napi_value NewAsyncDoFinal(napi_env env, CipherFwkCtx context)
435 {
436     napi_value resourceName = nullptr;
437     napi_create_string_utf8(env, "doFinal", NAPI_AUTO_LENGTH, &resourceName);
438 
439     napi_create_async_work(
440         env, nullptr, resourceName,
441         [](napi_env env, void *data) {
442             AsyncDoFinalProcess(env, data);
443             return;
444         },
445         [](napi_env env, napi_status status, void *data) {
446             AsyncDoFinalReturn(env, status, data);
447             return;
448         },
449         static_cast<void *>(context),
450         &context->asyncWork);
451 
452     napi_queue_async_work(env, context->asyncWork);
453     if (context->asyncType == ASYNC_PROMISE) {
454         return context->promise;
455     } else {
456         return NapiGetNull(env);
457     }
458 }
459 
NapiCipher(HcfCipher * cipher)460 NapiCipher::NapiCipher(HcfCipher *cipher)
461 {
462     this->cipher_ = cipher;
463 }
464 
~NapiCipher()465 NapiCipher::~NapiCipher()
466 {
467     HcfObjDestroy(this->cipher_);
468 }
469 
GetCipher() const470 HcfCipher *NapiCipher::GetCipher() const
471 {
472     return this->cipher_;
473 }
474 
JsCipherInit(napi_env env,napi_callback_info info)475 napi_value NapiCipher::JsCipherInit(napi_env env, napi_callback_info info)
476 {
477     CipherFwkCtx context = static_cast<CipherFwkCtx>(HcfMalloc(sizeof(CipherFwkCtxT), 0));
478     if (context == nullptr) {
479         napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "create context fail!"));
480         LOGE("create context fail!");
481         return nullptr;
482     }
483 
484     if (!BuildContextForInit(env, info, context)) {
485         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "build context for init fail!"));
486         LOGE("build context for init fail!");
487         FreeCipherFwkCtx(env, context);
488         return nullptr;
489     }
490 
491     return NewAsyncInit(env, context);
492 }
493 
JsCipherUpdate(napi_env env,napi_callback_info info)494 napi_value NapiCipher::JsCipherUpdate(napi_env env, napi_callback_info info)
495 {
496     CipherFwkCtx context = static_cast<CipherFwkCtx>(HcfMalloc(sizeof(CipherFwkCtxT), 0));
497     if (context == nullptr) {
498         napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "create context fail!"));
499         LOGE("create context fail!");
500         return nullptr;
501     }
502 
503     if (!BuildContextForUpdate(env, info, context)) {
504         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "build context for update fail!"));
505         LOGE("build context for update fail!");
506         FreeCipherFwkCtx(env, context);
507         return nullptr;
508     }
509 
510     return NewAsyncUpdate(env, context);
511 }
512 
JsCipherDoFinal(napi_env env,napi_callback_info info)513 napi_value NapiCipher::JsCipherDoFinal(napi_env env, napi_callback_info info)
514 {
515     CipherFwkCtx context = static_cast<CipherFwkCtx>(HcfMalloc(sizeof(CipherFwkCtxT), 0));
516     if (context == nullptr) {
517         napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "create context fail!"));
518         LOGE("create context fail!");
519         return nullptr;
520     }
521 
522     if (!BuildContextForFinal(env, info, context)) {
523         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "build context for final fail!"));
524         LOGE("build context for final fail!");
525         FreeCipherFwkCtx(env, context);
526         return nullptr;
527     }
528     return NewAsyncDoFinal(env, context);
529 }
530 
JsGetAlgorithm(napi_env env,napi_callback_info info)531 napi_value NapiCipher::JsGetAlgorithm(napi_env env, napi_callback_info info)
532 {
533     napi_value thisVar = nullptr;
534     NapiCipher *napiCipher = nullptr;
535 
536     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
537 
538     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCipher));
539     if (status != napi_ok || napiCipher == nullptr) {
540         LOGE("failed to unwrap napiCipher obj!");
541         return nullptr;
542     }
543 
544     HcfCipher *cipher = napiCipher->GetCipher();
545     if (cipher == nullptr) {
546         LOGE("failed to get cipher obj!");
547         return nullptr;
548     }
549 
550     // execute C function
551     const char *algo = cipher->getAlgorithm(cipher);
552     napi_value instance = nullptr;
553     napi_create_string_utf8(env, algo, NAPI_AUTO_LENGTH, &instance);
554     return instance;
555 }
556 
CipherConstructor(napi_env env,napi_callback_info info)557 napi_value NapiCipher::CipherConstructor(napi_env env, napi_callback_info info)
558 {
559     napi_value thisVar = nullptr;
560     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
561 
562     return thisVar;
563 }
564 
CreateCipher(napi_env env,napi_callback_info info)565 napi_value NapiCipher::CreateCipher(napi_env env, napi_callback_info info)
566 {
567     size_t expectedArgc = ARGS_SIZE_ONE;
568     size_t argc = ARGS_SIZE_ONE;
569     napi_value argv[ARGS_SIZE_ONE] = { nullptr };
570     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
571 
572     if (argc != expectedArgc) {
573         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "The input args num is invalid."));
574         LOGE("The input args num is invalid.");
575         return nullptr;
576     }
577 
578     // create instance according to input js object
579     napi_value instance = nullptr;
580     napi_value constructor = nullptr;
581     napi_get_reference_value(env, classRef_, &constructor);
582     napi_new_instance(env, constructor, argc, argv, &instance);
583 
584     // parse input string
585     std::string algoName;
586     if (!GetStringFromJSParams(env, argv[0], algoName)) {
587         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to get algoName."));
588         LOGE("failed to get algoName.");
589         return nullptr;
590     }
591 
592     // execute C function, generate C object
593     HcfCipher *cipher = nullptr;
594     HcfResult res = HcfCipherCreate(algoName.c_str(), &cipher);
595     if (res != HCF_SUCCESS) {
596         napi_throw(env, GenerateBusinessError(env, res, "create C cipher fail!"));
597         LOGE("create C cipher fail!");
598         return nullptr;
599     }
600     NapiCipher *napiCipher = new (std::nothrow) NapiCipher(cipher);
601     if (napiCipher == nullptr) {
602         napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "new napiCipher failed!"));
603         LOGE("new napiCipher failed!");
604         HcfObjDestroy(cipher);
605         return nullptr;
606     }
607 
608     napi_status status = napi_wrap(env, instance, napiCipher,
609         [](napi_env env, void *data, void *hint) {
610             NapiCipher *napiCipher = static_cast<NapiCipher *>(data);
611             delete napiCipher;
612             return;
613         }, nullptr, nullptr);
614     if (status != napi_ok) {
615         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to wrap napiCipher obj."));
616         LOGE("failed to wrap napiCipher obj!");
617         delete napiCipher;
618         return nullptr;
619     }
620     return instance;
621 }
622 
JsSetCipherSpec(napi_env env,napi_callback_info info)623 napi_value NapiCipher::JsSetCipherSpec(napi_env env, napi_callback_info info)
624 {
625     napi_value thisVar = nullptr;
626     NapiCipher *napiCipher = nullptr;
627     size_t expectedArgc = ARGS_SIZE_TWO;
628     size_t argc = ARGS_SIZE_TWO;
629     napi_value argv[ARGS_SIZE_TWO] = { nullptr };
630     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
631     if (argc != expectedArgc) {
632         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "init failed for wrong argument num."));
633         LOGE("wrong argument num. require 2 arguments. [Argc]: %zu!", argc);
634         return nullptr;
635     }
636     CipherSpecItem item;
637     if (napi_get_value_uint32(env, argv[0], reinterpret_cast<uint32_t *>(&item)) != napi_ok) {
638         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "get JsGetCipherSpecUint8Array failed!"));
639         LOGE("get JsGetCipherSpecUint8Array failed!");
640         return nullptr;
641     }
642     HcfBlob *pSource = nullptr;
643     pSource = GeneralGetBlobFromNapiValue(env, argv[1]);
644     if (pSource == nullptr || pSource->len == 0) {
645         LOGE("failed to get pSource.");
646         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS,
647             "[pSource]: must be of the DataBlob type."));
648         return nullptr;
649     }
650     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCipher));
651     if (status != napi_ok || napiCipher == nullptr) {
652         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to unwrap napiCipher obj!"));
653         LOGE("failed to unwrap napiCipher obj!");
654         return nullptr;
655     }
656     HcfCipher *cipher = napiCipher->GetCipher();
657     HcfResult res = cipher->setCipherSpecUint8Array(cipher, item, *pSource);
658     if (res != HCF_SUCCESS) {
659         napi_throw(env, GenerateBusinessError(env, res, "c set cipher spec failed."));
660         LOGE("c set cipher spec failed.");
661         return nullptr;
662     }
663     return thisVar;
664 }
665 
GetCipherSpecString(napi_env env,CipherSpecItem item,HcfCipher * cipher)666 static napi_value GetCipherSpecString(napi_env env, CipherSpecItem item, HcfCipher *cipher)
667 {
668     char *returnString = nullptr;
669     HcfResult res = cipher->getCipherSpecString(cipher, item, &returnString);
670     if (res != HCF_SUCCESS) {
671         napi_throw(env, GenerateBusinessError(env, res, "c getCipherSpecString failed."));
672         LOGE("c getCipherSpecString fail.");
673         return nullptr;
674     }
675 
676     napi_value instance = nullptr;
677     napi_create_string_utf8(env, returnString, NAPI_AUTO_LENGTH, &instance);
678     HcfFree(returnString);
679     return instance;
680 }
681 
GetCipherSpecUint8Array(napi_env env,CipherSpecItem item,HcfCipher * cipher)682 static napi_value GetCipherSpecUint8Array(napi_env env, CipherSpecItem item, HcfCipher *cipher)
683 {
684     HcfBlob blob = { .data = nullptr, .len = 0 };
685     HcfResult res = cipher->getCipherSpecUint8Array(cipher, item, &blob);
686     if (res != HCF_SUCCESS) {
687         napi_throw(env, GenerateBusinessError(env, res, "c getCipherSpecUint8Array fail."));
688         LOGE("c getCipherSpecUint8Array fail.");
689         return nullptr;
690     }
691 
692     napi_value instance = ConvertCipherBlobToNapiValue(env, &blob);
693     HcfBlobDataClearAndFree(&blob);
694     return instance;
695 }
696 
JsGetCipherSpec(napi_env env,napi_callback_info info)697 napi_value NapiCipher::JsGetCipherSpec(napi_env env, napi_callback_info info)
698 {
699     napi_value thisVar = nullptr;
700     NapiCipher *napiCipher = nullptr;
701     size_t expectedArgc = ARGS_SIZE_ONE;
702     size_t argc = ARGS_SIZE_ONE;
703     napi_value argv[ARGS_SIZE_ONE] = { nullptr };
704     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
705     if (argc != expectedArgc) {
706         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "init failed for wrong argument num."));
707         LOGE("wrong argument num. require 1 arguments. [Argc]: %zu!", argc);
708         return nullptr;
709     }
710     CipherSpecItem item;
711     if (napi_get_value_uint32(env, argv[0], reinterpret_cast<uint32_t *>(&item)) != napi_ok) {
712         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "get getCipherSpecString failed!"));
713         LOGE("get getCipherSpecString failed!");
714         return nullptr;
715     }
716 
717     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCipher));
718     if (status != napi_ok || napiCipher == nullptr) {
719         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to unwrap napiCipher obj!"));
720         LOGE("failed to unwrap napiCipher obj!");
721         return nullptr;
722     }
723     HcfCipher *cipher = napiCipher->GetCipher();
724     if (cipher == nullptr) {
725         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to get cipher obj!"));
726         LOGE("failed to get cipher obj!");
727         return nullptr;
728     }
729 
730     int32_t type = GetCipherSpecType(item);
731     if (type == SPEC_ITEM_TYPE_STR) {
732         return GetCipherSpecString(env, item, cipher);
733     } else if (type == SPEC_ITEM_TYPE_UINT8ARR) {
734         return GetCipherSpecUint8Array(env, item, cipher);
735     } else {
736         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "CipherSpecItem not support!"));
737         return nullptr;
738     }
739 }
740 
DefineCipherJSClass(napi_env env,napi_value exports)741 void NapiCipher::DefineCipherJSClass(napi_env env, napi_value exports)
742 {
743     napi_property_descriptor desc[] = {
744         DECLARE_NAPI_FUNCTION("createCipher", CreateCipher),
745     };
746     napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
747 
748     napi_property_descriptor classDesc[] = {
749         DECLARE_NAPI_FUNCTION("init", NapiCipher::JsCipherInit),
750         DECLARE_NAPI_FUNCTION("update", NapiCipher::JsCipherUpdate),
751         DECLARE_NAPI_FUNCTION("doFinal", NapiCipher::JsCipherDoFinal),
752         DECLARE_NAPI_FUNCTION("setCipherSpec", NapiCipher::JsSetCipherSpec),
753         DECLARE_NAPI_FUNCTION("getCipherSpec", NapiCipher::JsGetCipherSpec),
754         { .utf8name = "algName", .getter = NapiCipher::JsGetAlgorithm },
755     };
756     napi_value constructor = nullptr;
757     napi_define_class(env, "Cipher", NAPI_AUTO_LENGTH, NapiCipher::CipherConstructor, nullptr,
758         sizeof(classDesc) / sizeof(classDesc[0]), classDesc, &constructor);
759     napi_create_reference(env, constructor, 1, &classRef_);
760 }
761 } // CryptoFramework
762 } // OHOS