• 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 static 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 static 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 = GetBlobFromNapiDataBlob(env, argv[index++]);
209     if (input == nullptr) {
210         LOGE("GetBlobFromNapiDataBlob 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 static 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 = GetBlobFromNapiDataBlob(env, argv[index]);
252         if (input == nullptr) {
253             LOGE("GetBlobFromNapiDataBlob 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 static 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         LOGD("[error] init ret:%d", context->errCode);
307         context->errMsg = "init failed.";
308     }
309 }
310 
311 // update execute
AsyncUpdateProcess(napi_env env,void * data)312 static 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         LOGD("[error] Update ret:%d!", context->errCode);
319         context->errMsg = "update failed.";
320     }
321 }
322 
AsyncDoFinalProcess(napi_env env,void * data)323 static 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         LOGD("[error] doFinal ret:%d!", context->errCode);
331         context->errMsg = "doFinal failed.";
332     }
333 }
334 
AsyncInitReturn(napi_env env,napi_status status,void * data)335 static 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 static 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 static 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 static 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 static 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 static 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     LOGD("Enter CreateCipher...");
568     size_t expectedArgc = ARGS_SIZE_ONE;
569     size_t argc = ARGS_SIZE_ONE;
570     napi_value argv[ARGS_SIZE_ONE] = { nullptr };
571     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
572 
573     if (argc != expectedArgc) {
574         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "The input args num is invalid."));
575         LOGE("The input args num is invalid.");
576         return nullptr;
577     }
578 
579     // create instance according to input js object
580     napi_value instance = nullptr;
581     napi_value constructor = nullptr;
582     napi_get_reference_value(env, classRef_, &constructor);
583     napi_new_instance(env, constructor, argc, argv, &instance);
584 
585     // parse input string
586     std::string algoName;
587     if (!GetStringFromJSParams(env, argv[0], algoName)) {
588         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to get algoName."));
589         LOGE("failed to get algoName.");
590         return nullptr;
591     }
592 
593     // execute C function, generate C object
594     HcfCipher *cipher = nullptr;
595     HcfResult res = HcfCipherCreate(algoName.c_str(), &cipher);
596     if (res != HCF_SUCCESS) {
597         napi_throw(env, GenerateBusinessError(env, res, "create C cipher fail!"));
598         LOGE("create C cipher fail!");
599         return nullptr;
600     }
601     NapiCipher *napiCipher = new (std::nothrow) NapiCipher(cipher);
602     if (napiCipher == nullptr) {
603         napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "new napiCipher failed!"));
604         LOGE("new napiCipher failed!");
605         HcfObjDestroy(cipher);
606         return nullptr;
607     }
608 
609     napi_status status = napi_wrap(env, instance, napiCipher,
610         [](napi_env env, void *data, void *hint) {
611             NapiCipher *napiCipher = static_cast<NapiCipher *>(data);
612             delete napiCipher;
613             return;
614         }, nullptr, nullptr);
615     if (status != napi_ok) {
616         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to wrap napiCipher obj."));
617         LOGE("failed to wrap napiCipher obj!");
618         delete napiCipher;
619         return nullptr;
620     }
621     return instance;
622 }
623 
JsSetCipherSpec(napi_env env,napi_callback_info info)624 napi_value NapiCipher::JsSetCipherSpec(napi_env env, napi_callback_info info)
625 {
626     napi_value thisVar = nullptr;
627     NapiCipher *napiCipher = nullptr;
628     size_t expectedArgc = ARGS_SIZE_TWO;
629     size_t argc = ARGS_SIZE_TWO;
630     napi_value argv[ARGS_SIZE_TWO] = { nullptr };
631     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
632     if (argc != expectedArgc) {
633         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "init failed for wrong argument num."));
634         LOGE("wrong argument num. require 2 arguments. [Argc]: %zu!", argc);
635         return nullptr;
636     }
637     CipherSpecItem item;
638     if (napi_get_value_uint32(env, argv[0], reinterpret_cast<uint32_t *>(&item)) != napi_ok) {
639         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "get JsGetCipherSpecUint8Array failed!"));
640         LOGE("get JsGetCipherSpecUint8Array failed!");
641         return nullptr;
642     }
643     HcfBlob *pSource = nullptr;
644     pSource = GetBlobFromNapiUint8Arr(env, argv[1]);
645     if (pSource == nullptr || pSource->len == 0) {
646         LOGE("failed to get pSource.");
647         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS,
648             "[pSource]: must be of the DataBlob type."));
649         return nullptr;
650     }
651     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCipher));
652     if (status != napi_ok || napiCipher == nullptr) {
653         HcfBlobDataFree(pSource);
654         HcfFree(pSource);
655         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to unwrap napiCipher obj!"));
656         LOGE("failed to unwrap napiCipher obj!");
657         return nullptr;
658     }
659     HcfCipher *cipher = napiCipher->GetCipher();
660     HcfResult res = cipher->setCipherSpecUint8Array(cipher, item, *pSource);
661     if (res != HCF_SUCCESS) {
662         HcfBlobDataFree(pSource);
663         HcfFree(pSource);
664         napi_throw(env, GenerateBusinessError(env, res, "c set cipher spec failed."));
665         LOGE("c set cipher spec failed.");
666         return nullptr;
667     }
668     HcfBlobDataFree(pSource);
669     HcfFree(pSource);
670     return thisVar;
671 }
672 
GetCipherSpecString(napi_env env,CipherSpecItem item,HcfCipher * cipher)673 static napi_value GetCipherSpecString(napi_env env, CipherSpecItem item, HcfCipher *cipher)
674 {
675     char *returnString = nullptr;
676     HcfResult res = cipher->getCipherSpecString(cipher, item, &returnString);
677     if (res != HCF_SUCCESS) {
678         napi_throw(env, GenerateBusinessError(env, res, "c getCipherSpecString failed."));
679         LOGE("c getCipherSpecString fail.");
680         return nullptr;
681     }
682 
683     napi_value instance = nullptr;
684     napi_create_string_utf8(env, returnString, NAPI_AUTO_LENGTH, &instance);
685     HcfFree(returnString);
686     return instance;
687 }
688 
GetCipherSpecUint8Array(napi_env env,CipherSpecItem item,HcfCipher * cipher)689 static napi_value GetCipherSpecUint8Array(napi_env env, CipherSpecItem item, HcfCipher *cipher)
690 {
691     HcfBlob blob = { .data = nullptr, .len = 0 };
692     HcfResult res = cipher->getCipherSpecUint8Array(cipher, item, &blob);
693     if (res != HCF_SUCCESS) {
694         napi_throw(env, GenerateBusinessError(env, res, "c getCipherSpecUint8Array fail."));
695         LOGE("c getCipherSpecUint8Array fail.");
696         return nullptr;
697     }
698 
699     napi_value instance = ConvertCipherBlobToNapiValue(env, &blob);
700     HcfBlobDataClearAndFree(&blob);
701     return instance;
702 }
703 
JsGetCipherSpec(napi_env env,napi_callback_info info)704 napi_value NapiCipher::JsGetCipherSpec(napi_env env, napi_callback_info info)
705 {
706     napi_value thisVar = nullptr;
707     NapiCipher *napiCipher = nullptr;
708     size_t expectedArgc = ARGS_SIZE_ONE;
709     size_t argc = ARGS_SIZE_ONE;
710     napi_value argv[ARGS_SIZE_ONE] = { nullptr };
711     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
712     if (argc != expectedArgc) {
713         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "init failed for wrong argument num."));
714         LOGE("wrong argument num. require 1 arguments. [Argc]: %zu!", argc);
715         return nullptr;
716     }
717     CipherSpecItem item;
718     if (napi_get_value_uint32(env, argv[0], reinterpret_cast<uint32_t *>(&item)) != napi_ok) {
719         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "get getCipherSpecString failed!"));
720         LOGE("get getCipherSpecString failed!");
721         return nullptr;
722     }
723 
724     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCipher));
725     if (status != napi_ok || napiCipher == nullptr) {
726         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to unwrap napiCipher obj!"));
727         LOGE("failed to unwrap napiCipher obj!");
728         return nullptr;
729     }
730     HcfCipher *cipher = napiCipher->GetCipher();
731     if (cipher == nullptr) {
732         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to get cipher obj!"));
733         LOGE("failed to get cipher obj!");
734         return nullptr;
735     }
736 
737     int32_t type = GetCipherSpecType(item);
738     if (type == SPEC_ITEM_TYPE_STR) {
739         return GetCipherSpecString(env, item, cipher);
740     } else if (type == SPEC_ITEM_TYPE_UINT8ARR) {
741         return GetCipherSpecUint8Array(env, item, cipher);
742     } else {
743         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "CipherSpecItem not support!"));
744         return nullptr;
745     }
746 }
747 
DefineCipherJSClass(napi_env env,napi_value exports)748 void NapiCipher::DefineCipherJSClass(napi_env env, napi_value exports)
749 {
750     napi_property_descriptor desc[] = {
751         DECLARE_NAPI_FUNCTION("createCipher", CreateCipher),
752     };
753     napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
754 
755     napi_property_descriptor classDesc[] = {
756         DECLARE_NAPI_FUNCTION("init", NapiCipher::JsCipherInit),
757         DECLARE_NAPI_FUNCTION("update", NapiCipher::JsCipherUpdate),
758         DECLARE_NAPI_FUNCTION("doFinal", NapiCipher::JsCipherDoFinal),
759         DECLARE_NAPI_FUNCTION("setCipherSpec", NapiCipher::JsSetCipherSpec),
760         DECLARE_NAPI_FUNCTION("getCipherSpec", NapiCipher::JsGetCipherSpec),
761         { .utf8name = "algName", .getter = NapiCipher::JsGetAlgorithm },
762     };
763     napi_value constructor = nullptr;
764     napi_define_class(env, "Cipher", NAPI_AUTO_LENGTH, NapiCipher::CipherConstructor, nullptr,
765         sizeof(classDesc) / sizeof(classDesc[0]), classDesc, &constructor);
766     napi_create_reference(env, constructor, 1, &classRef_);
767 }
768 } // CryptoFramework
769 } // OHOS
770