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_mac.h"
17
18 #include "securec.h"
19 #include "log.h"
20 #include "memory.h"
21
22 #include "mac_params.h"
23 #include "detailed_hmac_params.h"
24 #include "detailed_cmac_params.h"
25 #include "napi_sym_key.h"
26 #include "napi_utils.h"
27 #include "napi_crypto_framework_defines.h"
28
29 namespace OHOS {
30 namespace CryptoFramework {
31 thread_local napi_ref NapiMac::classRef_ = nullptr;
32
33 struct MacCtx {
34 napi_env env = nullptr;
35
36 AsyncType asyncType = ASYNC_CALLBACK;
37 napi_ref callback = nullptr;
38 napi_deferred deferred = nullptr;
39 napi_value promise = nullptr;
40 napi_async_work asyncWork = nullptr;
41 napi_ref macRef = nullptr;
42 napi_ref symKeyRef = nullptr;
43
44 std::string algoName = "";
45 HcfSymKey *symKey = nullptr;
46 HcfBlob *inBlob = nullptr;
47
48 HcfResult errCode = HCF_SUCCESS;
49 const char *errMsg = nullptr;
50 HcfBlob *outBlob = nullptr;
51 HcfMac *mac = nullptr;
52 };
53
FreeCryptoFwkCtx(napi_env env,MacCtx * context)54 static void FreeCryptoFwkCtx(napi_env env, MacCtx *context)
55 {
56 if (context == nullptr) {
57 return;
58 }
59 if (context->asyncWork != nullptr) {
60 napi_delete_async_work(env, context->asyncWork);
61 context->asyncWork = nullptr;
62 }
63 if (context->callback != nullptr) {
64 napi_delete_reference(env, context->callback);
65 context->callback = nullptr;
66 }
67 if (context->macRef != nullptr) {
68 napi_delete_reference(env, context->macRef);
69 context->macRef = nullptr;
70 }
71 if (context->symKeyRef != nullptr) {
72 napi_delete_reference(env, context->symKeyRef);
73 context->symKeyRef = nullptr;
74 }
75 context->symKey = nullptr;
76 if (context->inBlob != nullptr) {
77 HcfFree(context->inBlob->data);
78 context->inBlob->data = nullptr;
79 context->inBlob->len = 0;
80 HcfFree(context->inBlob);
81 context->inBlob = nullptr;
82 }
83 if (context->outBlob != nullptr) {
84 HcfFree(context->outBlob->data);
85 context->outBlob->data = nullptr;
86 context->outBlob->len = 0;
87 HcfFree(context->outBlob);
88 context->outBlob = nullptr;
89 }
90 context->errMsg = nullptr;
91 context->mac = nullptr;
92 HcfFree(context);
93 }
94
FreeMacParams(HcfMacParamsSpec * params)95 static void FreeMacParams(HcfMacParamsSpec *params)
96 {
97 if (strcmp(params->algName, "HMAC") == 0) {
98 HcfFree(static_cast<void *>(const_cast<char *>(((HcfHmacParamsSpec *)params)->mdName)));
99 } else if (strcmp(params->algName, "CMAC") == 0) {
100 HcfFree(static_cast<void *>(const_cast<char *>(((HcfCmacParamsSpec *)params)->cipherName)));
101 }
102 HcfFree(params);
103 }
104
ReturnCallbackResult(napi_env env,MacCtx * context,napi_value result)105 static void ReturnCallbackResult(napi_env env, MacCtx *context, napi_value result)
106 {
107 napi_value businessError = nullptr;
108 if (context->errCode != HCF_SUCCESS) {
109 businessError = GenerateBusinessError(env, context->errCode, context->errMsg);
110 }
111 napi_value params[ARGS_SIZE_TWO] = { businessError, result };
112
113 napi_value func = nullptr;
114 napi_get_reference_value(env, context->callback, &func);
115
116 napi_value recv = nullptr;
117 napi_value callFuncRet = nullptr;
118 napi_get_undefined(env, &recv);
119 napi_call_function(env, recv, func, ARGS_SIZE_TWO, params, &callFuncRet);
120 }
121
ReturnPromiseResult(napi_env env,MacCtx * context,napi_value result)122 static void ReturnPromiseResult(napi_env env, MacCtx *context, napi_value result)
123 {
124 if (context->errCode == HCF_SUCCESS) {
125 napi_resolve_deferred(env, context->deferred, result);
126 } else {
127 napi_reject_deferred(env, context->deferred,
128 GenerateBusinessError(env, context->errCode, context->errMsg));
129 }
130 }
131
MacInitExecute(napi_env env,void * data)132 static void MacInitExecute(napi_env env, void *data)
133 {
134 MacCtx *context = static_cast<MacCtx *>(data);
135 HcfMac *macObj = context->mac;
136 HcfSymKey *symKey = context->symKey;
137 context->errCode = macObj->init(macObj, symKey);
138 if (context->errCode != HCF_SUCCESS) {
139 LOGD("[error] init failed!");
140 context->errMsg = "init failed";
141 }
142 }
143
MacInitComplete(napi_env env,napi_status status,void * data)144 static void MacInitComplete(napi_env env, napi_status status, void *data)
145 {
146 MacCtx *context = static_cast<MacCtx *>(data);
147 napi_value nullInstance = nullptr;
148 napi_get_null(env, &nullInstance);
149 if (context->asyncType == ASYNC_CALLBACK) {
150 ReturnCallbackResult(env, context, nullInstance);
151 } else {
152 ReturnPromiseResult(env, context, nullInstance);
153 }
154 FreeCryptoFwkCtx(env, context);
155 }
156
MacUpdateExecute(napi_env env,void * data)157 static void MacUpdateExecute(napi_env env, void *data)
158 {
159 MacCtx *context = static_cast<MacCtx *>(data);
160 HcfMac *macObj = context->mac;
161 HcfBlob *inBlob = reinterpret_cast<HcfBlob *>(context->inBlob);
162 context->errCode = macObj->update(macObj, inBlob);
163 if (context->errCode != HCF_SUCCESS) {
164 LOGD("[error] update failed!");
165 context->errMsg = "update failed";
166 }
167 }
168
MacUpdateComplete(napi_env env,napi_status status,void * data)169 static void MacUpdateComplete(napi_env env, napi_status status, void *data)
170 {
171 MacCtx *context = static_cast<MacCtx *>(data);
172 napi_value nullInstance = nullptr;
173 napi_get_null(env, &nullInstance);
174 if (context->asyncType == ASYNC_CALLBACK) {
175 ReturnCallbackResult(env, context, nullInstance);
176 } else {
177 ReturnPromiseResult(env, context, nullInstance);
178 }
179 FreeCryptoFwkCtx(env, context);
180 }
181
MacDoFinalExecute(napi_env env,void * data)182 static void MacDoFinalExecute(napi_env env, void *data)
183 {
184 MacCtx *context = static_cast<MacCtx *>(data);
185 HcfMac *macObj = context->mac;
186 HcfBlob *outBlob = reinterpret_cast<HcfBlob *>(HcfMalloc(sizeof(HcfBlob), 0));
187 if (outBlob == nullptr) {
188 LOGD("[error] outBlob is null!");
189 context->errCode = HCF_ERR_MALLOC;
190 context->errMsg = "malloc data blob failed";
191 return;
192 }
193 context->errCode = macObj->doFinal(macObj, outBlob);
194 if (context->errCode != HCF_SUCCESS) {
195 HcfFree(outBlob);
196 LOGE("doFinal failed!");
197 context->errMsg = "doFinal failed";
198 return;
199 }
200 context->outBlob = outBlob;
201 }
202
MacDoFinalComplete(napi_env env,napi_status status,void * data)203 static void MacDoFinalComplete(napi_env env, napi_status status, void *data)
204 {
205 MacCtx *context = static_cast<MacCtx *>(data);
206 napi_value returnOutBlob = ConvertBlobToNapiValue(env, context->outBlob);
207 if (returnOutBlob == nullptr) {
208 LOGE("returnOutBlob is nullptr!");
209 returnOutBlob = NapiGetNull(env);
210 }
211 if (context->asyncType == ASYNC_CALLBACK) {
212 ReturnCallbackResult(env, context, returnOutBlob);
213 } else {
214 ReturnPromiseResult(env, context, returnOutBlob);
215 }
216 FreeCryptoFwkCtx(env, context);
217 }
218
BuildMacJsInitCtx(napi_env env,napi_callback_info info,MacCtx * context)219 static bool BuildMacJsInitCtx(napi_env env, napi_callback_info info, MacCtx *context)
220 {
221 napi_value thisVar = nullptr;
222 NapiMac *napiMac = nullptr;
223 size_t expectedArgsCount = ARGS_SIZE_TWO;
224 size_t argc = expectedArgsCount;
225 napi_value argv[ARGS_SIZE_TWO] = { nullptr };
226 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
227 if (!CheckArgsCount(env, argc, ARGS_SIZE_TWO, false)) {
228 return false;
229 }
230
231 context->asyncType = isCallback(env, argv[expectedArgsCount - 1], argc, expectedArgsCount) ?
232 ASYNC_CALLBACK : ASYNC_PROMISE;
233 NapiSymKey *symKey = nullptr;
234 napi_status status = napi_unwrap(env, argv[PARAM0], reinterpret_cast<void **>(&symKey));
235 if (status != napi_ok || symKey == nullptr) {
236 LOGE("symKey is null!");
237 return false;
238 }
239 context->symKey = symKey->GetSymKey();
240 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiMac));
241 if (status != napi_ok || napiMac == nullptr) {
242 LOGE("failed to unwrap napiMac obj!");
243 return false;
244 }
245
246 context->mac = napiMac->GetMac();
247
248 if (napi_create_reference(env, thisVar, 1, &context->macRef) != napi_ok) {
249 LOGE("create mac ref failed when do mac init!");
250 return false;
251 }
252
253 if (napi_create_reference(env, argv[PARAM0], 1, &context->symKeyRef) != napi_ok) {
254 LOGE("create sym key ref failed when do mac init!");
255 return false;
256 }
257
258 if (context->asyncType == ASYNC_PROMISE) {
259 napi_create_promise(env, &context->deferred, &context->promise);
260 return true;
261 } else {
262 return GetCallbackFromJSParams(env, argv[PARAM1], &context->callback);
263 }
264 }
265
BuildMacJsUpdateCtx(napi_env env,napi_callback_info info,MacCtx * context)266 static bool BuildMacJsUpdateCtx(napi_env env, napi_callback_info info, MacCtx *context)
267 {
268 napi_value thisVar = nullptr;
269 NapiMac *napiMac = nullptr;
270 size_t expectedArgsCount = ARGS_SIZE_TWO;
271 size_t argc = expectedArgsCount;
272 napi_value argv[ARGS_SIZE_TWO] = { nullptr };
273 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
274 if (!CheckArgsCount(env, argc, ARGS_SIZE_TWO, false)) {
275 return false;
276 }
277
278 context->asyncType = isCallback(env, argv[expectedArgsCount - 1], argc, expectedArgsCount) ?
279 ASYNC_CALLBACK : ASYNC_PROMISE;
280 context->inBlob = GetBlobFromNapiDataBlob(env, argv[PARAM0]);
281 if (context->inBlob == nullptr) {
282 LOGE("inBlob is null!");
283 return false;
284 }
285 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiMac));
286 if (status != napi_ok || napiMac == nullptr) {
287 LOGE("failed to unwrap napiMac obj!");
288 return false;
289 }
290
291 context->mac = napiMac->GetMac();
292
293 if (napi_create_reference(env, thisVar, 1, &context->macRef) != napi_ok) {
294 LOGE("create mac ref failed when do mac update!");
295 return false;
296 }
297
298 if (context->asyncType == ASYNC_PROMISE) {
299 napi_create_promise(env, &context->deferred, &context->promise);
300 return true;
301 } else {
302 return GetCallbackFromJSParams(env, argv[PARAM1], &context->callback);
303 }
304 }
305
BuildMacJsDoFinalCtx(napi_env env,napi_callback_info info,MacCtx * context)306 static bool BuildMacJsDoFinalCtx(napi_env env, napi_callback_info info, MacCtx *context)
307 {
308 napi_value thisVar = nullptr;
309 NapiMac *napiMac = nullptr;
310 size_t expectedArgsCount = ARGS_SIZE_ONE;
311 size_t argc = expectedArgsCount;
312 napi_value argv[ARGS_SIZE_ONE] = { nullptr };
313 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
314 if (!CheckArgsCount(env, argc, ARGS_SIZE_ONE, false)) {
315 return false;
316 }
317
318 context->asyncType = isCallback(env, argv[expectedArgsCount - 1], argc, expectedArgsCount) ?
319 ASYNC_CALLBACK : ASYNC_PROMISE;
320 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiMac));
321 if (status != napi_ok || napiMac == nullptr) {
322 LOGE("failed to unwrap napiMac obj!");
323 return false;
324 }
325
326 context->mac = napiMac->GetMac();
327
328 if (napi_create_reference(env, thisVar, 1, &context->macRef) != napi_ok) {
329 LOGE("create mac ref failed when do mac final!");
330 return false;
331 }
332
333 if (context->asyncType == ASYNC_PROMISE) {
334 napi_create_promise(env, &context->deferred, &context->promise);
335 return true;
336 } else {
337 return GetCallbackFromJSParams(env, argv[PARAM0], &context->callback);
338 }
339 }
340
NewMacJsInitAsyncWork(napi_env env,MacCtx * context)341 static napi_value NewMacJsInitAsyncWork(napi_env env, MacCtx *context)
342 {
343 napi_create_async_work(
344 env, nullptr, GetResourceName(env, "MacInit"),
345 [](napi_env env, void *data) {
346 MacInitExecute(env, data);
347 return;
348 },
349 [](napi_env env, napi_status status, void *data) {
350 MacInitComplete(env, status, data);
351 return;
352 },
353 static_cast<void *>(context),
354 &context->asyncWork);
355
356 napi_queue_async_work(env, context->asyncWork);
357 if (context->asyncType == ASYNC_PROMISE) {
358 return context->promise;
359 } else {
360 return NapiGetNull(env);
361 }
362 }
363
NewMacJsUpdateAsyncWork(napi_env env,MacCtx * context)364 static napi_value NewMacJsUpdateAsyncWork(napi_env env, MacCtx *context)
365 {
366 napi_create_async_work(
367 env, nullptr, GetResourceName(env, "MacUpdate"),
368 [](napi_env env, void *data) {
369 MacUpdateExecute(env, data);
370 return;
371 },
372 [](napi_env env, napi_status status, void *data) {
373 MacUpdateComplete(env, status, data);
374 return;
375 },
376 static_cast<void *>(context),
377 &context->asyncWork);
378
379 napi_queue_async_work(env, context->asyncWork);
380 if (context->asyncType == ASYNC_PROMISE) {
381 return context->promise;
382 } else {
383 return NapiGetNull(env);
384 }
385 }
386
NewMacJsDoFinalAsyncWork(napi_env env,MacCtx * context)387 static napi_value NewMacJsDoFinalAsyncWork(napi_env env, MacCtx *context)
388 {
389 napi_create_async_work(
390 env, nullptr, GetResourceName(env, "MacDoFinal"),
391 [](napi_env env, void *data) {
392 MacDoFinalExecute(env, data);
393 return;
394 },
395 [](napi_env env, napi_status status, void *data) {
396 MacDoFinalComplete(env, status, data);
397 return;
398 },
399 static_cast<void *>(context),
400 &context->asyncWork);
401
402 napi_queue_async_work(env, context->asyncWork);
403 if (context->asyncType == ASYNC_PROMISE) {
404 return context->promise;
405 } else {
406 return NapiGetNull(env);
407 }
408 }
409
410
NapiMac(HcfMac * macObj)411 NapiMac::NapiMac(HcfMac *macObj)
412 {
413 this->macObj_ = macObj;
414 }
415
~NapiMac()416 NapiMac::~NapiMac()
417 {
418 HcfObjDestroy(this->macObj_);
419 }
420
GetMac()421 HcfMac *NapiMac::GetMac()
422 {
423 return this->macObj_;
424 }
425
JsMacInit(napi_env env,napi_callback_info info)426 napi_value NapiMac::JsMacInit(napi_env env, napi_callback_info info)
427 {
428 MacCtx *context = static_cast<MacCtx *>(HcfMalloc(sizeof(MacCtx), 0));
429 if (context == nullptr) {
430 napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "malloc context failed"));
431 LOGE("malloc context failed!");
432 return nullptr;
433 }
434
435 if (!BuildMacJsInitCtx(env, info, context)) {
436 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "build context fail."));
437 LOGE("build context fail.");
438 FreeCryptoFwkCtx(env, context);
439 return nullptr;
440 }
441
442 return NewMacJsInitAsyncWork(env, context);
443 }
444
JsMacInitSync(napi_env env,napi_callback_info info)445 napi_value NapiMac::JsMacInitSync(napi_env env, napi_callback_info info)
446 {
447 napi_value thisVar = nullptr;
448 NapiMac *napiMac = nullptr;
449 size_t argc = ARGS_SIZE_ONE;
450 napi_value argv[ARGS_SIZE_ONE] = { nullptr };
451 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
452 if (argc != ARGS_SIZE_ONE) {
453 LOGE("The input args num is invalid.");
454 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "The input args num is invalid."));
455 return nullptr;
456 }
457 NapiSymKey *napiSysKey = nullptr;
458 napi_status status = napi_unwrap(env, argv[PARAM0], reinterpret_cast<void **>(&napiSysKey));
459 if (status != napi_ok || napiSysKey == nullptr) {
460 LOGE("napiSysKey is null!");
461 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "napiSysKey is null!"));
462 return nullptr;
463 }
464 HcfSymKey *symKey = napiSysKey->GetSymKey();
465 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiMac));
466 if (status != napi_ok || napiMac == nullptr) {
467 LOGE("failed to unwrap napiMac obj!");
468 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to unwrap napiMac obj!"));
469 return nullptr;
470 }
471 HcfMac *mac = napiMac->GetMac();
472 if (mac == nullptr) {
473 LOGE("mac is nullptr!");
474 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "mac is nullptr!"));
475 return nullptr;
476 }
477 HcfResult errCode = mac->init(mac, symKey);
478 if (errCode != HCF_SUCCESS) {
479 LOGE("mac init failed!");
480 napi_throw(env, GenerateBusinessError(env, HCF_ERR_CRYPTO_OPERATION, "mac init failed!"));
481 return nullptr;
482 }
483 napi_value nullInstance = nullptr;
484 napi_get_null(env, &nullInstance);
485 return nullInstance;
486 }
487
JsMacUpdate(napi_env env,napi_callback_info info)488 napi_value NapiMac::JsMacUpdate(napi_env env, napi_callback_info info)
489 {
490 MacCtx *context = static_cast<MacCtx *>(HcfMalloc(sizeof(MacCtx), 0));
491 if (context == nullptr) {
492 napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "malloc context failed"));
493 LOGE("malloc context failed!");
494 return nullptr;
495 }
496
497 if (!BuildMacJsUpdateCtx(env, info, context)) {
498 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "build context fail."));
499 LOGE("build context fail.");
500 FreeCryptoFwkCtx(env, context);
501 return nullptr;
502 }
503
504 return NewMacJsUpdateAsyncWork(env, context);
505 }
506
JsMacUpdateSync(napi_env env,napi_callback_info info)507 napi_value NapiMac::JsMacUpdateSync(napi_env env, napi_callback_info info)
508 {
509 napi_value thisVar = nullptr;
510 NapiMac *napiMac = nullptr;
511 size_t argc = ARGS_SIZE_ONE;
512 napi_value argv[ARGS_SIZE_ONE] = { nullptr };
513 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
514 if (argc != ARGS_SIZE_ONE) {
515 LOGE("The input args num is invalid.");
516 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "The input args num is invalid."));
517 return nullptr;
518 }
519
520 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiMac));
521 if (status != napi_ok || napiMac == nullptr) {
522 LOGE("failed to unwrap napiMac obj!");
523 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to unwrap napiMac obj!"));
524 return nullptr;
525 }
526
527 HcfBlob *inBlob = GetBlobFromNapiDataBlob(env, argv[PARAM0]);
528 if (inBlob == nullptr) {
529 LOGE("inBlob is null!");
530 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "inBlob is null!"));
531 return nullptr;
532 }
533
534 HcfMac *mac = napiMac->GetMac();
535 if (mac == nullptr) {
536 LOGE("mac is nullptr!");
537 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "mac is nullptr!"));
538 HcfBlobDataClearAndFree(inBlob);
539 HcfFree(inBlob);
540 return nullptr;
541 }
542 HcfResult errCode = mac->update(mac, inBlob);
543 HcfBlobDataClearAndFree(inBlob);
544 HcfFree(inBlob);
545 if (errCode != HCF_SUCCESS) {
546 LOGE("mac update failed!");
547 napi_throw(env, GenerateBusinessError(env, HCF_ERR_CRYPTO_OPERATION, "mac update failed!"));
548 return nullptr;
549 }
550 napi_value nullInstance = nullptr;
551 napi_get_null(env, &nullInstance);
552 return nullInstance;
553 }
554
JsMacDoFinal(napi_env env,napi_callback_info info)555 napi_value NapiMac::JsMacDoFinal(napi_env env, napi_callback_info info)
556 {
557 MacCtx *context = static_cast<MacCtx *>(HcfMalloc(sizeof(MacCtx), 0));
558 if (context == nullptr) {
559 napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "malloc context failed"));
560 LOGE("malloc context failed!");
561 return nullptr;
562 }
563
564 if (!BuildMacJsDoFinalCtx(env, info, context)) {
565 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "build context fail."));
566 LOGE("build context fail.");
567 FreeCryptoFwkCtx(env, context);
568 return nullptr;
569 }
570
571 return NewMacJsDoFinalAsyncWork(env, context);
572 }
573
JsMacDoFinalSync(napi_env env,napi_callback_info info)574 napi_value NapiMac::JsMacDoFinalSync(napi_env env, napi_callback_info info)
575 {
576 napi_value thisVar = nullptr;
577 NapiMac *napiMac = nullptr;
578 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
579 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiMac));
580 if (status != napi_ok || napiMac == nullptr) {
581 LOGE("failed to unwrap napiMac obj!");
582 napi_throw(env, GenerateBusinessError(env, HCF_ERR_NAPI, "failed to unwrap napiMac obj."));
583 return nullptr;
584 }
585 HcfMac *mac = napiMac->GetMac();
586 if (mac == nullptr) {
587 LOGE("mac is nullptr!");
588 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "mac is nullptr!"));
589 return nullptr;
590 }
591 HcfBlob outBlob = { .data = nullptr, .len = 0 };
592 HcfResult errCode = mac->doFinal(mac, &outBlob);
593 if (errCode != HCF_SUCCESS) {
594 LOGE("mac doFinal failed!");
595 napi_throw(env, GenerateBusinessError(env, errCode, "mac doFinal failed!"));
596 HcfBlobDataClearAndFree(&outBlob);
597 return nullptr;
598 }
599
600 napi_value returnOutBlob = nullptr;
601 errCode = ConvertDataBlobToNapiValue(env, &outBlob, &returnOutBlob);
602 HcfBlobDataClearAndFree(&outBlob);
603 if (errCode != HCF_SUCCESS) {
604 LOGE("mac convert dataBlob to napi_value failed!");
605 napi_throw(env, GenerateBusinessError(env, errCode, "mac convert dataBlob to napi_value failed!"));
606 return nullptr;
607 }
608
609 return returnOutBlob;
610 }
611
JsGetMacLength(napi_env env,napi_callback_info info)612 napi_value NapiMac::JsGetMacLength(napi_env env, napi_callback_info info)
613 {
614 napi_value thisVar = nullptr;
615 NapiMac *napiMac = nullptr;
616
617 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
618 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiMac));
619 if (status != napi_ok || napiMac == nullptr) {
620 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to unwrap napiMac obj!"));
621 LOGE("failed to unwrap napiMac obj!");
622 return nullptr;
623 }
624
625 HcfMac *mac = napiMac->GetMac();
626 if (mac == nullptr) {
627 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "fail to get mac obj!"));
628 LOGE("fail to get mac obj!");
629 return nullptr;
630 }
631
632 uint32_t retLen = mac->getMacLength(mac);
633 napi_value napiLen = nullptr;
634 napi_create_uint32(env, retLen, &napiLen);
635 return napiLen;
636 }
637
MacConstructor(napi_env env,napi_callback_info info)638 napi_value NapiMac::MacConstructor(napi_env env, napi_callback_info info)
639 {
640 napi_value thisVar = nullptr;
641 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
642 return thisVar;
643 }
644
NapiWrapMac(napi_env env,napi_value instance,NapiMac * macNapiObj)645 static napi_value NapiWrapMac(napi_env env, napi_value instance, NapiMac *macNapiObj)
646 {
647 napi_status status = napi_wrap(
648 env, instance, macNapiObj,
649 [](napi_env env, void *data, void *hint) {
650 NapiMac *mac = static_cast<NapiMac *>(data);
651 delete mac;
652 return;
653 }, nullptr, nullptr);
654 if (status != napi_ok) {
655 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to wrap NapiMac obj!"));
656 delete macNapiObj;
657 LOGE("failed to wrap NapiMac obj!");
658 return nullptr;
659 }
660 return instance;
661 }
662
GetHmacParamsSpec(napi_env env,napi_value arg,const char * algName,HcfMacParamsSpec ** paramsSpec)663 static bool GetHmacParamsSpec(napi_env env, napi_value arg, const char *algName, HcfMacParamsSpec **paramsSpec)
664 {
665 napi_value data = nullptr;
666 napi_valuetype valueType = napi_undefined;
667 if ((env == nullptr) || (arg == nullptr) || (paramsSpec == nullptr)) {
668 LOGE("Invalid params!");
669 return false;
670 }
671
672 napi_status status = napi_get_named_property(env, arg, MD_NAME.c_str(), &data);
673 napi_typeof(env, data, &valueType);
674 if ((status != napi_ok) || (data == nullptr) || (valueType == napi_undefined)) {
675 LOGE("failed to get valid algo name!");
676 return false;
677 }
678 std::string mdName;
679 if (!GetStringFromJSParams(env, data, mdName)) {
680 LOGE("GetStringFromJSParams failed!");
681 return false;
682 }
683 HcfHmacParamsSpec *tmp = static_cast<HcfHmacParamsSpec *>(HcfMalloc(sizeof(HcfHmacParamsSpec), 0));
684 if (tmp == nullptr) {
685 LOGE("malloc hmac spec failed!");
686 return false;
687 }
688 char* mdNameCopy = static_cast<char*>(HcfMalloc(mdName.length() + 1, 0));
689 if (mdNameCopy == nullptr) {
690 LOGE("malloc mdName failed!");
691 HcfFree(tmp);
692 return false;
693 }
694 if (memcpy_s(mdNameCopy, mdName.length() + 1, mdName.c_str(), mdName.length() + 1) != EOK) {
695 LOGE("copy mdName failed!");
696 HcfFree(mdNameCopy);
697 HcfFree(tmp);
698 return false;
699 }
700 tmp->base.algName = algName;
701 tmp->mdName = mdNameCopy;
702 *paramsSpec = reinterpret_cast<HcfMacParamsSpec *>(tmp);
703 return true;
704 }
705
GetCmacParamsSpec(napi_env env,napi_value arg,const char * algName,HcfMacParamsSpec ** paramsSpec)706 static bool GetCmacParamsSpec(napi_env env, napi_value arg, const char *algName, HcfMacParamsSpec **paramsSpec)
707 {
708 napi_value data = nullptr;
709 napi_valuetype valueType = napi_undefined;
710 if ((env == nullptr) || (arg == nullptr) || (paramsSpec == nullptr)) {
711 LOGE("Invalid params!");
712 return false;
713 }
714
715 napi_status status = napi_get_named_property(env, arg, CIPHER_NAME.c_str(), &data);
716 napi_typeof(env, data, &valueType);
717 if ((status != napi_ok) || (data == nullptr) || (valueType == napi_undefined)) {
718 LOGE("failed to get valid algo name!");
719 return false;
720 }
721 std::string cipherName;
722 if (!GetStringFromJSParams(env, data, cipherName)) {
723 LOGE("GetStringFromJSParams failed!");
724 return false;
725 }
726 HcfCmacParamsSpec *tmp = nullptr;
727 tmp = static_cast<HcfCmacParamsSpec *>(HcfMalloc(sizeof(HcfCmacParamsSpec), 0));
728 if (tmp == nullptr) {
729 LOGE("malloc hmac spec failed!");
730 return false;
731 }
732 char* cipherNameCopy = static_cast<char*>(HcfMalloc(cipherName.length() + 1, 0));
733 if (cipherNameCopy == nullptr) {
734 LOGE("malloc cipherName failed!");
735 HcfFree(tmp);
736 return false;
737 }
738 if (memcpy_s(cipherNameCopy, cipherName.length() + 1, cipherName.c_str(), cipherName.length() + 1) != EOK) {
739 LOGE("copy cipherName failed!");
740 HcfFree(cipherNameCopy);
741 HcfFree(tmp);
742 return false;
743 }
744 tmp->base.algName = algName;
745 tmp->cipherName = cipherNameCopy;
746 *paramsSpec = reinterpret_cast<HcfMacParamsSpec *>(tmp);
747 return true;
748 }
749
GetMacSpecFromJSParams(napi_env env,napi_value arg,HcfMacParamsSpec ** params)750 static bool GetMacSpecFromJSParams(napi_env env, napi_value arg, HcfMacParamsSpec **params)
751 {
752 napi_value data = nullptr;
753 napi_valuetype valueType = napi_undefined;
754 if ((env == nullptr) || (arg == nullptr) || (params == nullptr)) {
755 LOGE("Invalid params!");
756 return false;
757 }
758
759 napi_status status = napi_get_named_property(env, arg, ALGO_PARAMS.c_str(), &data);
760 napi_typeof(env, data, &valueType);
761 if ((status != napi_ok) || (data == nullptr) || (valueType == napi_undefined)) {
762 LOGE("failed to get valid algo name!");
763 return false;
764 }
765 std::string algoName;
766 if (!GetStringFromJSParams(env, data, algoName)) {
767 LOGE("GetStringFromJSParams failed!");
768 return false;
769 }
770 if (algoName.compare("HMAC") == 0) {
771 return GetHmacParamsSpec(env, arg, algoName.c_str(), params);
772 } else if (algoName.compare("CMAC") == 0) {
773 return GetCmacParamsSpec(env, arg, algoName.c_str(), params);
774 } else {
775 LOGE("Not support that alg");
776 return false;
777 }
778 return true;
779 }
780
GetStringMacParams(napi_env env,napi_value argv,HcfMacParamsSpec ** paramsSpec)781 static bool GetStringMacParams(napi_env env, napi_value argv, HcfMacParamsSpec **paramsSpec)
782 {
783 if ((env == nullptr) || (paramsSpec == nullptr)) {
784 LOGE("Invalid params!");
785 return false;
786 }
787 std::string algoName;
788 if (!GetStringFromJSParams(env, argv, algoName)) {
789 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "Failed to get algorithm."));
790 LOGE("Failed to get algorithm.");
791 return false;
792 }
793 *paramsSpec = reinterpret_cast<HcfMacParamsSpec *>(HcfMalloc(sizeof(HcfHmacParamsSpec), 0));
794 if (*paramsSpec == nullptr) {
795 napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "Failed to allocate memory."));
796 LOGE("Failed to allocate memory.");
797 return false;
798 }
799 char* mdNameCopy = static_cast<char*>(HcfMalloc(algoName.length() + 1, 0));
800 if (mdNameCopy == nullptr) {
801 LOGE("malloc mdName failed!");
802 return false;
803 }
804 if (memcpy_s(mdNameCopy, algoName.length() + 1, algoName.c_str(), algoName.length() + 1) != EOK) {
805 LOGE("copy mdName failed!");
806 HcfFree(mdNameCopy);
807 return false;
808 }
809 (reinterpret_cast<HcfHmacParamsSpec *>(*paramsSpec))->base.algName = "HMAC";
810 (reinterpret_cast<HcfHmacParamsSpec *>(*paramsSpec))->mdName = mdNameCopy;
811 return true;
812 }
813
SetparamsSpec(napi_env env,napi_value argv,HcfMacParamsSpec ** paramsSpec)814 static bool SetparamsSpec(napi_env env, napi_value argv, HcfMacParamsSpec **paramsSpec)
815 {
816 napi_valuetype valueType;
817 napi_typeof(env, argv, &valueType);
818 if (valueType == napi_string) {
819 if (!GetStringMacParams(env, argv, paramsSpec)) {
820 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "Failed to get mac params."));
821 LOGE("Failed to get mac params.");
822 return false;
823 }
824 } else {
825 if (!GetMacSpecFromJSParams(env, argv, paramsSpec)) {
826 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "Failed to get mac params."));
827 LOGE("Failed to get mac params.");
828 return false;
829 }
830 }
831 return true;
832 }
833
CreateMac(napi_env env,napi_callback_info info)834 napi_value NapiMac::CreateMac(napi_env env, napi_callback_info info)
835 {
836 size_t expectedArgc = ARGS_SIZE_ONE;
837 size_t argc = expectedArgc;
838 napi_value argv[ARGS_SIZE_ONE] = { nullptr };
839 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
840 if (argc != expectedArgc) {
841 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "The input args num is invalid."));
842 LOGE("The input args num is invalid.");
843 return nullptr;
844 }
845
846 HcfMacParamsSpec *paramsSpec = nullptr;
847 if (!SetparamsSpec(env, argv[PARAM0], ¶msSpec)) {
848 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "Failed to set mac params."));
849 LOGE("Failed to set mac params.");
850 return nullptr;
851 }
852
853 HcfMac *macObj = nullptr;
854 HcfResult res = HcfMacCreate(paramsSpec, &macObj);
855 if (res != HCF_SUCCESS) {
856 napi_throw(env, GenerateBusinessError(env, res, "create C obj failed."));
857 LOGE("create c macObj failed.");
858 FreeMacParams(paramsSpec);
859 return nullptr;
860 }
861 napi_value napiAlgName = nullptr;
862 napi_create_string_utf8(env, paramsSpec->algName, NAPI_AUTO_LENGTH, &napiAlgName);
863 FreeMacParams(paramsSpec);
864 napi_value instance = nullptr;
865 napi_value constructor = nullptr;
866 napi_get_reference_value(env, classRef_, &constructor);
867 napi_new_instance(env, constructor, argc, argv, &instance);
868 napi_set_named_property(env, instance, CRYPTO_TAG_ALG_NAME.c_str(), napiAlgName);
869 NapiMac *macNapiObj = new (std::nothrow) NapiMac(macObj);
870 if (macNapiObj == nullptr) {
871 napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "new mac napi obj failed."));
872 HcfObjDestroy(macObj);
873 LOGE("create napi obj failed");
874 return nullptr;
875 }
876
877 return NapiWrapMac(env, instance, macNapiObj);
878 }
879
DefineMacJSClass(napi_env env,napi_value exports)880 void NapiMac::DefineMacJSClass(napi_env env, napi_value exports)
881 {
882 napi_property_descriptor desc[] = {
883 DECLARE_NAPI_FUNCTION("createMac", NapiMac::CreateMac),
884 };
885 napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
886 napi_property_descriptor classDesc[] = {
887 DECLARE_NAPI_FUNCTION("init", NapiMac::JsMacInit),
888 DECLARE_NAPI_FUNCTION("initSync", NapiMac::JsMacInitSync),
889 DECLARE_NAPI_FUNCTION("update", NapiMac::JsMacUpdate),
890 DECLARE_NAPI_FUNCTION("updateSync", NapiMac::JsMacUpdateSync),
891 DECLARE_NAPI_FUNCTION("doFinal", NapiMac::JsMacDoFinal),
892 DECLARE_NAPI_FUNCTION("doFinalSync", NapiMac::JsMacDoFinalSync),
893 DECLARE_NAPI_FUNCTION("getMacLength", NapiMac::JsGetMacLength),
894 };
895 napi_value constructor = nullptr;
896 napi_define_class(env, "Mac", NAPI_AUTO_LENGTH, MacConstructor, nullptr,
897 sizeof(classDesc) / sizeof(classDesc[0]), classDesc, &constructor);
898 napi_create_reference(env, constructor, 1, &classRef_);
899 }
900 } // CryptoFramework
901 } // OHOS