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 "napi_sym_key.h"
23 #include "napi_utils.h"
24 #include "napi_crypto_framework_defines.h"
25 
26 namespace OHOS {
27 namespace CryptoFramework {
28 thread_local napi_ref NapiMac::classRef_ = nullptr;
29 
30 struct MacCtx {
31     napi_env env = nullptr;
32 
33     AsyncType asyncType = ASYNC_CALLBACK;
34     napi_ref callback = nullptr;
35     napi_deferred deferred = nullptr;
36     napi_value promise = nullptr;
37     napi_async_work asyncWork = nullptr;
38     napi_ref macRef = nullptr;
39     napi_ref symKeyRef = nullptr;
40 
41     std::string algoName = "";
42     HcfSymKey *symKey = nullptr;
43     HcfBlob *inBlob = nullptr;
44 
45     HcfResult errCode = HCF_SUCCESS;
46     const char *errMsg = nullptr;
47     HcfBlob *outBlob = nullptr;
48     HcfMac *mac = nullptr;
49 };
50 
FreeCryptoFwkCtx(napi_env env,MacCtx * context)51 static void FreeCryptoFwkCtx(napi_env env, MacCtx *context)
52 {
53     if (context == nullptr) {
54         return;
55     }
56     if (context->asyncWork != nullptr) {
57         napi_delete_async_work(env, context->asyncWork);
58         context->asyncWork = nullptr;
59     }
60     if (context->callback != nullptr) {
61         napi_delete_reference(env, context->callback);
62         context->callback = nullptr;
63     }
64     if (context->macRef != nullptr) {
65         napi_delete_reference(env, context->macRef);
66         context->macRef = nullptr;
67     }
68     if (context->symKeyRef != nullptr) {
69         napi_delete_reference(env, context->symKeyRef);
70         context->symKeyRef = nullptr;
71     }
72     context->symKey = nullptr;
73     if (context->inBlob != nullptr) {
74         HcfFree(context->inBlob->data);
75         context->inBlob->data = nullptr;
76         context->inBlob->len = 0;
77         HcfFree(context->inBlob);
78         context->inBlob = nullptr;
79     }
80     if (context->outBlob != nullptr) {
81         HcfFree(context->outBlob->data);
82         context->outBlob->data = nullptr;
83         context->outBlob->len = 0;
84         HcfFree(context->outBlob);
85         context->outBlob = nullptr;
86     }
87     context->errMsg = nullptr;
88     context->mac = nullptr;
89     HcfFree(context);
90 }
91 
ReturnCallbackResult(napi_env env,MacCtx * context,napi_value result)92 static void ReturnCallbackResult(napi_env env, MacCtx *context, napi_value result)
93 {
94     napi_value businessError = nullptr;
95     if (context->errCode != HCF_SUCCESS) {
96         businessError = GenerateBusinessError(env, context->errCode, context->errMsg);
97     }
98     napi_value params[ARGS_SIZE_TWO] = { businessError, result };
99 
100     napi_value func = nullptr;
101     napi_get_reference_value(env, context->callback, &func);
102 
103     napi_value recv = nullptr;
104     napi_value callFuncRet = nullptr;
105     napi_get_undefined(env, &recv);
106     napi_call_function(env, recv, func, ARGS_SIZE_TWO, params, &callFuncRet);
107 }
108 
ReturnPromiseResult(napi_env env,MacCtx * context,napi_value result)109 static void ReturnPromiseResult(napi_env env, MacCtx *context, napi_value result)
110 {
111     if (context->errCode == HCF_SUCCESS) {
112         napi_resolve_deferred(env, context->deferred, result);
113     } else {
114         napi_reject_deferred(env, context->deferred,
115             GenerateBusinessError(env, context->errCode, context->errMsg));
116     }
117 }
118 
MacInitExecute(napi_env env,void * data)119 static void MacInitExecute(napi_env env, void *data)
120 {
121     MacCtx *context = static_cast<MacCtx *>(data);
122     HcfMac *macObj = context->mac;
123     HcfSymKey *symKey = context->symKey;
124     context->errCode = macObj->init(macObj, symKey);
125     if (context->errCode != HCF_SUCCESS) {
126         LOGD("[error] init failed!");
127         context->errMsg = "init failed";
128     }
129 }
130 
MacInitComplete(napi_env env,napi_status status,void * data)131 static void MacInitComplete(napi_env env, napi_status status, void *data)
132 {
133     MacCtx *context = static_cast<MacCtx *>(data);
134     napi_value nullInstance = nullptr;
135     napi_get_null(env, &nullInstance);
136     if (context->asyncType == ASYNC_CALLBACK) {
137         ReturnCallbackResult(env, context, nullInstance);
138     } else {
139         ReturnPromiseResult(env, context, nullInstance);
140     }
141     FreeCryptoFwkCtx(env, context);
142 }
143 
MacUpdateExecute(napi_env env,void * data)144 static void MacUpdateExecute(napi_env env, void *data)
145 {
146     MacCtx *context = static_cast<MacCtx *>(data);
147     HcfMac *macObj = context->mac;
148     HcfBlob *inBlob = reinterpret_cast<HcfBlob *>(context->inBlob);
149     context->errCode = macObj->update(macObj, inBlob);
150     if (context->errCode != HCF_SUCCESS) {
151         LOGD("[error] update failed!");
152         context->errMsg = "update failed";
153     }
154 }
155 
MacUpdateComplete(napi_env env,napi_status status,void * data)156 static void MacUpdateComplete(napi_env env, napi_status status, void *data)
157 {
158     MacCtx *context = static_cast<MacCtx *>(data);
159     napi_value nullInstance = nullptr;
160     napi_get_null(env, &nullInstance);
161     if (context->asyncType == ASYNC_CALLBACK) {
162         ReturnCallbackResult(env, context, nullInstance);
163     } else {
164         ReturnPromiseResult(env, context, nullInstance);
165     }
166     FreeCryptoFwkCtx(env, context);
167 }
168 
MacDoFinalExecute(napi_env env,void * data)169 static void MacDoFinalExecute(napi_env env, void *data)
170 {
171     MacCtx *context = static_cast<MacCtx *>(data);
172     HcfMac *macObj = context->mac;
173     HcfBlob *outBlob = reinterpret_cast<HcfBlob *>(HcfMalloc(sizeof(HcfBlob), 0));
174     if (outBlob == nullptr) {
175         LOGD("[error] outBlob is null!");
176         context->errCode = HCF_ERR_MALLOC;
177         context->errMsg = "malloc data blob failed";
178         return;
179     }
180     context->errCode = macObj->doFinal(macObj, outBlob);
181     if (context->errCode != HCF_SUCCESS) {
182         HcfFree(outBlob);
183         LOGE("doFinal failed!");
184         context->errMsg = "doFinal failed";
185         return;
186     }
187     context->outBlob = outBlob;
188 }
189 
MacDoFinalComplete(napi_env env,napi_status status,void * data)190 static void MacDoFinalComplete(napi_env env, napi_status status, void *data)
191 {
192     MacCtx *context = static_cast<MacCtx *>(data);
193     napi_value returnOutBlob = ConvertBlobToNapiValue(env, context->outBlob);
194     if (returnOutBlob == nullptr) {
195         LOGE("returnOutBlob is nullptr!");
196         returnOutBlob = NapiGetNull(env);
197     }
198     if (context->asyncType == ASYNC_CALLBACK) {
199         ReturnCallbackResult(env, context, returnOutBlob);
200     } else {
201         ReturnPromiseResult(env, context, returnOutBlob);
202     }
203     FreeCryptoFwkCtx(env, context);
204 }
205 
BuildMacJsInitCtx(napi_env env,napi_callback_info info,MacCtx * context)206 static bool BuildMacJsInitCtx(napi_env env, napi_callback_info info, MacCtx *context)
207 {
208     napi_value thisVar = nullptr;
209     NapiMac *napiMac = nullptr;
210     size_t expectedArgsCount = ARGS_SIZE_TWO;
211     size_t argc = expectedArgsCount;
212     napi_value argv[ARGS_SIZE_TWO] = { nullptr };
213     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
214     if (!CheckArgsCount(env, argc, ARGS_SIZE_TWO, false)) {
215         return false;
216     }
217 
218     context->asyncType = isCallback(env, argv[expectedArgsCount - 1], argc, expectedArgsCount) ?
219         ASYNC_CALLBACK : ASYNC_PROMISE;
220     NapiSymKey *symKey = nullptr;
221     napi_status status = napi_unwrap(env, argv[PARAM0], reinterpret_cast<void **>(&symKey));
222     if (status != napi_ok || symKey == nullptr) {
223         LOGE("symKey is null!");
224         return false;
225     }
226     context->symKey = symKey->GetSymKey();
227     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiMac));
228     if (status != napi_ok || napiMac == nullptr) {
229         LOGE("failed to unwrap napiMac obj!");
230         return false;
231     }
232 
233     context->mac = napiMac->GetMac();
234 
235     if (napi_create_reference(env, thisVar, 1, &context->macRef) != napi_ok) {
236         LOGE("create mac ref failed when do mac init!");
237         return false;
238     }
239 
240     if (napi_create_reference(env, argv[PARAM0], 1, &context->symKeyRef) != napi_ok) {
241         LOGE("create sym key ref failed when do mac init!");
242         return false;
243     }
244 
245     if (context->asyncType == ASYNC_PROMISE) {
246         napi_create_promise(env, &context->deferred, &context->promise);
247         return true;
248     } else {
249         return GetCallbackFromJSParams(env, argv[PARAM1], &context->callback);
250     }
251 }
252 
BuildMacJsUpdateCtx(napi_env env,napi_callback_info info,MacCtx * context)253 static bool BuildMacJsUpdateCtx(napi_env env, napi_callback_info info, MacCtx *context)
254 {
255     napi_value thisVar = nullptr;
256     NapiMac *napiMac = nullptr;
257     size_t expectedArgsCount = ARGS_SIZE_TWO;
258     size_t argc = expectedArgsCount;
259     napi_value argv[ARGS_SIZE_TWO] = { nullptr };
260     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
261     if (!CheckArgsCount(env, argc, ARGS_SIZE_TWO, false)) {
262         return false;
263     }
264 
265     context->asyncType = isCallback(env, argv[expectedArgsCount - 1], argc, expectedArgsCount) ?
266         ASYNC_CALLBACK : ASYNC_PROMISE;
267     context->inBlob = GetBlobFromNapiDataBlob(env, argv[PARAM0]);
268     if (context->inBlob == nullptr) {
269         LOGE("inBlob is null!");
270         return false;
271     }
272     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiMac));
273     if (status != napi_ok || napiMac == nullptr) {
274         LOGE("failed to unwrap napiMac obj!");
275         return false;
276     }
277 
278     context->mac = napiMac->GetMac();
279 
280     if (napi_create_reference(env, thisVar, 1, &context->macRef) != napi_ok) {
281         LOGE("create mac ref failed when do mac update!");
282         return false;
283     }
284 
285     if (context->asyncType == ASYNC_PROMISE) {
286         napi_create_promise(env, &context->deferred, &context->promise);
287         return true;
288     } else {
289         return GetCallbackFromJSParams(env, argv[PARAM1], &context->callback);
290     }
291 }
292 
BuildMacJsDoFinalCtx(napi_env env,napi_callback_info info,MacCtx * context)293 static bool BuildMacJsDoFinalCtx(napi_env env, napi_callback_info info, MacCtx *context)
294 {
295     napi_value thisVar = nullptr;
296     NapiMac *napiMac = nullptr;
297     size_t expectedArgsCount = ARGS_SIZE_ONE;
298     size_t argc = expectedArgsCount;
299     napi_value argv[ARGS_SIZE_ONE] = { nullptr };
300     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
301     if (!CheckArgsCount(env, argc, ARGS_SIZE_ONE, false)) {
302         return false;
303     }
304 
305     context->asyncType = isCallback(env, argv[expectedArgsCount - 1], argc, expectedArgsCount) ?
306         ASYNC_CALLBACK : ASYNC_PROMISE;
307     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiMac));
308     if (status != napi_ok || napiMac == nullptr) {
309         LOGE("failed to unwrap napiMac obj!");
310         return false;
311     }
312 
313     context->mac = napiMac->GetMac();
314 
315     if (napi_create_reference(env, thisVar, 1, &context->macRef) != napi_ok) {
316         LOGE("create mac ref failed when do mac final!");
317         return false;
318     }
319 
320     if (context->asyncType == ASYNC_PROMISE) {
321         napi_create_promise(env, &context->deferred, &context->promise);
322         return true;
323     } else {
324         return GetCallbackFromJSParams(env, argv[PARAM0], &context->callback);
325     }
326 }
327 
NewMacJsInitAsyncWork(napi_env env,MacCtx * context)328 static napi_value NewMacJsInitAsyncWork(napi_env env, MacCtx *context)
329 {
330     napi_create_async_work(
331         env, nullptr, GetResourceName(env, "MacInit"),
332         [](napi_env env, void *data) {
333             MacInitExecute(env, data);
334             return;
335         },
336         [](napi_env env, napi_status status, void *data) {
337             MacInitComplete(env, status, data);
338             return;
339         },
340         static_cast<void *>(context),
341         &context->asyncWork);
342 
343     napi_queue_async_work(env, context->asyncWork);
344     if (context->asyncType == ASYNC_PROMISE) {
345         return context->promise;
346     } else {
347         return NapiGetNull(env);
348     }
349 }
350 
NewMacJsUpdateAsyncWork(napi_env env,MacCtx * context)351 static napi_value NewMacJsUpdateAsyncWork(napi_env env, MacCtx *context)
352 {
353     napi_create_async_work(
354         env, nullptr, GetResourceName(env, "MacUpdate"),
355         [](napi_env env, void *data) {
356             MacUpdateExecute(env, data);
357             return;
358         },
359         [](napi_env env, napi_status status, void *data) {
360             MacUpdateComplete(env, status, data);
361             return;
362         },
363         static_cast<void *>(context),
364         &context->asyncWork);
365 
366     napi_queue_async_work(env, context->asyncWork);
367     if (context->asyncType == ASYNC_PROMISE) {
368         return context->promise;
369     } else {
370         return NapiGetNull(env);
371     }
372 }
373 
NewMacJsDoFinalAsyncWork(napi_env env,MacCtx * context)374 static napi_value NewMacJsDoFinalAsyncWork(napi_env env, MacCtx *context)
375 {
376     napi_create_async_work(
377         env, nullptr, GetResourceName(env, "MacDoFinal"),
378         [](napi_env env, void *data) {
379             MacDoFinalExecute(env, data);
380             return;
381         },
382         [](napi_env env, napi_status status, void *data) {
383             MacDoFinalComplete(env, status, data);
384             return;
385         },
386         static_cast<void *>(context),
387         &context->asyncWork);
388 
389     napi_queue_async_work(env, context->asyncWork);
390     if (context->asyncType == ASYNC_PROMISE) {
391         return context->promise;
392     } else {
393         return NapiGetNull(env);
394     }
395 }
396 
397 
NapiMac(HcfMac * macObj)398 NapiMac::NapiMac(HcfMac *macObj)
399 {
400     this->macObj_ = macObj;
401 }
402 
~NapiMac()403 NapiMac::~NapiMac()
404 {
405     HcfObjDestroy(this->macObj_);
406 }
407 
GetMac()408 HcfMac *NapiMac::GetMac()
409 {
410     return this->macObj_;
411 }
412 
JsMacInit(napi_env env,napi_callback_info info)413 napi_value NapiMac::JsMacInit(napi_env env, napi_callback_info info)
414 {
415     MacCtx *context = static_cast<MacCtx *>(HcfMalloc(sizeof(MacCtx), 0));
416     if (context == nullptr) {
417         napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "malloc context failed"));
418         LOGE("malloc context failed!");
419         return nullptr;
420     }
421 
422     if (!BuildMacJsInitCtx(env, info, context)) {
423         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "build context fail."));
424         LOGE("build context fail.");
425         FreeCryptoFwkCtx(env, context);
426         return nullptr;
427     }
428 
429     return NewMacJsInitAsyncWork(env, context);
430 }
431 
JsMacInitSync(napi_env env,napi_callback_info info)432 napi_value NapiMac::JsMacInitSync(napi_env env, napi_callback_info info)
433 {
434     napi_value thisVar = nullptr;
435     NapiMac *napiMac = nullptr;
436     size_t argc = ARGS_SIZE_ONE;
437     napi_value argv[ARGS_SIZE_ONE] = { nullptr };
438     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
439     if (argc != ARGS_SIZE_ONE) {
440         LOGE("The input args num is invalid.");
441         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "The input args num is invalid."));
442         return nullptr;
443     }
444     NapiSymKey *napiSysKey = nullptr;
445     napi_status status = napi_unwrap(env, argv[PARAM0], reinterpret_cast<void **>(&napiSysKey));
446     if (status != napi_ok || napiSysKey == nullptr) {
447         LOGE("napiSysKey is null!");
448         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "napiSysKey is null!"));
449         return nullptr;
450     }
451     HcfSymKey *symKey = napiSysKey->GetSymKey();
452     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiMac));
453     if (status != napi_ok || napiMac == nullptr) {
454         LOGE("failed to unwrap napiMac obj!");
455         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to unwrap napiMac obj!"));
456         return nullptr;
457     }
458     HcfMac *mac = napiMac->GetMac();
459     if (mac == nullptr) {
460         LOGE("mac is nullptr!");
461         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "mac is nullptr!"));
462         return nullptr;
463     }
464     HcfResult errCode = mac->init(mac, symKey);
465     if (errCode != HCF_SUCCESS) {
466         LOGE("mac init failed!");
467         napi_throw(env, GenerateBusinessError(env, HCF_ERR_CRYPTO_OPERATION, "mac init failed!"));
468         return nullptr;
469     }
470     napi_value nullInstance = nullptr;
471     napi_get_null(env, &nullInstance);
472     return nullInstance;
473 }
474 
JsMacUpdate(napi_env env,napi_callback_info info)475 napi_value NapiMac::JsMacUpdate(napi_env env, napi_callback_info info)
476 {
477     MacCtx *context = static_cast<MacCtx *>(HcfMalloc(sizeof(MacCtx), 0));
478     if (context == nullptr) {
479         napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "malloc context failed"));
480         LOGE("malloc context failed!");
481         return nullptr;
482     }
483 
484     if (!BuildMacJsUpdateCtx(env, info, context)) {
485         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "build context fail."));
486         LOGE("build context fail.");
487         FreeCryptoFwkCtx(env, context);
488         return nullptr;
489     }
490 
491     return NewMacJsUpdateAsyncWork(env, context);
492 }
493 
JsMacUpdateSync(napi_env env,napi_callback_info info)494 napi_value NapiMac::JsMacUpdateSync(napi_env env, napi_callback_info info)
495 {
496     napi_value thisVar = nullptr;
497     NapiMac *napiMac = nullptr;
498     size_t argc = ARGS_SIZE_ONE;
499     napi_value argv[ARGS_SIZE_ONE] = { nullptr };
500     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
501     if (argc != ARGS_SIZE_ONE) {
502         LOGE("The input args num is invalid.");
503         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "The input args num is invalid."));
504         return nullptr;
505     }
506 
507     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiMac));
508     if (status != napi_ok || napiMac == nullptr) {
509         LOGE("failed to unwrap napiMac obj!");
510         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to unwrap napiMac obj!"));
511         return nullptr;
512     }
513 
514     HcfBlob *inBlob = GetBlobFromNapiDataBlob(env, argv[PARAM0]);
515     if (inBlob == nullptr) {
516         LOGE("inBlob is null!");
517         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "inBlob is null!"));
518         return nullptr;
519     }
520 
521     HcfMac *mac = napiMac->GetMac();
522     if (mac == nullptr) {
523         LOGE("mac is nullptr!");
524         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "mac is nullptr!"));
525         HcfBlobDataClearAndFree(inBlob);
526         HcfFree(inBlob);
527         return nullptr;
528     }
529     HcfResult errCode = mac->update(mac, inBlob);
530     HcfBlobDataClearAndFree(inBlob);
531     HcfFree(inBlob);
532     if (errCode != HCF_SUCCESS) {
533         LOGE("mac update failed!");
534         napi_throw(env, GenerateBusinessError(env, HCF_ERR_CRYPTO_OPERATION, "mac update failed!"));
535         return nullptr;
536     }
537     napi_value nullInstance = nullptr;
538     napi_get_null(env, &nullInstance);
539     return nullInstance;
540 }
541 
JsMacDoFinal(napi_env env,napi_callback_info info)542 napi_value NapiMac::JsMacDoFinal(napi_env env, napi_callback_info info)
543 {
544     MacCtx *context = static_cast<MacCtx *>(HcfMalloc(sizeof(MacCtx), 0));
545     if (context == nullptr) {
546         napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "malloc context failed"));
547         LOGE("malloc context failed!");
548         return nullptr;
549     }
550 
551     if (!BuildMacJsDoFinalCtx(env, info, context)) {
552         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "build context fail."));
553         LOGE("build context fail.");
554         FreeCryptoFwkCtx(env, context);
555         return nullptr;
556     }
557 
558     return NewMacJsDoFinalAsyncWork(env, context);
559 }
560 
JsMacDoFinalSync(napi_env env,napi_callback_info info)561 napi_value NapiMac::JsMacDoFinalSync(napi_env env, napi_callback_info info)
562 {
563     napi_value thisVar = nullptr;
564     NapiMac *napiMac = nullptr;
565     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
566     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiMac));
567     if (status != napi_ok || napiMac == nullptr) {
568         LOGE("failed to unwrap napiMac obj!");
569         napi_throw(env, GenerateBusinessError(env, HCF_ERR_NAPI, "failed to unwrap napiMac obj."));
570         return nullptr;
571     }
572     HcfMac *mac = napiMac->GetMac();
573     if (mac == nullptr) {
574         LOGE("mac is nullptr!");
575         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "mac is nullptr!"));
576         return nullptr;
577     }
578     HcfBlob outBlob = { .data = nullptr, .len = 0 };
579     HcfResult errCode = mac->doFinal(mac, &outBlob);
580     if (errCode != HCF_SUCCESS) {
581         LOGE("mac doFinal failed!");
582         napi_throw(env, GenerateBusinessError(env, errCode, "mac doFinal failed!"));
583         HcfBlobDataClearAndFree(&outBlob);
584         return nullptr;
585     }
586 
587     napi_value returnOutBlob = nullptr;
588     errCode = ConvertDataBlobToNapiValue(env, &outBlob, &returnOutBlob);
589     HcfBlobDataClearAndFree(&outBlob);
590     if (errCode != HCF_SUCCESS) {
591         LOGE("mac convert dataBlob to napi_value failed!");
592         napi_throw(env, GenerateBusinessError(env, errCode, "mac convert dataBlob to napi_value failed!"));
593         return nullptr;
594     }
595 
596     return returnOutBlob;
597 }
598 
JsGetMacLength(napi_env env,napi_callback_info info)599 napi_value NapiMac::JsGetMacLength(napi_env env, napi_callback_info info)
600 {
601     napi_value thisVar = nullptr;
602     NapiMac *napiMac = nullptr;
603 
604     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
605     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiMac));
606     if (status != napi_ok || napiMac == nullptr) {
607         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to unwrap napiMac obj!"));
608         LOGE("failed to unwrap napiMac obj!");
609         return nullptr;
610     }
611 
612     HcfMac *mac = napiMac->GetMac();
613     if (mac == nullptr) {
614         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "fail to get mac obj!"));
615         LOGE("fail to get mac obj!");
616         return nullptr;
617     }
618 
619     uint32_t retLen = mac->getMacLength(mac);
620     napi_value napiLen = nullptr;
621     napi_create_uint32(env, retLen, &napiLen);
622     return napiLen;
623 }
624 
MacConstructor(napi_env env,napi_callback_info info)625 napi_value NapiMac::MacConstructor(napi_env env, napi_callback_info info)
626 {
627     napi_value thisVar = nullptr;
628     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
629     return thisVar;
630 }
631 
NapiWrapMac(napi_env env,napi_value instance,NapiMac * macNapiObj)632 static napi_value NapiWrapMac(napi_env env, napi_value instance, NapiMac *macNapiObj)
633 {
634     napi_status status = napi_wrap(
635         env, instance, macNapiObj,
636         [](napi_env env, void *data, void *hint) {
637             NapiMac *mac = static_cast<NapiMac *>(data);
638             delete mac;
639             return;
640         }, nullptr, nullptr);
641     if (status != napi_ok) {
642         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to wrap NapiMac obj!"));
643         delete macNapiObj;
644         LOGE("failed to wrap NapiMac obj!");
645         return nullptr;
646     }
647     return instance;
648 }
649 
CreateMac(napi_env env,napi_callback_info info)650 napi_value NapiMac::CreateMac(napi_env env, napi_callback_info info)
651 {
652     size_t expectedArgc = ARGS_SIZE_ONE;
653     size_t argc = expectedArgc;
654     napi_value argv[ARGS_SIZE_ONE] = { nullptr };
655     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
656     if (argc != expectedArgc) {
657         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "The input args num is invalid."));
658         LOGE("The input args num is invalid.");
659         return nullptr;
660     }
661     std::string algoName;
662     if (!GetStringFromJSParams(env, argv[PARAM0], algoName)) {
663         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "Failed to get algorithm."));
664         LOGE("Failed to get algorithm.");
665         return nullptr;
666     }
667     HcfMac *macObj = nullptr;
668     HcfResult res = HcfMacCreate(algoName.c_str(), &macObj);
669     if (res != HCF_SUCCESS) {
670         napi_throw(env, GenerateBusinessError(env, res, "create C obj failed."));
671         LOGE("create c macObj failed.");
672         return nullptr;
673     }
674     napi_value napiAlgName = nullptr;
675     napi_create_string_utf8(env, algoName.c_str(), NAPI_AUTO_LENGTH, &napiAlgName);
676     napi_value instance = nullptr;
677     napi_value constructor = nullptr;
678     napi_get_reference_value(env, classRef_, &constructor);
679     napi_new_instance(env, constructor, argc, argv, &instance);
680     napi_set_named_property(env, instance, CRYPTO_TAG_ALG_NAME.c_str(), napiAlgName);
681     NapiMac *macNapiObj = new (std::nothrow) NapiMac(macObj);
682     if (macNapiObj == nullptr) {
683         napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "new mac napi obj failed."));
684         HcfObjDestroy(macObj);
685         LOGE("create napi obj failed");
686         return nullptr;
687     }
688 
689     return NapiWrapMac(env, instance, macNapiObj);
690 }
691 
DefineMacJSClass(napi_env env,napi_value exports)692 void NapiMac::DefineMacJSClass(napi_env env, napi_value exports)
693 {
694     napi_property_descriptor desc[] = {
695         DECLARE_NAPI_FUNCTION("createMac", NapiMac::CreateMac),
696     };
697     napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
698     napi_property_descriptor classDesc[] = {
699         DECLARE_NAPI_FUNCTION("init", NapiMac::JsMacInit),
700         DECLARE_NAPI_FUNCTION("initSync", NapiMac::JsMacInitSync),
701         DECLARE_NAPI_FUNCTION("update", NapiMac::JsMacUpdate),
702         DECLARE_NAPI_FUNCTION("updateSync", NapiMac::JsMacUpdateSync),
703         DECLARE_NAPI_FUNCTION("doFinal", NapiMac::JsMacDoFinal),
704         DECLARE_NAPI_FUNCTION("doFinalSync", NapiMac::JsMacDoFinalSync),
705         DECLARE_NAPI_FUNCTION("getMacLength", NapiMac::JsGetMacLength),
706     };
707     napi_value constructor = nullptr;
708     napi_define_class(env, "Mac", NAPI_AUTO_LENGTH, MacConstructor, nullptr,
709         sizeof(classDesc) / sizeof(classDesc[0]), classDesc, &constructor);
710     napi_create_reference(env, constructor, 1, &classRef_);
711 }
712 } // CryptoFramework
713 } // OHOS