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], ¶msSpec)) {
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