1 /*
2  * Copyright (C) 2022-2024 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     napi_ref cipherRef = nullptr;
41     napi_ref keyRef = nullptr;
42 
43     HcfCipher *cipher = nullptr;
44     HcfKey *key = nullptr;
45     HcfParamsSpec *paramsSpec = nullptr;
46     HcfBlob input = { .data = nullptr, .len = 0 };
47     HcfBlob output = { .data = nullptr, .len = 0 };
48     enum HcfCryptoMode opMode = ENCRYPT_MODE;
49 
50     HcfResult errCode = HCF_SUCCESS;
51     const char *errMsg = nullptr;
52 };
53 
54 using CipherFwkCtx = CipherFwkCtxT *;
55 
FreeParamsSpec(HcfParamsSpec * paramsSpec)56 static void FreeParamsSpec(HcfParamsSpec *paramsSpec)
57 {
58     if (paramsSpec == nullptr) {
59         return;
60     }
61     if (IV_PARAMS_SPEC.compare(paramsSpec->getType()) == 0) {
62         HcfIvParamsSpec *iv = reinterpret_cast<HcfIvParamsSpec *>(paramsSpec);
63         HcfFree(iv->iv.data);
64         iv->iv.data = nullptr;
65         iv->iv.len = 0;
66     }
67     if (GCM_PARAMS_SPEC.compare(paramsSpec->getType()) == 0) {
68         HcfGcmParamsSpec *gcm = reinterpret_cast<HcfGcmParamsSpec *>(paramsSpec);
69         HcfFree(gcm->iv.data);
70         HcfFree(gcm->aad.data);
71         HcfFree(gcm->tag.data);
72         gcm->iv.len = 0;
73         gcm->aad.len = 0;
74         gcm->tag.len = 0;
75         gcm->iv.data = nullptr;
76         gcm->aad.data = nullptr;
77         gcm->tag.data = nullptr;
78     }
79     if (CCM_PARAMS_SPEC.compare(paramsSpec->getType()) == 0) {
80         HcfCcmParamsSpec *ccm = reinterpret_cast<HcfCcmParamsSpec *>(paramsSpec);
81         HcfFree(ccm->iv.data);
82         HcfFree(ccm->aad.data);
83         HcfFree(ccm->tag.data);
84         ccm->iv.len = 0;
85         ccm->aad.len = 0;
86         ccm->tag.len = 0;
87         ccm->iv.data = nullptr;
88         ccm->aad.data = nullptr;
89         ccm->tag.data = nullptr;
90     }
91     HcfFree(paramsSpec);
92 }
93 
FreeCipherFwkCtx(napi_env env,CipherFwkCtx & context)94 static void FreeCipherFwkCtx(napi_env env, CipherFwkCtx &context)
95 {
96     if (context == nullptr) {
97         return;
98     }
99 
100     if (context->asyncWork != nullptr) {
101         napi_delete_async_work(env, context->asyncWork);
102         context->asyncWork = nullptr;
103     }
104 
105     if (context->callback != nullptr) {
106         napi_delete_reference(env, context->callback);
107         context->callback = nullptr;
108     }
109 
110     if (context->cipherRef != nullptr) {
111         napi_delete_reference(env, context->cipherRef);
112         context->cipherRef = nullptr;
113     }
114 
115     if (context->keyRef != nullptr) {
116         napi_delete_reference(env, context->keyRef);
117         context->keyRef = nullptr;
118     }
119 
120     if (context->input.data != nullptr) {
121         HcfFree(context->input.data);
122         context->input.data = nullptr;
123         context->input.len = 0;
124     }
125     if (context->output.data != nullptr) {
126         HcfFree(context->output.data);
127         context->output.data = nullptr;
128         context->output.len = 0;
129     }
130     FreeParamsSpec(context->paramsSpec);
131     context->paramsSpec = nullptr;
132 
133     context->cipher = nullptr;
134     context->key = nullptr;
135     context->errMsg = nullptr;
136     HcfFree(context);
137     context = nullptr;
138 }
139 
CreateCipherRef(napi_env env,napi_value thisVar,napi_value key,CipherFwkCtx ctx)140 static bool CreateCipherRef(napi_env env, napi_value thisVar, napi_value key, CipherFwkCtx ctx)
141 {
142     if (napi_create_reference(env, thisVar, 1, &ctx->cipherRef) != napi_ok) {
143         LOGE("create cipher ref failed when do cipher init!");
144         return false;
145     }
146 
147     if (napi_create_reference(env, key, 1, &ctx->keyRef) != napi_ok) {
148         LOGE("create key ref failed when do cipher init!");
149         return false;
150     }
151 
152     return true;
153 }
154 
BuildContextForInit(napi_env env,napi_callback_info info,CipherFwkCtx context)155 static bool BuildContextForInit(napi_env env, napi_callback_info info, CipherFwkCtx context)
156 {
157     napi_value thisVar = nullptr;
158     NapiCipher *napiCipher = nullptr;
159     NapiKey *napiKey = nullptr;
160     size_t expectedArgc = ARGS_SIZE_FOUR;
161     size_t argc = ARGS_SIZE_FOUR;
162     napi_value argv[ARGS_SIZE_FOUR] = { nullptr };
163     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
164     if (argc != expectedArgc && argc != expectedArgc - 1) {
165         LOGE("wrong argument num. require 3 or 4 arguments. [Argc]: %zu!", argc);
166         return false;
167     }
168     context->asyncType = isCallback(env, argv[expectedArgc - 1], argc, expectedArgc) ? ASYNC_CALLBACK : ASYNC_PROMISE;
169 
170     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCipher));
171     if (status != napi_ok || napiCipher == nullptr) {
172         LOGE("failed to unwrap napi napiCipher obj!");
173         return false;
174     }
175     context->cipher = napiCipher->GetCipher();
176 
177     // get opMode, type is uint32
178     size_t index = 0;
179     if (napi_get_value_uint32(env, argv[index++], reinterpret_cast<uint32_t *>(&(context->opMode))) != napi_ok) {
180         LOGE("get opMode failed!");
181         return false;
182     }
183 
184     // get key, unwrap from JS
185     status = napi_unwrap(env, argv[index++], reinterpret_cast<void **>(&napiKey));
186     if (status != napi_ok || napiKey == nullptr) {
187         LOGE("failed to unwrap napi napiSymKey obj!");
188         return false;
189     }
190     context->key = napiKey->GetHcfKey();
191 
192     // get paramsSpec, unwrap from JS
193     napi_valuetype valueType;
194     napi_typeof(env, argv[index], &valueType);
195     if (valueType != napi_null) {
196         if (!GetParamsSpecFromNapiValue(env, argv[index], context->opMode, &context->paramsSpec)) {
197             LOGE("GetParamsSpecFromNapiValue failed!");
198             return false;
199         }
200     }
201     index++;
202 
203     if (!CreateCipherRef(env, thisVar, argv[PARAM1], context)) {
204         return false;
205     }
206 
207     if (context->asyncType == ASYNC_PROMISE) {
208         napi_create_promise(env, &context->deferred, &context->promise);
209         return true;
210     } else {
211         return GetCallbackFromJSParams(env, argv[index], &context->callback);
212     }
213 }
214 
BuildContextForUpdate(napi_env env,napi_callback_info info,CipherFwkCtx context)215 static bool BuildContextForUpdate(napi_env env, napi_callback_info info, CipherFwkCtx context)
216 {
217     napi_value thisVar = nullptr;
218     NapiCipher *napiCipher = nullptr;
219     size_t expectedArgc = ARGS_SIZE_TWO;
220     size_t argc = ARGS_SIZE_TWO;
221     napi_value argv[ARGS_SIZE_TWO] = { nullptr };
222     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
223     // argc : in & out, receives the actual count of arguments
224     if (argc != expectedArgc && argc != expectedArgc - 1) {
225         LOGE("wrong argument num. require 1 or 2 arguments. [Argc]: %zu!", argc);
226         return false;
227     }
228     context->asyncType = isCallback(env, argv[expectedArgc - 1], argc, expectedArgc) ? ASYNC_CALLBACK : ASYNC_PROMISE;
229 
230     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCipher));
231     if (status != napi_ok || napiCipher == nullptr) {
232         LOGE("failed to unwrap napi napiCipher obj!");
233         return false;
234     }
235     context->cipher = napiCipher->GetCipher();
236 
237     // get input, type is blob
238     size_t index = 0;
239     HcfBlob *input = nullptr;
240     input = GetBlobFromNapiDataBlob(env, argv[index++]);
241     if (input == nullptr) {
242         LOGE("GetBlobFromNapiDataBlob failed!");
243         return false;
244     }
245     context->input.data = input->data;
246     context->input.len = input->len;
247     HcfFree(input);
248 
249     if (napi_create_reference(env, thisVar, 1, &context->cipherRef) != napi_ok) {
250         LOGE("create cipher ref failed when do cipher update!");
251         return false;
252     }
253 
254     if (context->asyncType == ASYNC_PROMISE) {
255         napi_create_promise(env, &context->deferred, &context->promise);
256         return true;
257     } else {
258         return GetCallbackFromJSParams(env, argv[index], &context->callback);
259     }
260 }
261 
BuildContextForFinal(napi_env env,napi_callback_info info,CipherFwkCtx context)262 static bool BuildContextForFinal(napi_env env, napi_callback_info info, CipherFwkCtx context)
263 {
264     napi_value thisVar = nullptr;
265     NapiCipher *napiCipher = nullptr;
266     size_t expectedArgc = ARGS_SIZE_TWO;
267     size_t argc = ARGS_SIZE_TWO;
268     napi_value argv[ARGS_SIZE_TWO] = { nullptr };
269     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
270     if (argc != expectedArgc && argc != expectedArgc - 1) {
271         LOGE("wrong argument num. require 1 or 2 arguments. [Argc]: %zu!", argc);
272         return false;
273     }
274     context->asyncType = isCallback(env, argv[expectedArgc - 1], argc, expectedArgc) ? ASYNC_CALLBACK : ASYNC_PROMISE;
275 
276     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCipher));
277     if (status != napi_ok || napiCipher == nullptr) {
278         LOGE("failed to unwrap napi napiCipher obj!");
279         return false;
280     }
281     context->cipher = napiCipher->GetCipher();
282 
283     // get input, type is blob
284     size_t index = 0;
285     napi_valuetype valueType;
286     napi_typeof(env, argv[index], &valueType);
287     if (valueType != napi_null) {
288         HcfBlob *input = nullptr;
289         input = GetBlobFromNapiDataBlob(env, argv[index]);
290         if (input == nullptr) {
291             LOGE("GetBlobFromNapiDataBlob failed!");
292             return false;
293         }
294         context->input.data = input->data;
295         context->input.len = input->len;
296         HcfFree(input);
297     }
298 
299     if (napi_create_reference(env, thisVar, 1, &context->cipherRef) != napi_ok) {
300         LOGE("create cipher ref failed when do cipher final!");
301         return false;
302     }
303 
304     index++;
305     if (context->asyncType == ASYNC_PROMISE) {
306         napi_create_promise(env, &context->deferred, &context->promise);
307         return true;
308     } else {
309         return GetCallbackFromJSParams(env, argv[index], &context->callback);
310     }
311 }
312 
ReturnCallbackResult(napi_env env,CipherFwkCtx context,napi_value result)313 static void ReturnCallbackResult(napi_env env, CipherFwkCtx context, napi_value result)
314 {
315     napi_value businessError = nullptr;
316     if (context->errCode != HCF_SUCCESS) {
317         businessError = GenerateBusinessError(env, context->errCode, context->errMsg);
318     }
319     napi_value params[ARGS_SIZE_TWO] = { businessError, result };
320 
321     napi_value func = nullptr;
322     napi_get_reference_value(env, context->callback, &func);
323 
324     napi_value recv = nullptr;
325     napi_value callFuncRet = nullptr;
326     napi_get_undefined(env, &recv);
327     napi_call_function(env, recv, func, ARGS_SIZE_TWO, params, &callFuncRet);
328 }
329 
ReturnPromiseResult(napi_env env,CipherFwkCtx context,napi_value result)330 static void ReturnPromiseResult(napi_env env, CipherFwkCtx context, napi_value result)
331 {
332     if (context->errCode == HCF_SUCCESS) {
333         napi_resolve_deferred(env, context->deferred, result);
334     } else {
335         napi_reject_deferred(env, context->deferred,
336             GenerateBusinessError(env, context->errCode, context->errMsg));
337     }
338 }
339 
340 // init execute
AsyncInitProcess(napi_env env,void * data)341 static void AsyncInitProcess(napi_env env, void *data)
342 {
343     CipherFwkCtx context = static_cast<CipherFwkCtx>(data);
344     HcfCipher *cipher = context->cipher;
345     HcfParamsSpec *params = context->paramsSpec;
346     HcfKey *key = context->key;
347 
348     context->errCode = cipher->init(cipher, context->opMode, key, params);
349     if (context->errCode != HCF_SUCCESS) {
350         LOGD("[error] init ret:%d", context->errCode);
351         context->errMsg = "init failed.";
352     }
353 }
354 
355 // update execute
AsyncUpdateProcess(napi_env env,void * data)356 static void AsyncUpdateProcess(napi_env env, void *data)
357 {
358     CipherFwkCtx context = static_cast<CipherFwkCtx>(data);
359     HcfCipher *cipher = context->cipher;
360     context->errCode = cipher->update(cipher, &context->input, &context->output);
361     if (context->errCode != HCF_SUCCESS) {
362         LOGD("[error] Update ret:%d!", context->errCode);
363         context->errMsg = "update failed.";
364     }
365 }
366 
AsyncDoFinalProcess(napi_env env,void * data)367 static void AsyncDoFinalProcess(napi_env env, void *data)
368 {
369     CipherFwkCtx context = static_cast<CipherFwkCtx>(data);
370     HcfCipher *cipher = context->cipher;
371 
372     context->errCode = cipher->doFinal(cipher, &context->input, &context->output);
373     if (context->errCode != HCF_SUCCESS) {
374         LOGD("[error] doFinal ret:%d!", context->errCode);
375         context->errMsg = "doFinal failed.";
376     }
377 }
378 
AsyncInitReturn(napi_env env,napi_status status,void * data)379 static void AsyncInitReturn(napi_env env, napi_status status, void *data)
380 {
381     CipherFwkCtx context = static_cast<CipherFwkCtx>(data);
382     napi_value result = NapiGetNull(env);
383 
384     if (context->asyncType == ASYNC_CALLBACK) {
385         ReturnCallbackResult(env, context, result);
386     } else {
387         ReturnPromiseResult(env, context, result);
388     }
389     FreeCipherFwkCtx(env, context);
390 }
391 
AsyncUpdateReturn(napi_env env,napi_status status,void * data)392 static void AsyncUpdateReturn(napi_env env, napi_status status, void *data)
393 {
394     CipherFwkCtx context = static_cast<CipherFwkCtx>(data);
395     napi_value instance = ConvertBlobToNapiValue(env, &context->output);
396     if (instance == nullptr) {
397         LOGE("May be nullptr!");
398         instance = NapiGetNull(env);
399     }
400 
401     if (context->asyncType == ASYNC_CALLBACK) {
402         ReturnCallbackResult(env, context, instance);
403     } else {
404         ReturnPromiseResult(env, context, instance);
405     }
406     FreeCipherFwkCtx(env, context);
407 }
408 
AsyncDoFinalReturn(napi_env env,napi_status status,void * data)409 static void AsyncDoFinalReturn(napi_env env, napi_status status, void *data)
410 {
411     CipherFwkCtx context = static_cast<CipherFwkCtx>(data);
412     napi_value instance = ConvertBlobToNapiValue(env, &context->output);
413     if (instance == nullptr) {
414         LOGE("Maybe in decrypt mode, or CCM crypto maybe occur!");
415         instance = NapiGetNull(env);
416     }
417 
418     if (context->asyncType == ASYNC_CALLBACK) {
419         ReturnCallbackResult(env, context, instance);
420     } else {
421         ReturnPromiseResult(env, context, instance);
422     }
423     FreeCipherFwkCtx(env, context);
424 }
425 
NewAsyncInit(napi_env env,CipherFwkCtx context)426 static napi_value NewAsyncInit(napi_env env, CipherFwkCtx context)
427 {
428     napi_value resourceName = nullptr;
429     napi_create_string_utf8(env, "init", NAPI_AUTO_LENGTH, &resourceName);
430 
431     napi_create_async_work(
432         env, nullptr, resourceName,
433         [](napi_env env, void *data) {
434             AsyncInitProcess(env, data);
435             return;
436         },
437         [](napi_env env, napi_status status, void *data) {
438             AsyncInitReturn(env, status, data);
439             return;
440         },
441         static_cast<void *>(context),
442         &context->asyncWork);
443 
444     napi_queue_async_work(env, context->asyncWork);
445     if (context->asyncType == ASYNC_PROMISE) {
446         return context->promise;
447     } else {
448         return NapiGetNull(env);
449     }
450 }
451 
NewAsyncUpdate(napi_env env,CipherFwkCtx context)452 static napi_value NewAsyncUpdate(napi_env env, CipherFwkCtx context)
453 {
454     napi_value resourceName = nullptr;
455     napi_create_string_utf8(env, "update", NAPI_AUTO_LENGTH, &resourceName);
456 
457     napi_create_async_work(
458         env, nullptr, resourceName,
459         [](napi_env env, void *data) {
460             AsyncUpdateProcess(env, data);
461             return;
462         },
463         [](napi_env env, napi_status status, void *data) {
464             AsyncUpdateReturn(env, status, data);
465             return;
466         },
467         static_cast<void *>(context),
468         &context->asyncWork);
469 
470     napi_queue_async_work(env, context->asyncWork);
471     if (context->asyncType == ASYNC_PROMISE) {
472         return context->promise;
473     } else {
474         return NapiGetNull(env);
475     }
476 }
477 
NewAsyncDoFinal(napi_env env,CipherFwkCtx context)478 static napi_value NewAsyncDoFinal(napi_env env, CipherFwkCtx context)
479 {
480     napi_value resourceName = nullptr;
481     napi_create_string_utf8(env, "doFinal", NAPI_AUTO_LENGTH, &resourceName);
482 
483     napi_create_async_work(
484         env, nullptr, resourceName,
485         [](napi_env env, void *data) {
486             AsyncDoFinalProcess(env, data);
487             return;
488         },
489         [](napi_env env, napi_status status, void *data) {
490             AsyncDoFinalReturn(env, status, data);
491             return;
492         },
493         static_cast<void *>(context),
494         &context->asyncWork);
495 
496     napi_queue_async_work(env, context->asyncWork);
497     if (context->asyncType == ASYNC_PROMISE) {
498         return context->promise;
499     } else {
500         return NapiGetNull(env);
501     }
502 }
503 
NapiCipher(HcfCipher * cipher)504 NapiCipher::NapiCipher(HcfCipher *cipher)
505 {
506     this->cipher_ = cipher;
507 }
508 
~NapiCipher()509 NapiCipher::~NapiCipher()
510 {
511     HcfObjDestroy(this->cipher_);
512 }
513 
GetCipher() const514 HcfCipher *NapiCipher::GetCipher() const
515 {
516     return this->cipher_;
517 }
518 
JsCipherInit(napi_env env,napi_callback_info info)519 napi_value NapiCipher::JsCipherInit(napi_env env, napi_callback_info info)
520 {
521     CipherFwkCtx context = static_cast<CipherFwkCtx>(HcfMalloc(sizeof(CipherFwkCtxT), 0));
522     if (context == nullptr) {
523         napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "create context fail!"));
524         LOGE("create context fail!");
525         return nullptr;
526     }
527 
528     if (!BuildContextForInit(env, info, context)) {
529         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "build context for init fail!"));
530         LOGE("build context for init fail!");
531         FreeCipherFwkCtx(env, context);
532         return nullptr;
533     }
534 
535     return NewAsyncInit(env, context);
536 }
537 
SyncInit(napi_env env,HcfCipher * cipher,HcfCryptoMode opMode,HcfKey * key,HcfParamsSpec * paramsSpec)538 static napi_value SyncInit(napi_env env, HcfCipher *cipher, HcfCryptoMode opMode, HcfKey *key,
539     HcfParamsSpec *paramsSpec)
540 {
541     HcfResult res = cipher->init(cipher, opMode, key, paramsSpec);
542     if (res != HCF_SUCCESS) {
543         LOGE("failed to cipher init.");
544         napi_throw(env, GenerateBusinessError(env, res, "init cipher fail."));
545         return nullptr;
546     }
547     return NapiGetNull(env);
548 }
549 
JsCipherInitSync(napi_env env,napi_callback_info info)550 napi_value NapiCipher::JsCipherInitSync(napi_env env, napi_callback_info info)
551 {
552     napi_value thisVar = nullptr;
553     size_t argc = ARGS_SIZE_THREE;
554     napi_value argv[ARGS_SIZE_THREE] = { nullptr };
555     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
556     if (argc != ARGS_SIZE_THREE) {
557         LOGE("wrong argument num. require 3 arguments. [Argc]: %zu!", argc);
558         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "invalid params count"));
559         return nullptr;
560     }
561     NapiCipher *napiCipher = nullptr;
562     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCipher));
563     if (status != napi_ok || napiCipher == nullptr) {
564         LOGE("failed to unwrap napi napiCipher obj!");
565         napi_throw(env, GenerateBusinessError(env, HCF_ERR_NAPI, "unwrap napi napiCipher failed!"));
566         return nullptr;
567     }
568     HcfCipher *cipher = napiCipher->GetCipher();
569     // get opMode, type is uint32
570     size_t index = 0;
571     enum HcfCryptoMode opMode = ENCRYPT_MODE;
572     if (napi_get_value_uint32(env, argv[index++], reinterpret_cast<uint32_t *>(&opMode)) != napi_ok) {
573         LOGE("get option mode failed!");
574         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "get napi option mode failed!"));
575         return nullptr;
576     }
577     // get key, unwrap from JS
578     NapiKey *napiKey = nullptr;
579     status = napi_unwrap(env, argv[index++], reinterpret_cast<void **>(&napiKey));
580     if (status != napi_ok || napiKey == nullptr) {
581         LOGE("get key obj failed!");
582         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "get napi key failed!"));
583         return nullptr;
584     }
585     HcfKey *key = napiKey->GetHcfKey();
586     // get paramsSpec, unwrap from JS
587     HcfParamsSpec *paramsSpec = nullptr;
588     napi_valuetype valueType;
589     napi_typeof(env, argv[index], &valueType);
590     if (valueType != napi_null) {
591         if (!GetParamsSpecFromNapiValue(env, argv[index], opMode, &paramsSpec)) {
592             LOGE("get params failed!");
593             napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "get napi paramsSpec failed!"));
594             return nullptr;
595         }
596     }
597     napi_value instance = SyncInit(env, cipher, opMode, key, paramsSpec);
598     FreeParamsSpec(paramsSpec);
599     return instance;
600 }
601 
JsCipherUpdate(napi_env env,napi_callback_info info)602 napi_value NapiCipher::JsCipherUpdate(napi_env env, napi_callback_info info)
603 {
604     CipherFwkCtx context = static_cast<CipherFwkCtx>(HcfMalloc(sizeof(CipherFwkCtxT), 0));
605     if (context == nullptr) {
606         napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "create context fail!"));
607         LOGE("create context fail!");
608         return nullptr;
609     }
610 
611     if (!BuildContextForUpdate(env, info, context)) {
612         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "build context for update fail!"));
613         LOGE("build context for update fail!");
614         FreeCipherFwkCtx(env, context);
615         return nullptr;
616     }
617 
618     return NewAsyncUpdate(env, context);
619 }
620 
JsCipherUpdateSync(napi_env env,napi_callback_info info)621 napi_value NapiCipher::JsCipherUpdateSync(napi_env env, napi_callback_info info)
622 {
623     napi_value thisVar = nullptr;
624     NapiCipher *napiCipher = nullptr;
625     size_t argc = ARGS_SIZE_ONE;
626     napi_value argv[ARGS_SIZE_ONE] = { nullptr };
627     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
628     if (argc != ARGS_SIZE_ONE) {
629         LOGE("wrong argument num. require 1 arguments. [Argc]: %zu!", argc);
630         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "invalid params count"));
631         return nullptr;
632     }
633     HcfCipher *cipher = nullptr;
634     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCipher));
635     if (status != napi_ok || napiCipher == nullptr) {
636         LOGE("failed to unwrap napi napiCipher obj!");
637         napi_throw(env, GenerateBusinessError(env, HCF_ERR_NAPI, "unwrap napi cipher failed!"));
638         return nullptr;
639     }
640     cipher = napiCipher->GetCipher();
641     // get input, type is blob
642     HcfBlob input = { 0 };
643     HcfResult errCode = GetBlobFromNapiValue(env, argv[PARAM0], &input);
644     if (errCode != HCF_SUCCESS) {
645         LOGE("failed to get input blob!");
646         napi_throw(env, GenerateBusinessError(env, errCode, "get input blob failed!"));
647         return nullptr;
648     }
649     HcfBlob output = { .data = nullptr, .len = 0 };
650     errCode = cipher->update(cipher, &input, &output);
651     HcfBlobDataClearAndFree(&input);
652     if (errCode != HCF_SUCCESS) {
653         LOGE("failed to update!");
654         napi_throw(env, GenerateBusinessError(env, errCode, "update fail!"));
655         return nullptr;
656     }
657 
658     napi_value instance = nullptr;
659     errCode = ConvertDataBlobToNapiValue(env, &output, &instance);
660     HcfBlobDataClearAndFree(&output);
661     if (errCode != HCF_SUCCESS) {
662         LOGE("cipher update convert dataBlob to napi_value failed!");
663         napi_throw(env, GenerateBusinessError(env, errCode, "cipher update convert dataBlob to napi_value failed!"));
664         return nullptr;
665     }
666     return instance;
667 }
668 
JsCipherDoFinal(napi_env env,napi_callback_info info)669 napi_value NapiCipher::JsCipherDoFinal(napi_env env, napi_callback_info info)
670 {
671     CipherFwkCtx context = static_cast<CipherFwkCtx>(HcfMalloc(sizeof(CipherFwkCtxT), 0));
672     if (context == nullptr) {
673         napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "create context fail!"));
674         LOGE("create context fail!");
675         return nullptr;
676     }
677 
678     if (!BuildContextForFinal(env, info, context)) {
679         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "build context for final fail!"));
680         LOGE("build context for final fail!");
681         FreeCipherFwkCtx(env, context);
682         return nullptr;
683     }
684 
685     return NewAsyncDoFinal(env, context);
686 }
687 
JsCipherDoFinalSync(napi_env env,napi_callback_info info)688 napi_value NapiCipher::JsCipherDoFinalSync(napi_env env, napi_callback_info info)
689 {
690     napi_value thisVar = nullptr;
691     NapiCipher *napiCipher = nullptr;
692     size_t argc = ARGS_SIZE_ONE;
693     napi_value argv[ARGS_SIZE_ONE] = { nullptr };
694     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
695     if (argc != ARGS_SIZE_ONE) {
696         LOGE("wrong argument num. require 1 arguments. [Argc]: %zu!", argc);
697         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "invalid params count"));
698         return nullptr;
699     }
700     HcfCipher *cipher = nullptr;
701     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCipher));
702     if (status != napi_ok || napiCipher == nullptr) {
703         LOGE("failed to unwrap napi cipher obj!");
704         napi_throw(env, GenerateBusinessError(env, HCF_ERR_NAPI, "unwrap napi cipher failed"));
705         return nullptr;
706     }
707     cipher = napiCipher->GetCipher();
708     // get input, type is blob
709     napi_valuetype valueType;
710     HcfBlob *input = nullptr;
711     HcfBlob blob = { 0 };
712     napi_typeof(env, argv[PARAM0], &valueType);
713     if (valueType != napi_null) {
714         HcfResult ret = GetBlobFromNapiValue(env, argv[PARAM0], &blob);
715         if (ret != HCF_SUCCESS) {
716             LOGE("failed to get input blob!");
717             napi_throw(env, GenerateBusinessError(env, ret, "get input blob failed!"));
718             return nullptr;
719         }
720         input = &blob;
721     }
722     HcfBlob output = { .data = nullptr, .len = 0 };
723     HcfResult res = cipher->doFinal(cipher, input, &output);
724     HcfBlobDataClearAndFree(input);
725     if (res != HCF_SUCCESS) {
726         LOGE("failed to do final!");
727         napi_throw(env, GenerateBusinessError(env, res, "do final fail!"));
728         return nullptr;
729     }
730 
731     napi_value instance = nullptr;
732     res = ConvertDataBlobToNapiValue(env, &output, &instance);
733     HcfBlobDataClearAndFree(&output);
734     if (res != HCF_SUCCESS) {
735         LOGE("cipher convert dataBlob to napi_value failed!");
736         napi_throw(env, GenerateBusinessError(env, res, "cipher convert dataBlob to napi_value failed!"));
737         return nullptr;
738     }
739     return instance;
740 }
741 
JsGetAlgorithm(napi_env env,napi_callback_info info)742 napi_value NapiCipher::JsGetAlgorithm(napi_env env, napi_callback_info info)
743 {
744     napi_value thisVar = nullptr;
745     NapiCipher *napiCipher = nullptr;
746 
747     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
748 
749     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCipher));
750     if (status != napi_ok || napiCipher == nullptr) {
751         LOGE("failed to unwrap napiCipher obj!");
752         return nullptr;
753     }
754 
755     HcfCipher *cipher = napiCipher->GetCipher();
756     if (cipher == nullptr) {
757         LOGE("failed to get cipher obj!");
758         return nullptr;
759     }
760 
761     // execute C function
762     const char *algo = cipher->getAlgorithm(cipher);
763     napi_value instance = nullptr;
764     napi_create_string_utf8(env, algo, NAPI_AUTO_LENGTH, &instance);
765     return instance;
766 }
767 
CipherConstructor(napi_env env,napi_callback_info info)768 napi_value NapiCipher::CipherConstructor(napi_env env, napi_callback_info info)
769 {
770     napi_value thisVar = nullptr;
771     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
772 
773     return thisVar;
774 }
775 
CreateCipher(napi_env env,napi_callback_info info)776 napi_value NapiCipher::CreateCipher(napi_env env, napi_callback_info info)
777 {
778     LOGD("Enter CreateCipher...");
779     size_t expectedArgc = ARGS_SIZE_ONE;
780     size_t argc = ARGS_SIZE_ONE;
781     napi_value argv[ARGS_SIZE_ONE] = { nullptr };
782     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
783 
784     if (argc != expectedArgc) {
785         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "The input args num is invalid."));
786         LOGE("The input args num is invalid.");
787         return nullptr;
788     }
789 
790     // create instance according to input js object
791     napi_value instance = nullptr;
792     napi_value constructor = nullptr;
793     napi_get_reference_value(env, classRef_, &constructor);
794     napi_new_instance(env, constructor, argc, argv, &instance);
795 
796     // parse input string
797     std::string algoName;
798     if (!GetStringFromJSParams(env, argv[0], algoName)) {
799         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to get algoName."));
800         LOGE("failed to get algoName.");
801         return nullptr;
802     }
803 
804     // execute C function, generate C object
805     HcfCipher *cipher = nullptr;
806     HcfResult res = HcfCipherCreate(algoName.c_str(), &cipher);
807     if (res != HCF_SUCCESS) {
808         napi_throw(env, GenerateBusinessError(env, res, "create C cipher fail!"));
809         LOGE("create C cipher fail!");
810         return nullptr;
811     }
812     NapiCipher *napiCipher = new (std::nothrow) NapiCipher(cipher);
813     if (napiCipher == nullptr) {
814         napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "new napiCipher failed!"));
815         LOGE("new napiCipher failed!");
816         HcfObjDestroy(cipher);
817         return nullptr;
818     }
819 
820     napi_status status = napi_wrap(env, instance, napiCipher,
821         [](napi_env env, void *data, void *hint) {
822             NapiCipher *napiCipher = static_cast<NapiCipher *>(data);
823             delete napiCipher;
824             return;
825         }, nullptr, nullptr);
826     if (status != napi_ok) {
827         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to wrap napiCipher obj."));
828         LOGE("failed to wrap napiCipher obj!");
829         delete napiCipher;
830         return nullptr;
831     }
832     return instance;
833 }
834 
JsSetCipherSpec(napi_env env,napi_callback_info info)835 napi_value NapiCipher::JsSetCipherSpec(napi_env env, napi_callback_info info)
836 {
837     napi_value thisVar = nullptr;
838     NapiCipher *napiCipher = nullptr;
839     size_t expectedArgc = ARGS_SIZE_TWO;
840     size_t argc = ARGS_SIZE_TWO;
841     napi_value argv[ARGS_SIZE_TWO] = { nullptr };
842     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
843     if (argc != expectedArgc) {
844         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "init failed for wrong argument num."));
845         LOGE("wrong argument num. require 2 arguments. [Argc]: %zu!", argc);
846         return nullptr;
847     }
848     CipherSpecItem item;
849     if (napi_get_value_uint32(env, argv[0], reinterpret_cast<uint32_t *>(&item)) != napi_ok) {
850         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "get JsGetCipherSpecUint8Array failed!"));
851         LOGE("get JsGetCipherSpecUint8Array failed!");
852         return nullptr;
853     }
854     HcfBlob *pSource = GetBlobFromNapiUint8Arr(env, argv[1]);
855     if (pSource == nullptr || pSource->len == 0) {
856         LOGE("failed to get pSource.");
857         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "[pSource]: must be of the DataBlob type."));
858         return nullptr;
859     }
860     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCipher));
861     if (status != napi_ok || napiCipher == nullptr) {
862         HcfBlobDataFree(pSource);
863         HcfFree(pSource);
864         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to unwrap napiCipher obj!"));
865         LOGE("failed to unwrap napiCipher obj!");
866         return nullptr;
867     }
868     HcfCipher *cipher = napiCipher->GetCipher();
869     HcfResult res = cipher->setCipherSpecUint8Array(cipher, item, *pSource);
870     if (res != HCF_SUCCESS) {
871         HcfBlobDataFree(pSource);
872         HcfFree(pSource);
873         napi_throw(env, GenerateBusinessError(env, res, "c set cipher spec failed."));
874         LOGE("c set cipher spec failed.");
875         return nullptr;
876     }
877     HcfBlobDataFree(pSource);
878     HcfFree(pSource);
879     return thisVar;
880 }
881 
GetCipherSpecString(napi_env env,CipherSpecItem item,HcfCipher * cipher)882 static napi_value GetCipherSpecString(napi_env env, CipherSpecItem item, HcfCipher *cipher)
883 {
884     char *returnString = nullptr;
885     HcfResult res = cipher->getCipherSpecString(cipher, item, &returnString);
886     if (res != HCF_SUCCESS) {
887         napi_throw(env, GenerateBusinessError(env, res, "c getCipherSpecString failed."));
888         LOGE("c getCipherSpecString fail.");
889         return nullptr;
890     }
891 
892     napi_value instance = nullptr;
893     napi_create_string_utf8(env, returnString, NAPI_AUTO_LENGTH, &instance);
894     HcfFree(returnString);
895     return instance;
896 }
897 
GetCipherSpecUint8Array(napi_env env,CipherSpecItem item,HcfCipher * cipher)898 static napi_value GetCipherSpecUint8Array(napi_env env, CipherSpecItem item, HcfCipher *cipher)
899 {
900     HcfBlob blob = { .data = nullptr, .len = 0 };
901     HcfResult res = cipher->getCipherSpecUint8Array(cipher, item, &blob);
902     if (res != HCF_SUCCESS) {
903         napi_throw(env, GenerateBusinessError(env, res, "c getCipherSpecUint8Array fail."));
904         LOGE("c getCipherSpecUint8Array fail.");
905         return nullptr;
906     }
907 
908     napi_value instance = ConvertObjectBlobToNapiValue(env, &blob);
909     HcfBlobDataClearAndFree(&blob);
910     return instance;
911 }
912 
JsGetCipherSpec(napi_env env,napi_callback_info info)913 napi_value NapiCipher::JsGetCipherSpec(napi_env env, napi_callback_info info)
914 {
915     napi_value thisVar = nullptr;
916     NapiCipher *napiCipher = nullptr;
917     size_t expectedArgc = ARGS_SIZE_ONE;
918     size_t argc = ARGS_SIZE_ONE;
919     napi_value argv[ARGS_SIZE_ONE] = { nullptr };
920     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
921     if (argc != expectedArgc) {
922         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "init failed for wrong argument num."));
923         LOGE("wrong argument num. require 1 arguments. [Argc]: %zu!", argc);
924         return nullptr;
925     }
926     CipherSpecItem item;
927     if (napi_get_value_uint32(env, argv[0], reinterpret_cast<uint32_t *>(&item)) != napi_ok) {
928         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "get getCipherSpecString failed!"));
929         LOGE("get getCipherSpecString failed!");
930         return nullptr;
931     }
932 
933     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCipher));
934     if (status != napi_ok || napiCipher == nullptr) {
935         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to unwrap napiCipher obj!"));
936         LOGE("failed to unwrap napiCipher obj!");
937         return nullptr;
938     }
939     HcfCipher *cipher = napiCipher->GetCipher();
940     if (cipher == nullptr) {
941         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to get cipher obj!"));
942         LOGE("failed to get cipher obj!");
943         return nullptr;
944     }
945 
946     int32_t type = GetCipherSpecType(item);
947     if (type == SPEC_ITEM_TYPE_STR) {
948         return GetCipherSpecString(env, item, cipher);
949     } else if (type == SPEC_ITEM_TYPE_UINT8ARR) {
950         return GetCipherSpecUint8Array(env, item, cipher);
951     } else {
952         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "CipherSpecItem not support!"));
953         return nullptr;
954     }
955 }
956 
DefineCipherJSClass(napi_env env,napi_value exports)957 void NapiCipher::DefineCipherJSClass(napi_env env, napi_value exports)
958 {
959     napi_property_descriptor desc[] = {
960         DECLARE_NAPI_FUNCTION("createCipher", CreateCipher),
961     };
962     napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
963 
964     napi_property_descriptor classDesc[] = {
965         DECLARE_NAPI_FUNCTION("init", NapiCipher::JsCipherInit),
966         DECLARE_NAPI_FUNCTION("update", NapiCipher::JsCipherUpdate),
967         DECLARE_NAPI_FUNCTION("doFinal", NapiCipher::JsCipherDoFinal),
968         DECLARE_NAPI_FUNCTION("initSync", NapiCipher::JsCipherInitSync),
969         DECLARE_NAPI_FUNCTION("updateSync", NapiCipher::JsCipherUpdateSync),
970         DECLARE_NAPI_FUNCTION("doFinalSync", NapiCipher::JsCipherDoFinalSync),
971         DECLARE_NAPI_FUNCTION("setCipherSpec", NapiCipher::JsSetCipherSpec),
972         DECLARE_NAPI_FUNCTION("getCipherSpec", NapiCipher::JsGetCipherSpec),
973         { .utf8name = "algName", .getter = NapiCipher::JsGetAlgorithm },
974     };
975     napi_value constructor = nullptr;
976     napi_define_class(env, "Cipher", NAPI_AUTO_LENGTH, NapiCipher::CipherConstructor, nullptr,
977         sizeof(classDesc) / sizeof(classDesc[0]), classDesc, &constructor);
978     napi_create_reference(env, constructor, 1, &classRef_);
979 }
980 } // CryptoFramework
981 } // OHOS
982