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, ¶msSpec)) {
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