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