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