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