• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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], &paramsSpec)) {
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