• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023-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_kdf.h"
17 
18 #include "securec.h"
19 #include "memory.h"
20 
21 #include "napi_utils.h"
22 #include "napi_crypto_framework_defines.h"
23 #include "detailed_pbkdf2_params.h"
24 #include "detailed_hkdf_params.h"
25 #include "detailed_scrypt_params.h"
26 
27 #define PBKDF2_ALG_SIZE 6
28 
29 namespace OHOS {
30 namespace CryptoFramework {
31 thread_local napi_ref NapiKdf::classRef_ = nullptr;
32 
33 struct KdfCtx {
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 kdfRef = nullptr;
42 
43     HcfResult errCode = HCF_SUCCESS;
44     const char *errMsg = nullptr;
45     HcfKdfParamsSpec *paramsSpec = nullptr;
46     HcfKdf *kdf = nullptr;
47 };
48 
FreeKdfParamsSpec(HcfKdfParamsSpec * params)49 static void FreeKdfParamsSpec(HcfKdfParamsSpec *params)
50 {
51     if (params == nullptr) {
52         return;
53     }
54     if (PBKDF2_ALG_NAME.compare(params->algName) == 0) {
55         HcfPBKDF2ParamsSpec *tmp = reinterpret_cast<HcfPBKDF2ParamsSpec *>(params);
56         HcfBlobDataClearAndFree(&(tmp->password));
57         HcfBlobDataClearAndFree(&(tmp->salt));
58         HcfBlobDataClearAndFree(&(tmp->output));
59         tmp->base.algName = nullptr;
60     } else if (HKDF_ALG_NAME.compare(params->algName) == 0) {
61         HcfHkdfParamsSpec *tmp = reinterpret_cast<HcfHkdfParamsSpec *>(params);
62         HcfBlobDataClearAndFree(&(tmp->key));
63         HcfBlobDataClearAndFree(&(tmp->salt));
64         HcfBlobDataClearAndFree(&(tmp->info));
65         HcfBlobDataClearAndFree(&(tmp->output));
66         tmp->base.algName = nullptr;
67     } else if (SCRYPT_ALG_NAME.compare(params->algName) == 0) {
68         HcfScryptParamsSpec *tmp = reinterpret_cast<HcfScryptParamsSpec *>(params);
69         HcfBlobDataClearAndFree(&(tmp->passPhrase));
70         HcfBlobDataClearAndFree(&(tmp->salt));
71         HcfBlobDataClearAndFree(&(tmp->output));
72         tmp->base.algName = nullptr;
73     }
74 
75     HcfFree(params);
76 }
77 
FreeCryptoFwkCtx(napi_env env,KdfCtx * context)78 static void FreeCryptoFwkCtx(napi_env env, KdfCtx *context)
79 {
80     if (context == nullptr) {
81         return;
82     }
83     if (context->asyncWork != nullptr) {
84         napi_delete_async_work(env, context->asyncWork);
85         context->asyncWork = nullptr;
86     }
87 
88     if (context->callback != nullptr) {
89         napi_delete_reference(env, context->callback);
90         context->callback = nullptr;
91     }
92 
93     if (context->kdfRef != nullptr) {
94         napi_delete_reference(env, context->kdfRef);
95         context->kdfRef = nullptr;
96     }
97 
98     FreeKdfParamsSpec(context->paramsSpec);
99     context->paramsSpec = nullptr;
100     context->errMsg = nullptr;
101     context->kdf = nullptr;
102     HcfFree(context);
103 }
104 
ReturnCallbackResult(napi_env env,KdfCtx * context,napi_value result)105 static void ReturnCallbackResult(napi_env env, KdfCtx *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,KdfCtx * context,napi_value result)122 static void ReturnPromiseResult(napi_env env, KdfCtx *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 
KdfGenSecretExecute(napi_env env,void * data)132 static void KdfGenSecretExecute(napi_env env, void *data)
133 {
134     KdfCtx *context = static_cast<KdfCtx *>(data);
135     HcfKdf *kdf = context->kdf;
136     context->errCode = kdf->generateSecret(kdf, context->paramsSpec);
137     if (context->errCode != HCF_SUCCESS) {
138         LOGD("[error] KDF generateSecret failed!");
139         context->errMsg = "KDF generateSecret failed";
140         return;
141     }
142 }
143 
KdfGenSecretComplete(napi_env env,napi_status status,void * data)144 static void KdfGenSecretComplete(napi_env env, napi_status status, void *data)
145 {
146     KdfCtx *context = static_cast<KdfCtx *>(data);
147     napi_value returnBlob = nullptr;
148     if (PBKDF2_ALG_NAME.compare(context->paramsSpec->algName) == 0) {
149         HcfPBKDF2ParamsSpec *params = reinterpret_cast<HcfPBKDF2ParamsSpec *>(context->paramsSpec);
150         returnBlob = ConvertBlobToNapiValue(env, &(params->output));
151     } else if (HKDF_ALG_NAME.compare(context->paramsSpec->algName) == 0) {
152         HcfHkdfParamsSpec *params = reinterpret_cast<HcfHkdfParamsSpec *>(context->paramsSpec);
153         returnBlob = ConvertBlobToNapiValue(env, &(params->output));
154     } else if (SCRYPT_ALG_NAME.compare(context->paramsSpec->algName) == 0) {
155         HcfScryptParamsSpec *params = reinterpret_cast<HcfScryptParamsSpec *>(context->paramsSpec);
156         returnBlob = ConvertBlobToNapiValue(env, &(params->output));
157     }
158 
159     if (returnBlob == nullptr) {
160         LOGE("returnOutBlob is nullptr!");
161         returnBlob = NapiGetNull(env);
162     }
163     if (context->asyncType == ASYNC_CALLBACK) {
164         ReturnCallbackResult(env, context, returnBlob);
165     } else {
166         ReturnPromiseResult(env, context, returnBlob);
167     }
168     FreeCryptoFwkCtx(env, context);
169 }
170 
GetInt32FromKdfParams(napi_env env,napi_value arg,const std::string & name,int32_t & retInt)171 static bool GetInt32FromKdfParams(napi_env env, napi_value arg, const std::string &name, int32_t &retInt)
172 {
173     // int attribute
174     napi_value dataInt = nullptr;
175     napi_valuetype valueType = napi_undefined;
176     napi_status status = napi_get_named_property(env, arg, name.c_str(), &dataInt);
177     napi_typeof(env, dataInt, &valueType);
178     if ((status != napi_ok) || (dataInt == nullptr) || (valueType == napi_undefined)) {
179         LOGE("failed to get valid napi int");
180         return false;
181     }
182     return GetInt32FromJSParams(env, dataInt, retInt);
183 }
184 
GetUint64FromKdfParams(napi_env env,napi_value arg,const std::string & name,uint64_t & retInt)185 static bool GetUint64FromKdfParams(napi_env env, napi_value arg, const std::string &name, uint64_t &retInt)
186 {
187     napi_value dataInt = nullptr;
188     napi_valuetype valueType = napi_undefined;
189     napi_status status = napi_get_named_property(env, arg, name.c_str(), &dataInt);
190     napi_typeof(env, dataInt, &valueType);
191     if ((status != napi_ok) || (dataInt == nullptr) || (valueType == napi_undefined)) {
192         LOGE("failed to get valid napi int");
193         return false;
194     }
195     return GetUint64FromJSParams(env, dataInt, retInt);
196 }
197 
GetCharArrayFromUint8Arr(napi_env env,napi_value data,HcfBlob * retBlob)198 static bool GetCharArrayFromUint8Arr(napi_env env, napi_value data, HcfBlob *retBlob)
199 {
200     size_t length = 0;
201     size_t offset = 0;
202     void *rawData = nullptr;
203     napi_value arrayBuffer = nullptr;
204     napi_typedarray_type arrayType;
205     // Warning: Do not release the rawData returned by this interface because the rawData is managed by VM.
206     napi_status status = napi_get_typedarray_info(env, data, &arrayType, &length,
207         reinterpret_cast<void **>(&rawData), &arrayBuffer, &offset);
208     if ((status != napi_ok)) {
209         LOGE("failed to get valid rawData.");
210         return false;
211     }
212     if (arrayType != napi_uint8_array) {
213         LOGE("input data is not uint8 array.");
214         return false;
215     }
216     // input empty uint8Arr, ex: new Uint8Arr(), the length is 0 and rawData is nullptr;
217     if ((length == 0) || (rawData == nullptr)) {
218         LOGD("napi Uint8Arr is null");
219         return true;
220     }
221     if (length > INT_MAX) {
222         LOGE("Beyond the size");
223         return false;
224     }
225     uint8_t *tmp = static_cast<uint8_t *>(HcfMalloc(length, 0));
226     if (tmp == nullptr) {
227         LOGE("malloc blob data failed!");
228         return false;
229     }
230     (void)memcpy_s(tmp, length, rawData, length);
231     retBlob->data = tmp;
232     retBlob->len = length;
233     return true;
234 }
235 
GetCharArrayFromJsString(napi_env env,napi_value arg,HcfBlob * retBlob)236 static bool GetCharArrayFromJsString(napi_env env, napi_value arg, HcfBlob *retBlob)
237 {
238     size_t length = 0;
239     if (napi_get_value_string_utf8(env, arg, nullptr, 0, &length) != napi_ok) {
240         LOGE("can not get char string length");
241         return false;
242     }
243     if (length > INT_MAX) {
244         LOGE("password length should not exceed INT_MAX");
245         return false;
246     }
247     if (length == 0) {
248         LOGD("empty string");
249         return true;
250     }
251     char *tmpPassword = static_cast<char *>(HcfMalloc(length + 1, 0));
252     if (tmpPassword == nullptr) {
253         LOGE("malloc string failed");
254         return false;
255     }
256     if (napi_get_value_string_utf8(env, arg, tmpPassword, (length + 1), &length) != napi_ok) {
257         LOGE("can not get char string value");
258         HcfFree(tmpPassword);
259         tmpPassword = nullptr;
260         return false;
261     }
262     retBlob->data = reinterpret_cast<uint8_t *>(tmpPassword);
263     retBlob->len = length;
264     return true;
265 }
266 
GetKeyOrPwdFromKdfParams(napi_env env,napi_value arg,const std::string & name,HcfBlob * retBlob)267 static bool GetKeyOrPwdFromKdfParams(napi_env env, napi_value arg, const std::string &name, HcfBlob *retBlob)
268 {
269     napi_value data = nullptr;
270     napi_valuetype valueType = napi_undefined;
271     napi_status status = napi_get_named_property(env, arg, name.c_str(), &data);
272     napi_typeof(env, data, &valueType);
273     if ((status != napi_ok) || (data == nullptr) || (valueType == napi_undefined)) {
274         LOGE("failed to get valid password");
275         return false;
276     }
277     if (valueType == napi_string) {
278         if (GetCharArrayFromJsString(env, data, retBlob) != true) {
279             LOGE("get char string failed");
280             return false;
281         }
282     } else {
283         if (GetCharArrayFromUint8Arr(env, data, retBlob) != true) {
284             LOGE("get uint8arr failed");
285             return false;
286         }
287     }
288     return true;
289 }
290 
GetBlobFromKdfParamsSpec(napi_env env,napi_value arg,const std::string & name)291 static HcfBlob *GetBlobFromKdfParamsSpec(napi_env env, napi_value arg, const std::string &name)
292 {
293     // get uint8Array attribute
294     napi_value data = nullptr;
295     napi_valuetype valueType = napi_undefined;
296     napi_status status = napi_get_named_property(env, arg, name.c_str(), &data);
297     napi_typeof(env, data, &valueType);
298     if ((status != napi_ok) || (data == nullptr) || (valueType == napi_undefined)) {
299         LOGE("failed to get valid salt");
300         return nullptr;
301     }
302 
303     return GetBlobFromNapiUint8Arr(env, data);
304 }
305 
SetPBKDF2ParamsSpecAttribute(int iter,const HcfBlob & out,HcfBlob * salt,const HcfBlob & password,HcfPBKDF2ParamsSpec * tmp)306 static void SetPBKDF2ParamsSpecAttribute(int iter, const HcfBlob &out, HcfBlob *salt, const HcfBlob &password,
307     HcfPBKDF2ParamsSpec *tmp)
308 {
309     tmp->iterations = iter;
310     tmp->output = out;
311     tmp->salt.data = salt->data;
312     tmp->salt.len = salt->len;
313     tmp->password = password;
314     tmp->base.algName = PBKDF2_ALG_NAME.c_str();
315 }
316 
SetHkdfParamsSpecAttribute(const HcfBlob & out,const HcfBlob * salt,const HcfBlob & key,const HcfBlob * info,HcfHkdfParamsSpec * tmpParams)317 static void SetHkdfParamsSpecAttribute(const HcfBlob &out, const HcfBlob *salt, const HcfBlob &key,
318     const HcfBlob *info, HcfHkdfParamsSpec *tmpParams)
319 {
320     tmpParams->output = out;
321     tmpParams->salt = *salt;
322     tmpParams->key = key;
323     tmpParams->info = *info;
324     tmpParams->base.algName = HKDF_ALG_NAME.c_str();
325 }
326 
SetScryptParamsSpecAttribute(const HcfBlob & out,const HcfBlob * salt,const HcfBlob & passPhrase,HcfScryptParamsSpec * tmpParams)327 static void SetScryptParamsSpecAttribute(const HcfBlob &out, const HcfBlob *salt, const HcfBlob &passPhrase,
328     HcfScryptParamsSpec *tmpParams)
329 {
330     tmpParams->output = out;
331     tmpParams->salt = *salt;
332     tmpParams->passPhrase = passPhrase;
333     tmpParams->base.algName = SCRYPT_ALG_NAME.c_str();
334 }
335 
GetPBKDF2ParamsSpec(napi_env env,napi_value arg,HcfKdfParamsSpec ** params)336 static bool GetPBKDF2ParamsSpec(napi_env env, napi_value arg, HcfKdfParamsSpec **params)
337 {
338     // get attribute from params
339     // int attribute
340     int iter = -1;
341     int keySize = -1;
342     if (!GetInt32FromKdfParams(env, arg, PBKDF2_PARAMS_ITER, iter) ||
343         !GetInt32FromKdfParams(env, arg, KDF_PARAMS_KEY_SIZE, keySize)) {
344         LOGE("failed to get valid num");
345         return false;
346     }
347     if (iter <= 0 || keySize <= 0) {
348         LOGE("iter and keySize should larger than 0");
349         return false;
350     }
351     HcfBlob out = { .data = static_cast<uint8_t *>(HcfMalloc(keySize, 0)), .len = keySize };
352     if (out.data == nullptr) {
353         LOGE("output malloc failed!");
354         return false;
355     }
356     HcfBlob tmpPassword = { .data = nullptr, .len = 0 };
357     HcfBlob *salt = nullptr;
358     HcfPBKDF2ParamsSpec *tmp = nullptr;
359     do {
360         // get password
361         if (!GetKeyOrPwdFromKdfParams(env, arg, PBKDF2_PARAMS_PASSWORD, &tmpPassword)) {
362             LOGE("failed to get password");
363             break;
364         }
365         // get salt attribute
366         salt = GetBlobFromKdfParamsSpec(env, arg, KDF_PARAMS_SALT);
367         if (salt == nullptr) {
368             LOGE("fail to get salt");
369             break;
370         }
371         // malloc params
372         tmp = static_cast<HcfPBKDF2ParamsSpec *>(HcfMalloc(sizeof(HcfPBKDF2ParamsSpec), 0));
373         if (tmp == nullptr) {
374             LOGE("pbkdf2 spec malloc failed!");
375             break;
376         }
377         SetPBKDF2ParamsSpecAttribute(iter, out, salt, tmpPassword, tmp);
378         // only need the data and data length of the salt, so free the blob pointer.
379         HcfFree(salt);
380         salt = nullptr;
381         *params = reinterpret_cast<HcfKdfParamsSpec *>(tmp);
382         return true;
383     } while (0);
384     HcfBlobDataClearAndFree(&tmpPassword);
385     HcfBlobDataClearAndFree(salt);
386     HcfFree(salt);
387     salt = nullptr;
388     HcfFree(out.data);
389     out.data = nullptr;
390     return false;
391 }
392 
GetHkdfParamsSpec(napi_env env,napi_value arg,HcfKdfParamsSpec ** params)393 static bool GetHkdfParamsSpec(napi_env env, napi_value arg, HcfKdfParamsSpec **params)
394 {
395     int keySize = -1;
396     if (!GetInt32FromKdfParams(env, arg, KDF_PARAMS_KEY_SIZE, keySize)) {
397         LOGE("failed to get valid num");
398         return false;
399     }
400     if (keySize <= 0) {
401         LOGE("keySize should larger than 0");
402         return false;
403     }
404     HcfBlob out = { .data = static_cast<uint8_t *>(HcfMalloc(keySize, 0)), .len = keySize };
405     if (out.data == nullptr) {
406         LOGE("output malloc failed!");
407         return false;
408     }
409 
410     HcfBlob *salt = nullptr;
411     HcfBlob key = { .data = nullptr, .len = 0 };
412     HcfBlob *info = nullptr;
413     HcfHkdfParamsSpec *tmpParams = nullptr;
414     do {
415         // get key
416         if (!GetKeyOrPwdFromKdfParams(env, arg, HKDF_PARAMS_KEY, &key)) {
417             LOGE("failed to get key");
418             break;
419         }
420 
421         // get info、salt
422         info = GetBlobFromKdfParamsSpec(env, arg, HKDF_PARAMS_INFO);
423         salt = GetBlobFromKdfParamsSpec(env, arg, KDF_PARAMS_SALT);
424         if (info == nullptr || salt == nullptr) {
425             LOGE("fail to get info or salt");
426             break;
427         }
428 
429         // malloc tmpParams
430         tmpParams = static_cast<HcfHkdfParamsSpec *>(HcfMalloc(sizeof(HcfHkdfParamsSpec), 0));
431         if (tmpParams == nullptr) {
432             LOGE("hkdf spec malloc failed!");
433             break;
434         }
435         SetHkdfParamsSpecAttribute(out, salt, key, info, tmpParams);
436         // only need the data and data length of the salt, so free the blob pointer.
437         HCF_FREE_PTR(salt);
438         HCF_FREE_PTR(info);
439         *params = reinterpret_cast<HcfKdfParamsSpec *>(tmpParams);
440         return true;
441     } while (0);
442     HcfBlobDataClearAndFree(salt);
443     HcfBlobDataClearAndFree(&key);
444     HcfBlobDataClearAndFree(info);
445     HCF_FREE_PTR(salt);
446     HCF_FREE_PTR(info);
447     HCF_FREE_PTR(out.data);
448     return false;
449 }
450 
AllocateAndSetScryptParams(napi_env env,napi_value arg,HcfBlob & out,HcfScryptParamsSpec * & tmpParams)451 static bool AllocateAndSetScryptParams(napi_env env, napi_value arg, HcfBlob &out, HcfScryptParamsSpec *&tmpParams)
452 {
453     HcfBlob *salt = nullptr;
454     HcfBlob passPhrase = { .data = nullptr, .len = 0 };
455     do {
456         if (!GetKeyOrPwdFromKdfParams(env, arg, SCRYPT_PASSPHRASE, &passPhrase)) {
457             LOGE("failed to get passPhrase");
458             break;
459         }
460 
461         salt = GetBlobFromKdfParamsSpec(env, arg, KDF_PARAMS_SALT);
462         if (salt == nullptr) {
463             LOGE("fail to get salt");
464             break;
465         }
466 
467         tmpParams = static_cast<HcfScryptParamsSpec *>(HcfMalloc(sizeof(HcfScryptParamsSpec), 0));
468         if (tmpParams == nullptr) {
469             LOGE("scrypt spec malloc failed!");
470             break;
471         }
472 
473         SetScryptParamsSpecAttribute(out, salt, passPhrase, tmpParams);
474         HcfFree(salt);
475         salt = nullptr;
476         return true;
477     } while (0);
478     HcfBlobDataClearAndFree(salt);
479     HcfBlobDataClearAndFree(&passPhrase);
480     HcfFree(salt);
481     salt = nullptr;
482 
483     return false;
484 }
485 
GetScryptParamsSpec(napi_env env,napi_value arg,HcfKdfParamsSpec ** params)486 static bool GetScryptParamsSpec(napi_env env, napi_value arg, HcfKdfParamsSpec **params)
487 {
488     int keySize = -1;
489     if (!GetInt32FromKdfParams(env, arg, KDF_PARAMS_KEY_SIZE, keySize)) {
490         LOGE("failed to get valid num");
491         return false;
492     }
493     if (keySize <= 0) {
494         LOGE("keySize should larger than 0");
495         return false;
496     }
497 
498     uint64_t n = 0;
499     uint64_t r = 0;
500     uint64_t p = 0;
501     uint64_t maxMemory = 0;
502     if (!GetUint64FromKdfParams(env, arg, SCRYPT_N, n) || !GetUint64FromKdfParams(env, arg, SCRYPT_R, r) ||
503         !GetUint64FromKdfParams(env, arg, SCRYPT_P, p) || !GetUint64FromKdfParams(env, arg, SCRYPT_MEMORY, maxMemory)) {
504         LOGE("failed to get valid num");
505         return false;
506     }
507 
508     HcfBlob out = { .data = static_cast<uint8_t *>(HcfMalloc(keySize, 0)), .len = keySize };
509     if (out.data == nullptr) {
510         LOGE("output malloc failed!");
511         return false;
512     }
513 
514     HcfScryptParamsSpec *tmpParams = nullptr;
515     if (!AllocateAndSetScryptParams(env, arg, out, tmpParams)) {
516         HcfFree(out.data);
517         out.data = nullptr;
518         return false;
519     }
520     tmpParams->n = n;
521     tmpParams->p = p;
522     tmpParams->r = r;
523     tmpParams->maxMem = maxMemory;
524 
525     *params = reinterpret_cast<HcfKdfParamsSpec *>(tmpParams);
526     return true;
527 }
528 
GetKdfParamsSpec(napi_env env,napi_value arg,HcfKdfParamsSpec ** params)529 static bool GetKdfParamsSpec(napi_env env, napi_value arg, HcfKdfParamsSpec **params)
530 {
531     napi_value data = nullptr;
532     napi_valuetype valueType = napi_undefined;
533     if ((env == nullptr) || (arg == nullptr) || (params == nullptr)) {
534         LOGE("Invalid params!");
535         return false;
536     }
537 
538     napi_status status = napi_get_named_property(env, arg, ALGO_PARAMS.c_str(), &data);
539     napi_typeof(env, data, &valueType);
540     if ((status != napi_ok) || (data == nullptr) || (valueType == napi_undefined)) {
541         LOGE("failed to get valid algo name!");
542         return false;
543     }
544     std::string algoName;
545     if (!GetStringFromJSParams(env, data, algoName)) {
546         LOGE("GetStringFromJSParams failed!");
547         return false;
548     }
549     if (algoName.compare(PBKDF2_ALG_NAME) == 0) {
550         return GetPBKDF2ParamsSpec(env, arg, params);
551     } else if (algoName.compare(HKDF_ALG_NAME) == 0) {
552         return GetHkdfParamsSpec(env, arg, params);
553     } else if (algoName.compare(SCRYPT_ALG_NAME) == 0) {
554         return GetScryptParamsSpec(env, arg, params);
555     } else {
556         LOGE("Not support that alg");
557         return false;
558     }
559 }
560 
BuildKdfGenSecretCtx(napi_env env,napi_callback_info info,KdfCtx * context)561 static bool BuildKdfGenSecretCtx(napi_env env, napi_callback_info info, KdfCtx *context)
562 {
563     napi_value thisVar = nullptr;
564     size_t expectedArgsCount = ARGS_SIZE_TWO;
565     size_t argc = expectedArgsCount;
566     napi_value argv[ARGS_SIZE_TWO] = { nullptr };
567     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
568     if ((argc != expectedArgsCount) && (argc != expectedArgsCount - CALLBACK_SIZE)) {
569         LOGE("The arguments count is not expected!");
570         return false;
571     }
572 
573     NapiKdf *napiKdf = nullptr;
574     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiKdf));
575     if (status != napi_ok || napiKdf == nullptr) {
576         LOGE("failed to unwrap NapiKdf obj!");
577         return false;
578     }
579 
580     context->kdf = napiKdf->GetKdf();
581     if (!GetKdfParamsSpec(env, argv[PARAM0], &(context->paramsSpec))) {
582         LOGE("get kdf paramsspec failed!");
583         return false;
584     }
585     context->asyncType = isCallback(env, argv[expectedArgsCount - 1], argc, expectedArgsCount) ?
586         ASYNC_CALLBACK : ASYNC_PROMISE;
587 
588     if (napi_create_reference(env, thisVar, 1, &context->kdfRef) != napi_ok) {
589         LOGE("create kdf ref failed when derive secret key using kdf!");
590         return false;
591     }
592 
593     if (context->asyncType == ASYNC_PROMISE) {
594         napi_create_promise(env, &context->deferred, &context->promise);
595         return true;
596     } else {
597         return GetCallbackFromJSParams(env, argv[PARAM1], &context->callback);
598     }
599 }
600 
NewKdfJsGenSecretAsyncWork(napi_env env,KdfCtx * context)601 static napi_value NewKdfJsGenSecretAsyncWork(napi_env env, KdfCtx *context)
602 {
603     napi_create_async_work(
604         env, nullptr, GetResourceName(env, "KdfGenerateSecret"),
605         [](napi_env env, void *data) {
606             KdfGenSecretExecute(env, data);
607             return;
608         },
609         [](napi_env env, napi_status status, void *data) {
610             KdfGenSecretComplete(env, status, data);
611             return;
612         },
613         static_cast<void *>(context),
614         &context->asyncWork);
615 
616     napi_queue_async_work(env, context->asyncWork);
617     if (context->asyncType == ASYNC_PROMISE) {
618         return context->promise;
619     } else {
620         return NapiGetNull(env);
621     }
622 }
623 
NapiKdf(HcfKdf * kdfObj)624 NapiKdf::NapiKdf(HcfKdf *kdfObj)
625 {
626     this->kdf = kdfObj;
627 }
628 
~NapiKdf()629 NapiKdf::~NapiKdf()
630 {
631     HcfObjDestroy(this->kdf);
632     this->kdf = nullptr;
633 }
634 
GetKdf() const635 HcfKdf *NapiKdf::GetKdf() const
636 {
637     return this->kdf;
638 }
639 
JsKdfGenerateSecret(napi_env env,napi_callback_info info)640 napi_value NapiKdf::JsKdfGenerateSecret(napi_env env, napi_callback_info info)
641 {
642     KdfCtx *context = static_cast<KdfCtx *>(HcfMalloc(sizeof(KdfCtx), 0));
643     if (context == nullptr) {
644         napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "malloc context failed"));
645         LOGE("malloc context failed!");
646         return nullptr;
647     }
648 
649     if (!BuildKdfGenSecretCtx(env, info, context)) {
650         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "build context fail."));
651         LOGE("build context fail.");
652         FreeCryptoFwkCtx(env, context);
653         return nullptr;
654     }
655 
656     return NewKdfJsGenSecretAsyncWork(env, context);
657 }
658 
NewKdfJsGenSecretSyncWork(napi_env env,HcfKdfParamsSpec * paramsSpec)659 static napi_value NewKdfJsGenSecretSyncWork(napi_env env, HcfKdfParamsSpec *paramsSpec)
660 {
661     napi_value returnBlob = nullptr;
662     if (PBKDF2_ALG_NAME.compare(paramsSpec->algName) == 0) {
663         HcfPBKDF2ParamsSpec *params = reinterpret_cast<HcfPBKDF2ParamsSpec *>(paramsSpec);
664         returnBlob = ConvertBlobToNapiValue(env, &(params->output));
665     } else if (HKDF_ALG_NAME.compare(paramsSpec->algName) == 0) {
666         HcfHkdfParamsSpec *params = reinterpret_cast<HcfHkdfParamsSpec *>(paramsSpec);
667         returnBlob = ConvertBlobToNapiValue(env, &(params->output));
668     } else if (SCRYPT_ALG_NAME.compare(paramsSpec->algName) == 0) {
669         HcfScryptParamsSpec *params = reinterpret_cast<HcfScryptParamsSpec *>(paramsSpec);
670         returnBlob = ConvertBlobToNapiValue(env, &(params->output));
671     }
672     if (returnBlob == nullptr) {
673         LOGE("returnBlob is nullptr!");
674         napi_throw(env, GenerateBusinessError(env, HCF_ERR_NAPI, "returnBlob is nullptr!"));
675         returnBlob = NapiGetNull(env);
676     }
677     FreeKdfParamsSpec(paramsSpec);
678     paramsSpec = nullptr;
679     return returnBlob;
680 }
681 
JsKdfGenerateSecretSync(napi_env env,napi_callback_info info)682 napi_value NapiKdf::JsKdfGenerateSecretSync(napi_env env, napi_callback_info info)
683 {
684     napi_value thisVar = nullptr;
685     size_t argc = ARGS_SIZE_ONE;
686     napi_value argv[ARGS_SIZE_ONE] = { nullptr };
687     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
688     if (argc != ARGS_SIZE_ONE) {
689         LOGE("The arguments count is not expected!");
690         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "The arguments count is not expected!"));
691         return nullptr;
692     }
693     NapiKdf *napiKdf = nullptr;
694     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiKdf));
695     if (status != napi_ok || napiKdf == nullptr) {
696         LOGE("failed to unwrap NapiKdf obj!");
697         napi_throw(env, GenerateBusinessError(env, HCF_ERR_NAPI, "failed to unwrap NapiKdf obj!"));
698         return nullptr;
699     }
700     HcfKdf *kdf = napiKdf->GetKdf();
701     if (kdf == nullptr) {
702         LOGE("fail to get kdf obj!");
703         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "fail to get kdf obj!"));
704         return nullptr;
705     }
706     HcfKdfParamsSpec *paramsSpec = nullptr;
707     if (!GetKdfParamsSpec(env, argv[PARAM0], &paramsSpec)) {
708         LOGE("get kdf paramsspec failed!");
709         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "get kdf paramsspec failed!"));
710         FreeKdfParamsSpec(paramsSpec);
711         paramsSpec = nullptr;
712         return nullptr;
713     }
714     HcfResult errCode = kdf->generateSecret(kdf, paramsSpec);
715     if (errCode != HCF_SUCCESS) {
716         LOGE("KDF generateSecret failed!");
717         napi_throw(env, GenerateBusinessError(env, errCode, "KDF generateSecret failed!"));
718         FreeKdfParamsSpec(paramsSpec);
719         return nullptr;
720     }
721     napi_value returnBlob = NewKdfJsGenSecretSyncWork(env, paramsSpec);
722     return returnBlob;
723 }
724 
JsGetAlgorithm(napi_env env,napi_callback_info info)725 napi_value NapiKdf::JsGetAlgorithm(napi_env env, napi_callback_info info)
726 {
727     napi_value thisVar = nullptr;
728     NapiKdf *napiKdf = nullptr;
729 
730     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
731     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiKdf));
732     if (status != napi_ok || napiKdf == nullptr) {
733         LOGE("failed to unwrap NapiKdf obj!");
734         return nullptr;
735     }
736 
737     HcfKdf *kdf = napiKdf->GetKdf();
738     if (kdf == nullptr) {
739         LOGE("fail to get kdf obj!");
740         return nullptr;
741     }
742 
743     const char *algoName = kdf->getAlgorithm(kdf);
744     napi_value instance = nullptr;
745     napi_create_string_utf8(env, algoName, NAPI_AUTO_LENGTH, &instance);
746     return instance;
747 }
748 
KdfConstructor(napi_env env,napi_callback_info info)749 napi_value NapiKdf::KdfConstructor(napi_env env, napi_callback_info info)
750 {
751     napi_value thisVar = nullptr;
752     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
753     return thisVar;
754 }
755 
CreateJsKdf(napi_env env,napi_callback_info info)756 napi_value NapiKdf::CreateJsKdf(napi_env env, napi_callback_info info)
757 {
758     size_t expectedArgc = ARGS_SIZE_ONE;
759     size_t argc = expectedArgc;
760     napi_value argv[ARGS_SIZE_ONE] = { nullptr };
761     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
762     if (argc != expectedArgc) {
763         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "The input args num is invalid."));
764         LOGE("The input args num is invalid.");
765         return nullptr;
766     }
767     std::string algoName;
768     if (!GetStringFromJSParams(env, argv[PARAM0], algoName)) {
769         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "Failed to get algorithm."));
770         LOGE("Failed to get algorithm.");
771         return nullptr;
772     }
773     HcfKdf *kdf = nullptr;
774     HcfResult res = HcfKdfCreate(algoName.c_str(), &kdf);
775     if (res != HCF_SUCCESS) {
776         napi_throw(env, GenerateBusinessError(env, res, "create C obj failed."));
777         LOGE("create c kdf obj failed.");
778         return nullptr;
779     }
780     napi_value instance = nullptr;
781     napi_value constructor = nullptr;
782     napi_get_reference_value(env, classRef_, &constructor);
783     napi_new_instance(env, constructor, 0, nullptr, &instance);
784     NapiKdf *napiKdf = new (std::nothrow) NapiKdf(kdf);
785     if (napiKdf == nullptr) {
786         napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "new kdf napi obj failed."));
787         HcfObjDestroy(kdf);
788         kdf = nullptr;
789         LOGE("create kdf napi obj failed");
790         return nullptr;
791     }
792     napi_status status = napi_wrap(env, instance, napiKdf,
793         [](napi_env env, void *data, void *hint) {
794             NapiKdf *kdf = static_cast<NapiKdf *>(data);
795             delete kdf;
796             return;
797         }, nullptr, nullptr);
798     if (status != napi_ok) {
799         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to wrap NapiKdf obj!"));
800         delete napiKdf;
801         LOGE("failed to wrap NapiKdf obj!");
802         return nullptr;
803     }
804     return instance;
805 }
806 
DefineKdfJSClass(napi_env env,napi_value exports)807 void NapiKdf::DefineKdfJSClass(napi_env env, napi_value exports)
808 {
809     napi_property_descriptor desc[] = {
810         DECLARE_NAPI_FUNCTION("createKdf", NapiKdf::CreateJsKdf),
811     };
812     napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
813     napi_property_descriptor classDesc[] = {
814         DECLARE_NAPI_FUNCTION("generateSecret", NapiKdf::JsKdfGenerateSecret),
815         DECLARE_NAPI_FUNCTION("generateSecretSync", NapiKdf::JsKdfGenerateSecretSync),
816         {.utf8name = "algName", .getter = NapiKdf::JsGetAlgorithm},
817     };
818     napi_value constructor = nullptr;
819     napi_define_class(env, "Kdf", NAPI_AUTO_LENGTH, KdfConstructor, nullptr,
820         sizeof(classDesc) / sizeof(classDesc[0]), classDesc, &constructor);
821     napi_create_reference(env, constructor, 1, &classRef_);
822 }
823 } // CryptoFramework
824 } // OHOS
825