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