1 /*
2 * Copyright (C) 2022-2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "napi_cipher.h"
17 #include "napi_key.h"
18 #include "securec.h"
19 #include "log.h"
20 #include "memory.h"
21
22 #include "cipher.h"
23 #include "napi_utils.h"
24 #include "napi_crypto_framework_defines.h"
25 #include "detailed_iv_params.h"
26 #include "detailed_gcm_params.h"
27 #include "detailed_ccm_params.h"
28
29 namespace OHOS {
30 namespace CryptoFramework {
31 thread_local napi_ref NapiCipher::classRef_ = nullptr;
32
33 struct CipherFwkCtxT {
34 napi_env env = nullptr;
35 AsyncType asyncType = ASYNC_CALLBACK;
36 napi_ref callback = nullptr;
37 napi_deferred deferred = nullptr;
38 napi_value promise = nullptr;
39 napi_async_work asyncWork = nullptr;
40
41 HcfCipher *cipher = nullptr;
42 HcfKey *key = nullptr;
43 HcfParamsSpec *paramsSpec = nullptr;
44 HcfBlob input = { .data = nullptr, .len = 0 };
45 HcfBlob output = { .data = nullptr, .len = 0 };
46 enum HcfCryptoMode opMode = ENCRYPT_MODE;
47
48 HcfResult errCode = HCF_SUCCESS;
49 const char *errMsg = nullptr;
50 };
51
52 using CipherFwkCtx = CipherFwkCtxT *;
53
FreeParamsSpec(HcfParamsSpec * paramsSpec)54 static void FreeParamsSpec(HcfParamsSpec *paramsSpec)
55 {
56 if (paramsSpec == nullptr) {
57 return;
58 }
59 if (IV_PARAMS_SPEC.compare(paramsSpec->getType()) == 0) {
60 HcfIvParamsSpec *iv = reinterpret_cast<HcfIvParamsSpec *>(paramsSpec);
61 HcfFree(iv->iv.data);
62 iv->iv.data = nullptr;
63 iv->iv.len = 0;
64 }
65 if (GCM_PARAMS_SPEC.compare(paramsSpec->getType()) == 0) {
66 HcfGcmParamsSpec *gcm = reinterpret_cast<HcfGcmParamsSpec *>(paramsSpec);
67 HcfFree(gcm->iv.data);
68 HcfFree(gcm->aad.data);
69 HcfFree(gcm->tag.data);
70 gcm->iv.len = 0;
71 gcm->aad.len = 0;
72 gcm->tag.len = 0;
73 gcm->iv.data = nullptr;
74 gcm->aad.data = nullptr;
75 gcm->tag.data = nullptr;
76 }
77 if (CCM_PARAMS_SPEC.compare(paramsSpec->getType()) == 0) {
78 HcfCcmParamsSpec *ccm = reinterpret_cast<HcfCcmParamsSpec *>(paramsSpec);
79 HcfFree(ccm->iv.data);
80 HcfFree(ccm->aad.data);
81 HcfFree(ccm->tag.data);
82 ccm->iv.len = 0;
83 ccm->aad.len = 0;
84 ccm->tag.len = 0;
85 ccm->iv.data = nullptr;
86 ccm->aad.data = nullptr;
87 ccm->tag.data = nullptr;
88 }
89 HcfFree(paramsSpec);
90 }
91
FreeCipherFwkCtx(napi_env env,CipherFwkCtx & context)92 static void FreeCipherFwkCtx(napi_env env, CipherFwkCtx &context)
93 {
94 if (context == nullptr) {
95 return;
96 }
97
98 if (context->asyncWork != nullptr) {
99 napi_delete_async_work(env, context->asyncWork);
100 context->asyncWork = nullptr;
101 }
102
103 if (context->callback != nullptr) {
104 napi_delete_reference(env, context->callback);
105 context->callback = nullptr;
106 }
107 if (context->input.data != nullptr) {
108 HcfFree(context->input.data);
109 context->input.data = nullptr;
110 context->input.len = 0;
111 }
112 if (context->output.data != nullptr) {
113 HcfFree(context->output.data);
114 context->output.data = nullptr;
115 context->output.len = 0;
116 }
117 FreeParamsSpec(context->paramsSpec);
118 context->paramsSpec = nullptr;
119
120 context->cipher = nullptr;
121 context->key = nullptr;
122 context->errMsg = nullptr;
123 HcfFree(context);
124 context = nullptr;
125 }
126
BuildContextForInit(napi_env env,napi_callback_info info,CipherFwkCtx context)127 static bool BuildContextForInit(napi_env env, napi_callback_info info, CipherFwkCtx context)
128 {
129 napi_value thisVar = nullptr;
130 NapiCipher *napiCipher = nullptr;
131 NapiKey *napiKey = nullptr;
132 size_t expectedArgc = ARGS_SIZE_FOUR;
133 size_t argc = ARGS_SIZE_FOUR;
134 napi_value argv[ARGS_SIZE_FOUR] = { nullptr };
135 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
136 if (argc != expectedArgc && argc != expectedArgc - 1) {
137 LOGE("wrong argument num. require 3 or 4 arguments. [Argc]: %zu!", argc);
138 return false;
139 }
140 context->asyncType = isCallback(env, argv[expectedArgc - 1], argc, expectedArgc) ? ASYNC_CALLBACK : ASYNC_PROMISE;
141
142 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCipher));
143 if (status != napi_ok || napiCipher == nullptr) {
144 LOGE("failed to unwrap napi napiCipher obj!");
145 return false;
146 }
147 context->cipher = napiCipher->GetCipher();
148
149 // get opMode, type is uint32
150 size_t index = 0;
151 if (napi_get_value_uint32(env, argv[index++], reinterpret_cast<uint32_t *>(&(context->opMode))) != napi_ok) {
152 LOGE("get opMode failed!");
153 return false;
154 }
155
156 // get key, unwrap from JS
157 status = napi_unwrap(env, argv[index++], reinterpret_cast<void **>(&napiKey));
158 if (status != napi_ok || napiKey == nullptr) {
159 LOGE("failed to unwrap napi napiSymKey obj!");
160 return false;
161 }
162 context->key = napiKey->GetHcfKey();
163
164 // get paramsSpec, unwrap from JS
165 napi_valuetype valueType;
166 napi_typeof(env, argv[index], &valueType);
167 if (valueType != napi_null) {
168 if (!GetParamsSpecFromNapiValue(env, argv[index], context->opMode, &context->paramsSpec)) {
169 LOGE("GetParamsSpecFromNapiValue failed!");
170 return false;
171 }
172 }
173 index++;
174
175 if (context->asyncType == ASYNC_PROMISE) {
176 napi_create_promise(env, &context->deferred, &context->promise);
177 return true;
178 } else {
179 return GetCallbackFromJSParams(env, argv[index], &context->callback);
180 }
181 }
182
BuildContextForUpdate(napi_env env,napi_callback_info info,CipherFwkCtx context)183 static bool BuildContextForUpdate(napi_env env, napi_callback_info info, CipherFwkCtx context)
184 {
185 napi_value thisVar = nullptr;
186 NapiCipher *napiCipher = nullptr;
187 size_t expectedArgc = ARGS_SIZE_TWO;
188 size_t argc = ARGS_SIZE_TWO;
189 napi_value argv[ARGS_SIZE_TWO] = { nullptr };
190 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
191 // argc : in & out, receives the actual count of arguments
192 if (argc != expectedArgc && argc != expectedArgc - 1) {
193 LOGE("wrong argument num. require 1 or 2 arguments. [Argc]: %zu!", argc);
194 return false;
195 }
196 context->asyncType = isCallback(env, argv[expectedArgc - 1], argc, expectedArgc) ? ASYNC_CALLBACK : ASYNC_PROMISE;
197
198 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCipher));
199 if (status != napi_ok || napiCipher == nullptr) {
200 LOGE("failed to unwrap napi napiCipher obj!");
201 return false;
202 }
203 context->cipher = napiCipher->GetCipher();
204
205 // get input, type is blob
206 size_t index = 0;
207 HcfBlob *input = nullptr;
208 input = GetBlobFromNapiDataBlob(env, argv[index++]);
209 if (input == nullptr) {
210 LOGE("GetBlobFromNapiDataBlob failed!");
211 return false;
212 }
213 context->input.data = input->data;
214 context->input.len = input->len;
215 HcfFree(input);
216 if (context->asyncType == ASYNC_PROMISE) {
217 napi_create_promise(env, &context->deferred, &context->promise);
218 return true;
219 } else {
220 return GetCallbackFromJSParams(env, argv[index], &context->callback);
221 }
222 }
223
BuildContextForFinal(napi_env env,napi_callback_info info,CipherFwkCtx context)224 static bool BuildContextForFinal(napi_env env, napi_callback_info info, CipherFwkCtx context)
225 {
226 napi_value thisVar = nullptr;
227 NapiCipher *napiCipher = nullptr;
228 size_t expectedArgc = ARGS_SIZE_TWO;
229 size_t argc = ARGS_SIZE_TWO;
230 napi_value argv[ARGS_SIZE_TWO] = { nullptr };
231 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
232 if (argc != expectedArgc && argc != expectedArgc - 1) {
233 LOGE("wrong argument num. require 1 or 2 arguments. [Argc]: %zu!", argc);
234 return false;
235 }
236 context->asyncType = isCallback(env, argv[expectedArgc - 1], argc, expectedArgc) ? ASYNC_CALLBACK : ASYNC_PROMISE;
237
238 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCipher));
239 if (status != napi_ok || napiCipher == nullptr) {
240 LOGE("failed to unwrap napi napiCipher obj!");
241 return false;
242 }
243 context->cipher = napiCipher->GetCipher();
244
245 // get input, type is blob
246 size_t index = 0;
247 napi_valuetype valueType;
248 napi_typeof(env, argv[index], &valueType);
249 if (valueType != napi_null) {
250 HcfBlob *input = nullptr;
251 input = GetBlobFromNapiDataBlob(env, argv[index]);
252 if (input == nullptr) {
253 LOGE("GetBlobFromNapiDataBlob failed!");
254 return false;
255 }
256 context->input.data = input->data;
257 context->input.len = input->len;
258 HcfFree(input);
259 }
260 index++;
261 if (context->asyncType == ASYNC_PROMISE) {
262 napi_create_promise(env, &context->deferred, &context->promise);
263 return true;
264 } else {
265 return GetCallbackFromJSParams(env, argv[index], &context->callback);
266 }
267 }
268
ReturnCallbackResult(napi_env env,CipherFwkCtx context,napi_value result)269 static void ReturnCallbackResult(napi_env env, CipherFwkCtx context, napi_value result)
270 {
271 napi_value businessError = nullptr;
272 if (context->errCode != HCF_SUCCESS) {
273 businessError = GenerateBusinessError(env, context->errCode, context->errMsg);
274 }
275 napi_value params[ARGS_SIZE_TWO] = { businessError, result };
276
277 napi_value func = nullptr;
278 napi_get_reference_value(env, context->callback, &func);
279
280 napi_value recv = nullptr;
281 napi_value callFuncRet = nullptr;
282 napi_get_undefined(env, &recv);
283 napi_call_function(env, recv, func, ARGS_SIZE_TWO, params, &callFuncRet);
284 }
285
ReturnPromiseResult(napi_env env,CipherFwkCtx context,napi_value result)286 static void ReturnPromiseResult(napi_env env, CipherFwkCtx context, napi_value result)
287 {
288 if (context->errCode == HCF_SUCCESS) {
289 napi_resolve_deferred(env, context->deferred, result);
290 } else {
291 napi_reject_deferred(env, context->deferred,
292 GenerateBusinessError(env, context->errCode, context->errMsg));
293 }
294 }
295
296 // init execute
AsyncInitProcess(napi_env env,void * data)297 static void AsyncInitProcess(napi_env env, void *data)
298 {
299 CipherFwkCtx context = static_cast<CipherFwkCtx>(data);
300 HcfCipher *cipher = context->cipher;
301 HcfParamsSpec *params = context->paramsSpec;
302 HcfKey *key = context->key;
303
304 context->errCode = cipher->init(cipher, context->opMode, key, params);
305 if (context->errCode != HCF_SUCCESS) {
306 LOGD("[error] init ret:%d", context->errCode);
307 context->errMsg = "init failed.";
308 }
309 }
310
311 // update execute
AsyncUpdateProcess(napi_env env,void * data)312 static void AsyncUpdateProcess(napi_env env, void *data)
313 {
314 CipherFwkCtx context = static_cast<CipherFwkCtx>(data);
315 HcfCipher *cipher = context->cipher;
316 context->errCode = cipher->update(cipher, &context->input, &context->output);
317 if (context->errCode != HCF_SUCCESS) {
318 LOGD("[error] Update ret:%d!", context->errCode);
319 context->errMsg = "update failed.";
320 }
321 }
322
AsyncDoFinalProcess(napi_env env,void * data)323 static void AsyncDoFinalProcess(napi_env env, void *data)
324 {
325 CipherFwkCtx context = static_cast<CipherFwkCtx>(data);
326 HcfCipher *cipher = context->cipher;
327
328 context->errCode = cipher->doFinal(cipher, &context->input, &context->output);
329 if (context->errCode != HCF_SUCCESS) {
330 LOGD("[error] doFinal ret:%d!", context->errCode);
331 context->errMsg = "doFinal failed.";
332 }
333 }
334
AsyncInitReturn(napi_env env,napi_status status,void * data)335 static void AsyncInitReturn(napi_env env, napi_status status, void *data)
336 {
337 CipherFwkCtx context = static_cast<CipherFwkCtx>(data);
338 napi_value result = NapiGetNull(env);
339
340 if (context->asyncType == ASYNC_CALLBACK) {
341 ReturnCallbackResult(env, context, result);
342 } else {
343 ReturnPromiseResult(env, context, result);
344 }
345 FreeCipherFwkCtx(env, context);
346 }
347
AsyncUpdateReturn(napi_env env,napi_status status,void * data)348 static void AsyncUpdateReturn(napi_env env, napi_status status, void *data)
349 {
350 CipherFwkCtx context = static_cast<CipherFwkCtx>(data);
351 napi_value instance = ConvertBlobToNapiValue(env, &context->output);
352 if (instance == nullptr) {
353 LOGE("May be nullptr!");
354 instance = NapiGetNull(env);
355 }
356
357 if (context->asyncType == ASYNC_CALLBACK) {
358 ReturnCallbackResult(env, context, instance);
359 } else {
360 ReturnPromiseResult(env, context, instance);
361 }
362 FreeCipherFwkCtx(env, context);
363 }
364
AsyncDoFinalReturn(napi_env env,napi_status status,void * data)365 static void AsyncDoFinalReturn(napi_env env, napi_status status, void *data)
366 {
367 CipherFwkCtx context = static_cast<CipherFwkCtx>(data);
368 napi_value instance = ConvertBlobToNapiValue(env, &context->output);
369 if (instance == nullptr) {
370 LOGE("Maybe in decrypt mode, or CCM crypto maybe occur!");
371 instance = NapiGetNull(env);
372 }
373
374 if (context->asyncType == ASYNC_CALLBACK) {
375 ReturnCallbackResult(env, context, instance);
376 } else {
377 ReturnPromiseResult(env, context, instance);
378 }
379 FreeCipherFwkCtx(env, context);
380 }
381
NewAsyncInit(napi_env env,CipherFwkCtx context)382 static napi_value NewAsyncInit(napi_env env, CipherFwkCtx context)
383 {
384 napi_value resourceName = nullptr;
385 napi_create_string_utf8(env, "init", NAPI_AUTO_LENGTH, &resourceName);
386
387 napi_create_async_work(
388 env, nullptr, resourceName,
389 [](napi_env env, void *data) {
390 AsyncInitProcess(env, data);
391 return;
392 },
393 [](napi_env env, napi_status status, void *data) {
394 AsyncInitReturn(env, status, data);
395 return;
396 },
397 static_cast<void *>(context),
398 &context->asyncWork);
399
400 napi_queue_async_work(env, context->asyncWork);
401 if (context->asyncType == ASYNC_PROMISE) {
402 return context->promise;
403 } else {
404 return NapiGetNull(env);
405 }
406 }
407
NewAsyncUpdate(napi_env env,CipherFwkCtx context)408 static napi_value NewAsyncUpdate(napi_env env, CipherFwkCtx context)
409 {
410 napi_value resourceName = nullptr;
411 napi_create_string_utf8(env, "update", NAPI_AUTO_LENGTH, &resourceName);
412
413 napi_create_async_work(
414 env, nullptr, resourceName,
415 [](napi_env env, void *data) {
416 AsyncUpdateProcess(env, data);
417 return;
418 },
419 [](napi_env env, napi_status status, void *data) {
420 AsyncUpdateReturn(env, status, data);
421 return;
422 },
423 static_cast<void *>(context),
424 &context->asyncWork);
425
426 napi_queue_async_work(env, context->asyncWork);
427 if (context->asyncType == ASYNC_PROMISE) {
428 return context->promise;
429 } else {
430 return NapiGetNull(env);
431 }
432 }
433
NewAsyncDoFinal(napi_env env,CipherFwkCtx context)434 static napi_value NewAsyncDoFinal(napi_env env, CipherFwkCtx context)
435 {
436 napi_value resourceName = nullptr;
437 napi_create_string_utf8(env, "doFinal", NAPI_AUTO_LENGTH, &resourceName);
438
439 napi_create_async_work(
440 env, nullptr, resourceName,
441 [](napi_env env, void *data) {
442 AsyncDoFinalProcess(env, data);
443 return;
444 },
445 [](napi_env env, napi_status status, void *data) {
446 AsyncDoFinalReturn(env, status, data);
447 return;
448 },
449 static_cast<void *>(context),
450 &context->asyncWork);
451
452 napi_queue_async_work(env, context->asyncWork);
453 if (context->asyncType == ASYNC_PROMISE) {
454 return context->promise;
455 } else {
456 return NapiGetNull(env);
457 }
458 }
459
NapiCipher(HcfCipher * cipher)460 NapiCipher::NapiCipher(HcfCipher *cipher)
461 {
462 this->cipher_ = cipher;
463 }
464
~NapiCipher()465 NapiCipher::~NapiCipher()
466 {
467 HcfObjDestroy(this->cipher_);
468 }
469
GetCipher() const470 HcfCipher *NapiCipher::GetCipher() const
471 {
472 return this->cipher_;
473 }
474
JsCipherInit(napi_env env,napi_callback_info info)475 napi_value NapiCipher::JsCipherInit(napi_env env, napi_callback_info info)
476 {
477 CipherFwkCtx context = static_cast<CipherFwkCtx>(HcfMalloc(sizeof(CipherFwkCtxT), 0));
478 if (context == nullptr) {
479 napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "create context fail!"));
480 LOGE("create context fail!");
481 return nullptr;
482 }
483
484 if (!BuildContextForInit(env, info, context)) {
485 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "build context for init fail!"));
486 LOGE("build context for init fail!");
487 FreeCipherFwkCtx(env, context);
488 return nullptr;
489 }
490
491 return NewAsyncInit(env, context);
492 }
493
JsCipherUpdate(napi_env env,napi_callback_info info)494 napi_value NapiCipher::JsCipherUpdate(napi_env env, napi_callback_info info)
495 {
496 CipherFwkCtx context = static_cast<CipherFwkCtx>(HcfMalloc(sizeof(CipherFwkCtxT), 0));
497 if (context == nullptr) {
498 napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "create context fail!"));
499 LOGE("create context fail!");
500 return nullptr;
501 }
502
503 if (!BuildContextForUpdate(env, info, context)) {
504 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "build context for update fail!"));
505 LOGE("build context for update fail!");
506 FreeCipherFwkCtx(env, context);
507 return nullptr;
508 }
509
510 return NewAsyncUpdate(env, context);
511 }
512
JsCipherDoFinal(napi_env env,napi_callback_info info)513 napi_value NapiCipher::JsCipherDoFinal(napi_env env, napi_callback_info info)
514 {
515 CipherFwkCtx context = static_cast<CipherFwkCtx>(HcfMalloc(sizeof(CipherFwkCtxT), 0));
516 if (context == nullptr) {
517 napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "create context fail!"));
518 LOGE("create context fail!");
519 return nullptr;
520 }
521
522 if (!BuildContextForFinal(env, info, context)) {
523 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "build context for final fail!"));
524 LOGE("build context for final fail!");
525 FreeCipherFwkCtx(env, context);
526 return nullptr;
527 }
528 return NewAsyncDoFinal(env, context);
529 }
530
JsGetAlgorithm(napi_env env,napi_callback_info info)531 napi_value NapiCipher::JsGetAlgorithm(napi_env env, napi_callback_info info)
532 {
533 napi_value thisVar = nullptr;
534 NapiCipher *napiCipher = nullptr;
535
536 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
537
538 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCipher));
539 if (status != napi_ok || napiCipher == nullptr) {
540 LOGE("failed to unwrap napiCipher obj!");
541 return nullptr;
542 }
543
544 HcfCipher *cipher = napiCipher->GetCipher();
545 if (cipher == nullptr) {
546 LOGE("failed to get cipher obj!");
547 return nullptr;
548 }
549
550 // execute C function
551 const char *algo = cipher->getAlgorithm(cipher);
552 napi_value instance = nullptr;
553 napi_create_string_utf8(env, algo, NAPI_AUTO_LENGTH, &instance);
554 return instance;
555 }
556
CipherConstructor(napi_env env,napi_callback_info info)557 napi_value NapiCipher::CipherConstructor(napi_env env, napi_callback_info info)
558 {
559 napi_value thisVar = nullptr;
560 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
561
562 return thisVar;
563 }
564
CreateCipher(napi_env env,napi_callback_info info)565 napi_value NapiCipher::CreateCipher(napi_env env, napi_callback_info info)
566 {
567 LOGD("Enter CreateCipher...");
568 size_t expectedArgc = ARGS_SIZE_ONE;
569 size_t argc = ARGS_SIZE_ONE;
570 napi_value argv[ARGS_SIZE_ONE] = { nullptr };
571 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
572
573 if (argc != expectedArgc) {
574 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "The input args num is invalid."));
575 LOGE("The input args num is invalid.");
576 return nullptr;
577 }
578
579 // create instance according to input js object
580 napi_value instance = nullptr;
581 napi_value constructor = nullptr;
582 napi_get_reference_value(env, classRef_, &constructor);
583 napi_new_instance(env, constructor, argc, argv, &instance);
584
585 // parse input string
586 std::string algoName;
587 if (!GetStringFromJSParams(env, argv[0], algoName)) {
588 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to get algoName."));
589 LOGE("failed to get algoName.");
590 return nullptr;
591 }
592
593 // execute C function, generate C object
594 HcfCipher *cipher = nullptr;
595 HcfResult res = HcfCipherCreate(algoName.c_str(), &cipher);
596 if (res != HCF_SUCCESS) {
597 napi_throw(env, GenerateBusinessError(env, res, "create C cipher fail!"));
598 LOGE("create C cipher fail!");
599 return nullptr;
600 }
601 NapiCipher *napiCipher = new (std::nothrow) NapiCipher(cipher);
602 if (napiCipher == nullptr) {
603 napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "new napiCipher failed!"));
604 LOGE("new napiCipher failed!");
605 HcfObjDestroy(cipher);
606 return nullptr;
607 }
608
609 napi_status status = napi_wrap(env, instance, napiCipher,
610 [](napi_env env, void *data, void *hint) {
611 NapiCipher *napiCipher = static_cast<NapiCipher *>(data);
612 delete napiCipher;
613 return;
614 }, nullptr, nullptr);
615 if (status != napi_ok) {
616 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to wrap napiCipher obj."));
617 LOGE("failed to wrap napiCipher obj!");
618 delete napiCipher;
619 return nullptr;
620 }
621 return instance;
622 }
623
JsSetCipherSpec(napi_env env,napi_callback_info info)624 napi_value NapiCipher::JsSetCipherSpec(napi_env env, napi_callback_info info)
625 {
626 napi_value thisVar = nullptr;
627 NapiCipher *napiCipher = nullptr;
628 size_t expectedArgc = ARGS_SIZE_TWO;
629 size_t argc = ARGS_SIZE_TWO;
630 napi_value argv[ARGS_SIZE_TWO] = { nullptr };
631 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
632 if (argc != expectedArgc) {
633 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "init failed for wrong argument num."));
634 LOGE("wrong argument num. require 2 arguments. [Argc]: %zu!", argc);
635 return nullptr;
636 }
637 CipherSpecItem item;
638 if (napi_get_value_uint32(env, argv[0], reinterpret_cast<uint32_t *>(&item)) != napi_ok) {
639 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "get JsGetCipherSpecUint8Array failed!"));
640 LOGE("get JsGetCipherSpecUint8Array failed!");
641 return nullptr;
642 }
643 HcfBlob *pSource = nullptr;
644 pSource = GetBlobFromNapiUint8Arr(env, argv[1]);
645 if (pSource == nullptr || pSource->len == 0) {
646 LOGE("failed to get pSource.");
647 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS,
648 "[pSource]: must be of the DataBlob type."));
649 return nullptr;
650 }
651 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCipher));
652 if (status != napi_ok || napiCipher == nullptr) {
653 HcfBlobDataFree(pSource);
654 HcfFree(pSource);
655 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to unwrap napiCipher obj!"));
656 LOGE("failed to unwrap napiCipher obj!");
657 return nullptr;
658 }
659 HcfCipher *cipher = napiCipher->GetCipher();
660 HcfResult res = cipher->setCipherSpecUint8Array(cipher, item, *pSource);
661 if (res != HCF_SUCCESS) {
662 HcfBlobDataFree(pSource);
663 HcfFree(pSource);
664 napi_throw(env, GenerateBusinessError(env, res, "c set cipher spec failed."));
665 LOGE("c set cipher spec failed.");
666 return nullptr;
667 }
668 HcfBlobDataFree(pSource);
669 HcfFree(pSource);
670 return thisVar;
671 }
672
GetCipherSpecString(napi_env env,CipherSpecItem item,HcfCipher * cipher)673 static napi_value GetCipherSpecString(napi_env env, CipherSpecItem item, HcfCipher *cipher)
674 {
675 char *returnString = nullptr;
676 HcfResult res = cipher->getCipherSpecString(cipher, item, &returnString);
677 if (res != HCF_SUCCESS) {
678 napi_throw(env, GenerateBusinessError(env, res, "c getCipherSpecString failed."));
679 LOGE("c getCipherSpecString fail.");
680 return nullptr;
681 }
682
683 napi_value instance = nullptr;
684 napi_create_string_utf8(env, returnString, NAPI_AUTO_LENGTH, &instance);
685 HcfFree(returnString);
686 return instance;
687 }
688
GetCipherSpecUint8Array(napi_env env,CipherSpecItem item,HcfCipher * cipher)689 static napi_value GetCipherSpecUint8Array(napi_env env, CipherSpecItem item, HcfCipher *cipher)
690 {
691 HcfBlob blob = { .data = nullptr, .len = 0 };
692 HcfResult res = cipher->getCipherSpecUint8Array(cipher, item, &blob);
693 if (res != HCF_SUCCESS) {
694 napi_throw(env, GenerateBusinessError(env, res, "c getCipherSpecUint8Array fail."));
695 LOGE("c getCipherSpecUint8Array fail.");
696 return nullptr;
697 }
698
699 napi_value instance = ConvertCipherBlobToNapiValue(env, &blob);
700 HcfBlobDataClearAndFree(&blob);
701 return instance;
702 }
703
JsGetCipherSpec(napi_env env,napi_callback_info info)704 napi_value NapiCipher::JsGetCipherSpec(napi_env env, napi_callback_info info)
705 {
706 napi_value thisVar = nullptr;
707 NapiCipher *napiCipher = nullptr;
708 size_t expectedArgc = ARGS_SIZE_ONE;
709 size_t argc = ARGS_SIZE_ONE;
710 napi_value argv[ARGS_SIZE_ONE] = { nullptr };
711 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
712 if (argc != expectedArgc) {
713 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "init failed for wrong argument num."));
714 LOGE("wrong argument num. require 1 arguments. [Argc]: %zu!", argc);
715 return nullptr;
716 }
717 CipherSpecItem item;
718 if (napi_get_value_uint32(env, argv[0], reinterpret_cast<uint32_t *>(&item)) != napi_ok) {
719 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "get getCipherSpecString failed!"));
720 LOGE("get getCipherSpecString failed!");
721 return nullptr;
722 }
723
724 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCipher));
725 if (status != napi_ok || napiCipher == nullptr) {
726 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to unwrap napiCipher obj!"));
727 LOGE("failed to unwrap napiCipher obj!");
728 return nullptr;
729 }
730 HcfCipher *cipher = napiCipher->GetCipher();
731 if (cipher == nullptr) {
732 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to get cipher obj!"));
733 LOGE("failed to get cipher obj!");
734 return nullptr;
735 }
736
737 int32_t type = GetCipherSpecType(item);
738 if (type == SPEC_ITEM_TYPE_STR) {
739 return GetCipherSpecString(env, item, cipher);
740 } else if (type == SPEC_ITEM_TYPE_UINT8ARR) {
741 return GetCipherSpecUint8Array(env, item, cipher);
742 } else {
743 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "CipherSpecItem not support!"));
744 return nullptr;
745 }
746 }
747
DefineCipherJSClass(napi_env env,napi_value exports)748 void NapiCipher::DefineCipherJSClass(napi_env env, napi_value exports)
749 {
750 napi_property_descriptor desc[] = {
751 DECLARE_NAPI_FUNCTION("createCipher", CreateCipher),
752 };
753 napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
754
755 napi_property_descriptor classDesc[] = {
756 DECLARE_NAPI_FUNCTION("init", NapiCipher::JsCipherInit),
757 DECLARE_NAPI_FUNCTION("update", NapiCipher::JsCipherUpdate),
758 DECLARE_NAPI_FUNCTION("doFinal", NapiCipher::JsCipherDoFinal),
759 DECLARE_NAPI_FUNCTION("setCipherSpec", NapiCipher::JsSetCipherSpec),
760 DECLARE_NAPI_FUNCTION("getCipherSpec", NapiCipher::JsGetCipherSpec),
761 { .utf8name = "algName", .getter = NapiCipher::JsGetAlgorithm },
762 };
763 napi_value constructor = nullptr;
764 napi_define_class(env, "Cipher", NAPI_AUTO_LENGTH, NapiCipher::CipherConstructor, nullptr,
765 sizeof(classDesc) / sizeof(classDesc[0]), classDesc, &constructor);
766 napi_create_reference(env, constructor, 1, &classRef_);
767 }
768 } // CryptoFramework
769 } // OHOS
770