• 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         return false;
260     }
261     retBlob->data = reinterpret_cast<uint8_t *>(tmpPassword);
262     retBlob->len = length;
263     return true;
264 }
265 
GetKeyOrPwdFromKdfParams(napi_env env,napi_value arg,const std::string & name,HcfBlob * retBlob)266 static bool GetKeyOrPwdFromKdfParams(napi_env env, napi_value arg, const std::string &name, HcfBlob *retBlob)
267 {
268     napi_value data = nullptr;
269     napi_valuetype valueType = napi_undefined;
270     napi_status status = napi_get_named_property(env, arg, name.c_str(), &data);
271     napi_typeof(env, data, &valueType);
272     if ((status != napi_ok) || (data == nullptr) || (valueType == napi_undefined)) {
273         LOGE("failed to get valid password");
274         return false;
275     }
276     if (valueType == napi_string) {
277         if (GetCharArrayFromJsString(env, data, retBlob) != true) {
278             LOGE("get char string failed");
279             return false;
280         }
281     } else {
282         if (GetCharArrayFromUint8Arr(env, data, retBlob) != true) {
283             LOGE("get uint8arr failed");
284             return false;
285         }
286     }
287     return true;
288 }
289 
GetBlobFromKdfParamsSpec(napi_env env,napi_value arg,const std::string & name)290 static HcfBlob *GetBlobFromKdfParamsSpec(napi_env env, napi_value arg, const std::string &name)
291 {
292     // get uint8Array attribute
293     napi_value data = nullptr;
294     napi_valuetype valueType = napi_undefined;
295     napi_status status = napi_get_named_property(env, arg, name.c_str(), &data);
296     napi_typeof(env, data, &valueType);
297     if ((status != napi_ok) || (data == nullptr) || (valueType == napi_undefined)) {
298         LOGE("failed to get valid salt");
299         return nullptr;
300     }
301 
302     return GetBlobFromNapiUint8Arr(env, data);
303 }
304 
SetPBKDF2ParamsSpecAttribute(int iter,const HcfBlob & out,HcfBlob * salt,const HcfBlob & password,HcfPBKDF2ParamsSpec * tmp)305 static void SetPBKDF2ParamsSpecAttribute(int iter, const HcfBlob &out, HcfBlob *salt, const HcfBlob &password,
306     HcfPBKDF2ParamsSpec *tmp)
307 {
308     tmp->iterations = iter;
309     tmp->output = out;
310     tmp->salt.data = salt->data;
311     tmp->salt.len = salt->len;
312     tmp->password = password;
313     tmp->base.algName = PBKDF2_ALG_NAME.c_str();
314 }
315 
SetHkdfParamsSpecAttribute(const HcfBlob & out,const HcfBlob * salt,const HcfBlob & key,const HcfBlob * info,HcfHkdfParamsSpec * tmpParams)316 static void SetHkdfParamsSpecAttribute(const HcfBlob &out, const HcfBlob *salt, const HcfBlob &key,
317     const HcfBlob *info, HcfHkdfParamsSpec *tmpParams)
318 {
319     tmpParams->output = out;
320     tmpParams->salt = *salt;
321     tmpParams->key = key;
322     tmpParams->info = *info;
323     tmpParams->base.algName = HKDF_ALG_NAME.c_str();
324 }
325 
SetScryptParamsSpecAttribute(const HcfBlob & out,const HcfBlob * salt,const HcfBlob & passPhrase,HcfScryptParamsSpec * tmpParams)326 static void SetScryptParamsSpecAttribute(const HcfBlob &out, const HcfBlob *salt, const HcfBlob &passPhrase,
327     HcfScryptParamsSpec *tmpParams)
328 {
329     tmpParams->output = out;
330     tmpParams->salt = *salt;
331     tmpParams->passPhrase = passPhrase;
332     tmpParams->base.algName = SCRYPT_ALG_NAME.c_str();
333 }
334 
GetPBKDF2ParamsSpec(napi_env env,napi_value arg,HcfKdfParamsSpec ** params)335 static bool GetPBKDF2ParamsSpec(napi_env env, napi_value arg, HcfKdfParamsSpec **params)
336 {
337     // get attribute from params
338     // int attribute
339     int iter = -1;
340     int keySize = -1;
341     if (!GetInt32FromKdfParams(env, arg, PBKDF2_PARAMS_ITER, iter) ||
342         !GetInt32FromKdfParams(env, arg, KDF_PARAMS_KEY_SIZE, keySize)) {
343         LOGE("failed to get valid num");
344         return false;
345     }
346     if (iter <= 0 || keySize <= 0) {
347         LOGE("iter and keySize should larger than 0");
348         return false;
349     }
350     HcfBlob out = { .data = static_cast<uint8_t *>(HcfMalloc(keySize, 0)), .len = keySize };
351     if (out.data == nullptr) {
352         LOGE("output malloc failed!");
353         return false;
354     }
355     HcfBlob tmpPassword = { .data = nullptr, .len = 0 };
356     HcfBlob *salt = nullptr;
357     HcfPBKDF2ParamsSpec *tmp = nullptr;
358     do {
359         // get password
360         if (!GetKeyOrPwdFromKdfParams(env, arg, PBKDF2_PARAMS_PASSWORD, &tmpPassword)) {
361             LOGE("failed to get password");
362             break;
363         }
364         // get salt attribute
365         salt = GetBlobFromKdfParamsSpec(env, arg, KDF_PARAMS_SALT);
366         if (salt == nullptr) {
367             LOGE("fail to get salt");
368             break;
369         }
370         // malloc params
371         tmp = static_cast<HcfPBKDF2ParamsSpec *>(HcfMalloc(sizeof(HcfPBKDF2ParamsSpec), 0));
372         if (tmp == nullptr) {
373             LOGE("pbkdf2 spec malloc failed!");
374             break;
375         }
376         SetPBKDF2ParamsSpecAttribute(iter, out, salt, tmpPassword, tmp);
377         // only need the data and data length of the salt, so free the blob pointer.
378         HcfFree(salt);
379         *params = reinterpret_cast<HcfKdfParamsSpec *>(tmp);
380         return true;
381     } while (0);
382     HcfBlobDataClearAndFree(&tmpPassword);
383     HcfBlobDataClearAndFree(salt);
384     HcfFree(salt);
385     HcfFree(out.data);
386     return false;
387 }
388 
GetHkdfParamsSpec(napi_env env,napi_value arg,HcfKdfParamsSpec ** params)389 static bool GetHkdfParamsSpec(napi_env env, napi_value arg, HcfKdfParamsSpec **params)
390 {
391     int keySize = -1;
392     if (!GetInt32FromKdfParams(env, arg, KDF_PARAMS_KEY_SIZE, keySize)) {
393         LOGE("failed to get valid num");
394         return false;
395     }
396     if (keySize <= 0) {
397         LOGE("keySize should larger than 0");
398         return false;
399     }
400     HcfBlob out = { .data = static_cast<uint8_t *>(HcfMalloc(keySize, 0)), .len = keySize };
401     if (out.data == nullptr) {
402         LOGE("output malloc failed!");
403         return false;
404     }
405 
406     HcfBlob *salt = nullptr;
407     HcfBlob key = { .data = nullptr, .len = 0 };
408     HcfBlob *info = nullptr;
409     HcfHkdfParamsSpec *tmpParams = nullptr;
410     do {
411         // get key
412         if (!GetKeyOrPwdFromKdfParams(env, arg, HKDF_PARAMS_KEY, &key)) {
413             LOGE("failed to get key");
414             break;
415         }
416 
417         // get info、salt
418         info = GetBlobFromKdfParamsSpec(env, arg, HKDF_PARAMS_INFO);
419         salt = GetBlobFromKdfParamsSpec(env, arg, KDF_PARAMS_SALT);
420         if (info == nullptr || salt == nullptr) {
421             LOGE("fail to get info or salt");
422             break;
423         }
424 
425         // malloc tmpParams
426         tmpParams = static_cast<HcfHkdfParamsSpec *>(HcfMalloc(sizeof(HcfHkdfParamsSpec), 0));
427         if (tmpParams == nullptr) {
428             LOGE("hkdf spec malloc failed!");
429             break;
430         }
431         SetHkdfParamsSpecAttribute(out, salt, key, info, tmpParams);
432         // only need the data and data length of the salt, so free the blob pointer.
433         HcfFree(salt);
434         HcfFree(info);
435         *params = reinterpret_cast<HcfKdfParamsSpec *>(tmpParams);
436         return true;
437     } while (0);
438     HcfBlobDataClearAndFree(salt);
439     HcfBlobDataClearAndFree(&key);
440     HcfBlobDataClearAndFree(info);
441     HcfFree(salt);
442     HcfFree(info);
443     HcfFree(out.data);
444     return false;
445 }
446 
AllocateAndSetScryptParams(napi_env env,napi_value arg,HcfBlob & out,HcfScryptParamsSpec * & tmpParams)447 static bool AllocateAndSetScryptParams(napi_env env, napi_value arg, HcfBlob &out, HcfScryptParamsSpec *&tmpParams)
448 {
449     HcfBlob *salt = nullptr;
450     HcfBlob passPhrase = { .data = nullptr, .len = 0 };
451     do {
452         if (!GetKeyOrPwdFromKdfParams(env, arg, SCRYPT_PASSPHRASE, &passPhrase)) {
453             LOGE("failed to get passPhrase");
454             break;
455         }
456 
457         salt = GetBlobFromKdfParamsSpec(env, arg, KDF_PARAMS_SALT);
458         if (salt == nullptr) {
459             LOGE("fail to get salt");
460             break;
461         }
462 
463         tmpParams = static_cast<HcfScryptParamsSpec *>(HcfMalloc(sizeof(HcfScryptParamsSpec), 0));
464         if (tmpParams == nullptr) {
465             LOGE("scrypt spec malloc failed!");
466             break;
467         }
468 
469         SetScryptParamsSpecAttribute(out, salt, passPhrase, tmpParams);
470         HcfFree(salt);
471         return true;
472     } while (0);
473     HcfBlobDataClearAndFree(salt);
474     HcfBlobDataClearAndFree(&passPhrase);
475     HcfFree(salt);
476 
477     return false;
478 }
479 
GetScryptParamsSpec(napi_env env,napi_value arg,HcfKdfParamsSpec ** params)480 static bool GetScryptParamsSpec(napi_env env, napi_value arg, HcfKdfParamsSpec **params)
481 {
482     int keySize = -1;
483     if (!GetInt32FromKdfParams(env, arg, KDF_PARAMS_KEY_SIZE, keySize)) {
484         LOGE("failed to get valid num");
485         return false;
486     }
487     if (keySize <= 0) {
488         LOGE("keySize should larger than 0");
489         return false;
490     }
491 
492     uint64_t n = 0;
493     uint64_t r = 0;
494     uint64_t p = 0;
495     uint64_t maxMemory = 0;
496     if (!GetUint64FromKdfParams(env, arg, SCRYPT_N, n) || !GetUint64FromKdfParams(env, arg, SCRYPT_R, r) ||
497         !GetUint64FromKdfParams(env, arg, SCRYPT_P, p) || !GetUint64FromKdfParams(env, arg, SCRYPT_MEMORY, maxMemory)) {
498         LOGE("failed to get valid num");
499         return false;
500     }
501 
502     if (n < 0 || r < 0 || p < 0 || maxMemory < 0) {
503         LOGE("n, r, p, or maxMemory cannot be negative number.");
504         return false;
505     }
506 
507     HcfBlob out = { .data = static_cast<uint8_t *>(HcfMalloc(keySize, 0)), .len = keySize };
508     if (out.data == nullptr) {
509         LOGE("output malloc failed!");
510         return false;
511     }
512 
513     HcfScryptParamsSpec *tmpParams = nullptr;
514     if (!AllocateAndSetScryptParams(env, arg, out, tmpParams)) {
515         HcfFree(out.data);
516         return false;
517     }
518     tmpParams->n = n;
519     tmpParams->p = p;
520     tmpParams->r = r;
521     tmpParams->maxMem = maxMemory;
522 
523     *params = reinterpret_cast<HcfKdfParamsSpec *>(tmpParams);
524     return true;
525 }
526 
GetKdfParamsSpec(napi_env env,napi_value arg,HcfKdfParamsSpec ** params)527 static bool GetKdfParamsSpec(napi_env env, napi_value arg, HcfKdfParamsSpec **params)
528 {
529     napi_value data = nullptr;
530     napi_valuetype valueType = napi_undefined;
531     if ((env == nullptr) || (arg == nullptr) || (params == nullptr)) {
532         LOGE("Invalid params!");
533         return false;
534     }
535 
536     napi_status status = napi_get_named_property(env, arg, ALGO_PARAMS.c_str(), &data);
537     napi_typeof(env, data, &valueType);
538     if ((status != napi_ok) || (data == nullptr) || (valueType == napi_undefined)) {
539         LOGE("failed to get valid algo name!");
540         return false;
541     }
542     std::string algoName;
543     if (!GetStringFromJSParams(env, data, algoName)) {
544         LOGE("GetStringFromJSParams failed!");
545         return false;
546     }
547     if (algoName.compare(PBKDF2_ALG_NAME) == 0) {
548         return GetPBKDF2ParamsSpec(env, arg, params);
549     } else if (algoName.compare(HKDF_ALG_NAME) == 0) {
550         return GetHkdfParamsSpec(env, arg, params);
551     } else if (algoName.compare(SCRYPT_ALG_NAME) == 0) {
552         return GetScryptParamsSpec(env, arg, params);
553     } else {
554         LOGE("Not support that alg");
555         return false;
556     }
557 }
558 
BuildKdfGenSecretCtx(napi_env env,napi_callback_info info,KdfCtx * context)559 static bool BuildKdfGenSecretCtx(napi_env env, napi_callback_info info, KdfCtx *context)
560 {
561     napi_value thisVar = nullptr;
562     size_t expectedArgsCount = ARGS_SIZE_TWO;
563     size_t argc = expectedArgsCount;
564     napi_value argv[ARGS_SIZE_TWO] = { nullptr };
565     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
566     if ((argc != expectedArgsCount) && (argc != expectedArgsCount - CALLBACK_SIZE)) {
567         LOGE("The arguments count is not expected!");
568         return false;
569     }
570 
571     NapiKdf *napiKdf = nullptr;
572     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiKdf));
573     if (status != napi_ok || napiKdf == nullptr) {
574         LOGE("failed to unwrap NapiKdf obj!");
575         return false;
576     }
577 
578     context->kdf = napiKdf->GetKdf();
579     if (!GetKdfParamsSpec(env, argv[PARAM0], &(context->paramsSpec))) {
580         LOGE("get kdf paramsspec failed!");
581         return false;
582     }
583     context->asyncType = isCallback(env, argv[expectedArgsCount - 1], argc, expectedArgsCount) ?
584         ASYNC_CALLBACK : ASYNC_PROMISE;
585 
586     if (napi_create_reference(env, thisVar, 1, &context->kdfRef) != napi_ok) {
587         LOGE("create kdf ref failed when derive secret key using kdf!");
588         return false;
589     }
590 
591     if (context->asyncType == ASYNC_PROMISE) {
592         napi_create_promise(env, &context->deferred, &context->promise);
593         return true;
594     } else {
595         return GetCallbackFromJSParams(env, argv[PARAM1], &context->callback);
596     }
597 }
598 
NewKdfJsGenSecretAsyncWork(napi_env env,KdfCtx * context)599 static napi_value NewKdfJsGenSecretAsyncWork(napi_env env, KdfCtx *context)
600 {
601     napi_create_async_work(
602         env, nullptr, GetResourceName(env, "KdfGenerateSecret"),
603         [](napi_env env, void *data) {
604             KdfGenSecretExecute(env, data);
605             return;
606         },
607         [](napi_env env, napi_status status, void *data) {
608             KdfGenSecretComplete(env, status, data);
609             return;
610         },
611         static_cast<void *>(context),
612         &context->asyncWork);
613 
614     napi_queue_async_work(env, context->asyncWork);
615     if (context->asyncType == ASYNC_PROMISE) {
616         return context->promise;
617     } else {
618         return NapiGetNull(env);
619     }
620 }
621 
NapiKdf(HcfKdf * kdfObj)622 NapiKdf::NapiKdf(HcfKdf *kdfObj)
623 {
624     this->kdf = kdfObj;
625 }
626 
~NapiKdf()627 NapiKdf::~NapiKdf()
628 {
629     HcfObjDestroy(this->kdf);
630 }
631 
GetKdf() const632 HcfKdf *NapiKdf::GetKdf() const
633 {
634     return this->kdf;
635 }
636 
JsKdfGenerateSecret(napi_env env,napi_callback_info info)637 napi_value NapiKdf::JsKdfGenerateSecret(napi_env env, napi_callback_info info)
638 {
639     KdfCtx *context = static_cast<KdfCtx *>(HcfMalloc(sizeof(KdfCtx), 0));
640     if (context == nullptr) {
641         napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "malloc context failed"));
642         LOGE("malloc context failed!");
643         return nullptr;
644     }
645 
646     if (!BuildKdfGenSecretCtx(env, info, context)) {
647         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "build context fail."));
648         LOGE("build context fail.");
649         FreeCryptoFwkCtx(env, context);
650         return nullptr;
651     }
652 
653     return NewKdfJsGenSecretAsyncWork(env, context);
654 }
655 
NewKdfJsGenSecretSyncWork(napi_env env,HcfKdfParamsSpec * paramsSpec)656 static napi_value NewKdfJsGenSecretSyncWork(napi_env env, HcfKdfParamsSpec *paramsSpec)
657 {
658     napi_value returnBlob = nullptr;
659     if (PBKDF2_ALG_NAME.compare(paramsSpec->algName) == 0) {
660         HcfPBKDF2ParamsSpec *params = reinterpret_cast<HcfPBKDF2ParamsSpec *>(paramsSpec);
661         returnBlob = ConvertBlobToNapiValue(env, &(params->output));
662     } else if (HKDF_ALG_NAME.compare(paramsSpec->algName) == 0) {
663         HcfHkdfParamsSpec *params = reinterpret_cast<HcfHkdfParamsSpec *>(paramsSpec);
664         returnBlob = ConvertBlobToNapiValue(env, &(params->output));
665     } else if (SCRYPT_ALG_NAME.compare(paramsSpec->algName) == 0) {
666         HcfScryptParamsSpec *params = reinterpret_cast<HcfScryptParamsSpec *>(paramsSpec);
667         returnBlob = ConvertBlobToNapiValue(env, &(params->output));
668     }
669     if (returnBlob == nullptr) {
670         LOGE("returnBlob is nullptr!");
671         napi_throw(env, GenerateBusinessError(env, HCF_ERR_NAPI, "returnBlob is nullptr!"));
672         returnBlob = NapiGetNull(env);
673     }
674     FreeKdfParamsSpec(paramsSpec);
675     paramsSpec = nullptr;
676     return returnBlob;
677 }
678 
JsKdfGenerateSecretSync(napi_env env,napi_callback_info info)679 napi_value NapiKdf::JsKdfGenerateSecretSync(napi_env env, napi_callback_info info)
680 {
681     napi_value thisVar = nullptr;
682     size_t argc = ARGS_SIZE_ONE;
683     napi_value argv[ARGS_SIZE_ONE] = { nullptr };
684     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
685     if (argc != ARGS_SIZE_ONE) {
686         LOGE("The arguments count is not expected!");
687         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "The arguments count is not expected!"));
688         return nullptr;
689     }
690     NapiKdf *napiKdf = nullptr;
691     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiKdf));
692     if (status != napi_ok || napiKdf == nullptr) {
693         LOGE("failed to unwrap NapiKdf obj!");
694         napi_throw(env, GenerateBusinessError(env, HCF_ERR_NAPI, "failed to unwrap NapiKdf obj!"));
695         return nullptr;
696     }
697     HcfKdf *kdf = napiKdf->GetKdf();
698     if (kdf == nullptr) {
699         LOGE("fail to get kdf obj!");
700         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "fail to get kdf obj!"));
701         return nullptr;
702     }
703     HcfKdfParamsSpec *paramsSpec = nullptr;
704     if (!GetKdfParamsSpec(env, argv[PARAM0], &paramsSpec)) {
705         LOGE("get kdf paramsspec failed!");
706         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "get kdf paramsspec failed!"));
707         FreeKdfParamsSpec(paramsSpec);
708         paramsSpec = nullptr;
709         return nullptr;
710     }
711     HcfResult errCode = kdf->generateSecret(kdf, paramsSpec);
712     if (errCode != HCF_SUCCESS) {
713         LOGE("KDF generateSecret failed!");
714         napi_throw(env, GenerateBusinessError(env, errCode, "KDF generateSecret failed!"));
715         FreeKdfParamsSpec(paramsSpec);
716         return nullptr;
717     }
718     napi_value returnBlob = NewKdfJsGenSecretSyncWork(env, paramsSpec);
719     return returnBlob;
720 }
721 
JsGetAlgorithm(napi_env env,napi_callback_info info)722 napi_value NapiKdf::JsGetAlgorithm(napi_env env, napi_callback_info info)
723 {
724     napi_value thisVar = nullptr;
725     NapiKdf *napiKdf = nullptr;
726 
727     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
728     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiKdf));
729     if (status != napi_ok || napiKdf == nullptr) {
730         LOGE("failed to unwrap NapiKdf obj!");
731         return nullptr;
732     }
733 
734     HcfKdf *kdf = napiKdf->GetKdf();
735     if (kdf == nullptr) {
736         LOGE("fail to get kdf obj!");
737         return nullptr;
738     }
739 
740     const char *algoName = kdf->getAlgorithm(kdf);
741     napi_value instance = nullptr;
742     napi_create_string_utf8(env, algoName, NAPI_AUTO_LENGTH, &instance);
743     return instance;
744 }
745 
KdfConstructor(napi_env env,napi_callback_info info)746 napi_value NapiKdf::KdfConstructor(napi_env env, napi_callback_info info)
747 {
748     napi_value thisVar = nullptr;
749     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
750     return thisVar;
751 }
752 
CreateJsKdf(napi_env env,napi_callback_info info)753 napi_value NapiKdf::CreateJsKdf(napi_env env, napi_callback_info info)
754 {
755     size_t expectedArgc = ARGS_SIZE_ONE;
756     size_t argc = expectedArgc;
757     napi_value argv[ARGS_SIZE_ONE] = { nullptr };
758     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
759     if (argc != expectedArgc) {
760         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "The input args num is invalid."));
761         LOGE("The input args num is invalid.");
762         return nullptr;
763     }
764     std::string algoName;
765     if (!GetStringFromJSParams(env, argv[PARAM0], algoName)) {
766         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "Failed to get algorithm."));
767         LOGE("Failed to get algorithm.");
768         return nullptr;
769     }
770     HcfKdf *kdf = nullptr;
771     HcfResult res = HcfKdfCreate(algoName.c_str(), &kdf);
772     if (res != HCF_SUCCESS) {
773         napi_throw(env, GenerateBusinessError(env, res, "create C obj failed."));
774         LOGE("create c kdf obj failed.");
775         return nullptr;
776     }
777     napi_value instance = nullptr;
778     napi_value constructor = nullptr;
779     napi_get_reference_value(env, classRef_, &constructor);
780     napi_new_instance(env, constructor, 0, nullptr, &instance);
781     NapiKdf *napiKdf = new (std::nothrow) NapiKdf(kdf);
782     if (napiKdf == nullptr) {
783         napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "new kdf napi obj failed."));
784         HcfObjDestroy(kdf);
785         LOGE("create kdf napi obj failed");
786         return nullptr;
787     }
788     napi_status status = napi_wrap(env, instance, napiKdf,
789         [](napi_env env, void *data, void *hint) {
790             NapiKdf *kdf = static_cast<NapiKdf *>(data);
791             delete kdf;
792             return;
793         }, nullptr, nullptr);
794     if (status != napi_ok) {
795         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to wrap NapiKdf obj!"));
796         delete napiKdf;
797         LOGE("failed to wrap NapiKdf obj!");
798         return nullptr;
799     }
800     return instance;
801 }
802 
DefineKdfJSClass(napi_env env,napi_value exports)803 void NapiKdf::DefineKdfJSClass(napi_env env, napi_value exports)
804 {
805     napi_property_descriptor desc[] = {
806         DECLARE_NAPI_FUNCTION("createKdf", NapiKdf::CreateJsKdf),
807     };
808     napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
809     napi_property_descriptor classDesc[] = {
810         DECLARE_NAPI_FUNCTION("generateSecret", NapiKdf::JsKdfGenerateSecret),
811         DECLARE_NAPI_FUNCTION("generateSecretSync", NapiKdf::JsKdfGenerateSecretSync),
812         {.utf8name = "algName", .getter = NapiKdf::JsGetAlgorithm},
813     };
814     napi_value constructor = nullptr;
815     napi_define_class(env, "Kdf", NAPI_AUTO_LENGTH, KdfConstructor, nullptr,
816         sizeof(classDesc) / sizeof(classDesc[0]), classDesc, &constructor);
817     napi_create_reference(env, constructor, 1, &classRef_);
818 }
819 } // CryptoFramework
820 } // OHOS
821