1 /*
2 * Copyright (c) 2021-2022 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 "huks_napi_decrypt.h"
17
18 #include "securec.h"
19
20 #include "hks_api.h"
21 #include "hks_log.h"
22 #include "hks_mem.h"
23 #include "hks_param.h"
24 #include "hks_type.h"
25 #include "huks_napi_common.h"
26
27 namespace HuksNapi {
28 namespace {
29 constexpr int HUKS_NAPI_DECRYPT_MIN_ARGS = 2;
30 constexpr int HUKS_NAPI_DECRYPT_MAX_ARGS = 3;
31 } // namespace
32
33 struct DecryptAsyncContextT {
34 napi_async_work asyncWork = nullptr;
35 napi_deferred deferred = nullptr;
36 napi_ref callback = nullptr;
37
38 int32_t result = 0;
39 struct HksBlob *keyAlias = nullptr;
40 struct HksParamSet *paramSet = nullptr;
41 struct HksBlob *cipherText = nullptr;
42 struct HksBlob *plainText = nullptr;
43 };
44 using DecryptAsyncContext = DecryptAsyncContextT *;
45
CreateDecryptAsyncContext()46 static DecryptAsyncContext CreateDecryptAsyncContext()
47 {
48 DecryptAsyncContext context = (DecryptAsyncContext)HksMalloc(sizeof(DecryptAsyncContextT));
49 if (context != nullptr) {
50 (void)memset_s(context, sizeof(DecryptAsyncContextT), 0, sizeof(DecryptAsyncContextT));
51 }
52 return context;
53 }
54
DeleteDecryptAsyncContext(napi_env env,DecryptAsyncContext & context)55 static void DeleteDecryptAsyncContext(napi_env env, DecryptAsyncContext &context)
56 {
57 if (context == nullptr) {
58 return;
59 }
60
61 if (context->asyncWork != nullptr) {
62 napi_delete_async_work(env, context->asyncWork);
63 context->asyncWork = nullptr;
64 }
65
66 if (context->callback != nullptr) {
67 napi_delete_reference(env, context->callback);
68 context->callback = nullptr;
69 }
70
71 if (context->keyAlias != nullptr) {
72 FreeHksBlob(context->keyAlias);
73 }
74
75 if (context->paramSet != nullptr) {
76 HksFreeParamSet(&context->paramSet);
77 }
78
79 if (context->cipherText != nullptr) {
80 if (context->cipherText->data != nullptr && context->cipherText->size != 0) {
81 (void)memset_s(context->cipherText->data, context->cipherText->size, 0, context->cipherText->size);
82 }
83 FreeHksBlob(context->cipherText);
84 }
85
86 if (context->plainText != nullptr) {
87 if (context->plainText->data != nullptr && context->plainText->size != 0) {
88 (void)memset_s(context->plainText->data, context->plainText->size, 0, context->plainText->size);
89 }
90 FreeHksBlob(context->plainText);
91 }
92
93 HksFree(context);
94 context = nullptr;
95 }
96
DecryptParseParams(napi_env env,napi_callback_info info,DecryptAsyncContext context)97 static napi_value DecryptParseParams(napi_env env, napi_callback_info info, DecryptAsyncContext context)
98 {
99 size_t argc = HUKS_NAPI_DECRYPT_MAX_ARGS;
100 napi_value argv[HUKS_NAPI_DECRYPT_MAX_ARGS] = {0};
101 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
102
103 if (argc < HUKS_NAPI_DECRYPT_MIN_ARGS) {
104 napi_throw_error(env, NULL, "invalid arguments");
105 HKS_LOG_E("no enough params");
106 return nullptr;
107 }
108
109 size_t index = 0;
110 napi_value result = ParseKeyAlias(env, argv[index], context->keyAlias);
111 if (result == nullptr) {
112 HKS_LOG_E("could not get alias");
113 return nullptr;
114 }
115
116 index++;
117 napi_value properties = nullptr;
118 napi_status status =
119 napi_get_named_property(env, argv[index], HKS_OPTIONS_PROPERTY_PROPERTIES.c_str(), &properties);
120 if (status != napi_ok || properties == nullptr) {
121 GET_AND_THROW_LAST_ERROR((env));
122 HKS_LOG_E("could not get property %s", HKS_OPTIONS_PROPERTY_PROPERTIES.c_str());
123 return nullptr;
124 }
125 result = ParseHksParamSet(env, properties, context->paramSet);
126 if (result == nullptr) {
127 HKS_LOG_E("could not get paramset");
128 return nullptr;
129 }
130 napi_value inData = nullptr;
131 status = napi_get_named_property(env, argv[index], HKS_OPTIONS_PROPERTY_INDATA.c_str(), &inData);
132 if (status != napi_ok || inData == nullptr) {
133 GET_AND_THROW_LAST_ERROR((env));
134 HKS_LOG_E("could not get property %s", HKS_OPTIONS_PROPERTY_INDATA.c_str());
135 return nullptr;
136 }
137 context->cipherText = (HksBlob *)HksMalloc(sizeof(HksBlob));
138 if (context->cipherText == nullptr) {
139 HKS_LOG_E("could not alloc memory");
140 return nullptr;
141 }
142 (void)memset_s(context->cipherText, sizeof(HksBlob), 0, sizeof(HksBlob));
143
144 if (GetUint8Array(env, inData, *context->cipherText) == nullptr) {
145 HKS_LOG_E("could not get indata");
146 return nullptr;
147 }
148
149 index++;
150 if (index < argc) {
151 context->callback = GetCallback(env, argv[index]);
152 }
153
154 return GetInt32(env, 0);
155 }
156
DecryptKeyWriteResult(napi_env env,DecryptAsyncContext context)157 static napi_value DecryptKeyWriteResult(napi_env env, DecryptAsyncContext context)
158 {
159 return GenerateHksResult(env,
160 context->result,
161 ((context->result == HKS_SUCCESS && context->plainText != nullptr) ? context->plainText->data : nullptr),
162 (context->result == HKS_SUCCESS && context->plainText != nullptr) ? context->plainText->size : 0);
163 }
164
DecryptAsyncWork(napi_env env,DecryptAsyncContext context)165 static napi_value DecryptAsyncWork(napi_env env, DecryptAsyncContext context)
166 {
167 napi_value promise = nullptr;
168 if (context->callback == nullptr) {
169 NAPI_CALL(env, napi_create_promise(env, &context->deferred, &promise));
170 }
171
172 napi_value resourceName = nullptr;
173 napi_create_string_latin1(env, "decryptAsyncWork", NAPI_AUTO_LENGTH, &resourceName);
174
175 napi_create_async_work(
176 env,
177 nullptr,
178 resourceName,
179 [](napi_env env, void *data) {
180 DecryptAsyncContext context = static_cast<DecryptAsyncContext>(data);
181
182 context->plainText = (HksBlob *)HksMalloc(sizeof(HksBlob));
183 if (context->plainText != NULL) {
184 context->plainText->data = (uint8_t *)HksMalloc(context->cipherText->size);
185 context->plainText->size = context->cipherText->size;
186 }
187
188 context->result = HksDecrypt(context->keyAlias, context->paramSet, context->cipherText, context->plainText);
189 },
190 [](napi_env env, napi_status status, void *data) {
191 DecryptAsyncContext context = static_cast<DecryptAsyncContext>(data);
192 napi_value result = DecryptKeyWriteResult(env, context);
193 if (result == nullptr) {
194 return;
195 }
196 if (context->callback != nullptr) {
197 CallAsyncCallback(env, context->callback, context->result, result);
198 } else {
199 napi_resolve_deferred(env, context->deferred, result);
200 }
201 DeleteDecryptAsyncContext(env, context);
202 },
203 (void *)context,
204 &context->asyncWork);
205
206 napi_status status = napi_queue_async_work(env, context->asyncWork);
207 if (status != napi_ok) {
208 GET_AND_THROW_LAST_ERROR((env));
209 DeleteDecryptAsyncContext(env, context);
210 HKS_LOG_E("could not queue async work");
211 return nullptr;
212 }
213
214 if (context->callback == nullptr) {
215 return promise;
216 } else {
217 return GetNull(env);
218 }
219 return nullptr;
220 }
221
HuksNapiDecrypt(napi_env env,napi_callback_info info)222 napi_value HuksNapiDecrypt(napi_env env, napi_callback_info info)
223 {
224 DecryptAsyncContext context = CreateDecryptAsyncContext();
225 if (context == nullptr) {
226 HKS_LOG_E("could not create context");
227 return nullptr;
228 }
229
230 napi_value result = DecryptParseParams(env, info, context);
231 if (result == nullptr) {
232 HKS_LOG_E("could not parse params");
233 DeleteDecryptAsyncContext(env, context);
234 return nullptr;
235 }
236
237 result = DecryptAsyncWork(env, context);
238 if (result == nullptr) {
239 HKS_LOG_E("could not start async work");
240 DeleteDecryptAsyncContext(env, context);
241 return nullptr;
242 }
243 return result;
244 }
245 } // namespace HuksNapi