1 /*
2 * Copyright (C) 2025 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 "scrypt_openssl.h"
17
18 #include "log.h"
19 #include "memory.h"
20 #include "result.h"
21 #include "securec.h"
22 #include "utils.h"
23 #include "openssl_adapter.h"
24 #include "openssl_common.h"
25 #include "openssl/kdf.h"
26 #include "detailed_scrypt_params.h"
27
28 #define SCRYPT_ALG_NAME "SCRYPT"
29
30 typedef struct {
31 unsigned char *salt;
32 int saltLen;
33 unsigned char *password;
34 int passwordLen;
35 uint64_t n;
36 uint64_t r;
37 uint64_t p;
38 uint64_t maxBytes;
39 unsigned char *out;
40 int outLen;
41 } HcfScryptData;
42
43 typedef struct {
44 HcfKdfSpi base;
45 HcfScryptData *kdfData;
46 } OpensslScryptSpiImpl;
47
EngineGetKdfClass(void)48 static const char *EngineGetKdfClass(void)
49 {
50 return "OpensslScrypt";
51 }
52
HcfClearAndFree(unsigned char * buf,int bufLen)53 static void HcfClearAndFree(unsigned char *buf, int bufLen)
54 {
55 // when buf == null, bufLen must be 0; in check func, bufLen >= 0
56 if (buf == NULL) {
57 return;
58 }
59 (void)memset_s(buf, bufLen, 0, bufLen);
60 HcfFree(buf);
61 }
62
FreeScryptData(HcfScryptData ** data)63 static void FreeScryptData(HcfScryptData **data)
64 {
65 if (data == NULL || *data == NULL) {
66 return;
67 }
68 HcfClearAndFree((*data)->out, (*data)->outLen);
69 (*data)->out = NULL;
70 (*data)->outLen = 0;
71 HcfClearAndFree((*data)->salt, (*data)->saltLen);
72 (*data)->salt = NULL;
73 (*data)->saltLen = 0;
74 HcfClearAndFree((*data)->password, (*data)->passwordLen);
75 (*data)->password = NULL;
76 (*data)->passwordLen = 0;
77 (void)memset_s(*data, sizeof(HcfScryptData), 0, sizeof(HcfScryptData));
78 HcfFree(*data);
79 *data = NULL;
80 }
81
EngineDestroyKdf(HcfObjectBase * self)82 static void EngineDestroyKdf(HcfObjectBase *self)
83 {
84 if (self == NULL) {
85 LOGE("Self ptr is NULL!");
86 return;
87 }
88 if (!HcfIsClassMatch(self, EngineGetKdfClass())) {
89 LOGE("Class is not match.");
90 return;
91 }
92 OpensslScryptSpiImpl *impl = (OpensslScryptSpiImpl *)self;
93 FreeScryptData(&(impl->kdfData));
94 HcfFree(self);
95 }
96
CheckScryptParams(HcfScryptParamsSpec * params)97 static bool CheckScryptParams(HcfScryptParamsSpec *params)
98 {
99 // openssl only support INT and blob attribute is size_t, it should samller than INT_MAX.
100 if (params->output.len > INT_MAX || params->salt.len > INT_MAX || params->passPhrase.len > INT_MAX) {
101 LOGE("beyond the length");
102 return false;
103 }
104 if (params->passPhrase.data == NULL && params->passPhrase.len == 0) {
105 LOGE("check params failed, passPhrase is NULL");
106 return false;
107 }
108 if (params->output.data == NULL || params->output.len == 0) {
109 LOGE("check params failed, output data is NULL");
110 return false;
111 }
112 if (params->salt.data == NULL && params->salt.len == 0) {
113 LOGD("empty salt");
114 }
115
116 return true;
117 }
118
GetScryptSaltFromSpec(HcfScryptData * data,HcfScryptParamsSpec * params)119 static bool GetScryptSaltFromSpec(HcfScryptData *data, HcfScryptParamsSpec *params)
120 {
121 if (params->salt.len == 0) {
122 LOGD("salt can be empty.");
123 return true;
124 }
125
126 data->salt = (unsigned char *)HcfMalloc(params->salt.len, 0);
127 if (data->salt == NULL) {
128 return false;
129 }
130 (void)memcpy_s(data->salt, params->salt.len, params->salt.data, params->salt.len);
131 data->saltLen = (int)params->salt.len;
132 return true;
133 }
134
GetScryptPasswordFromSpec(HcfScryptData * data,HcfScryptParamsSpec * params)135 static bool GetScryptPasswordFromSpec(HcfScryptData *data, HcfScryptParamsSpec *params)
136 {
137 if (params->passPhrase.data != NULL && params->passPhrase.len != 0) {
138 data->password = (unsigned char *)HcfMalloc(params->passPhrase.len, 0);
139 if (data->password == NULL) {
140 return false;
141 }
142 (void)memcpy_s(data->password, params->passPhrase.len, params->passPhrase.data, params->passPhrase.len);
143 data->passwordLen = (int)params->passPhrase.len;
144 } else {
145 data->passwordLen = 0;
146 data->password = NULL;
147 }
148 return true;
149 }
150
InitScryptData(OpensslScryptSpiImpl * self,HcfScryptParamsSpec * params)151 static HcfResult InitScryptData(OpensslScryptSpiImpl *self, HcfScryptParamsSpec *params)
152 {
153 HcfScryptData *data = (HcfScryptData *)HcfMalloc(sizeof(HcfScryptData), 0);
154 do {
155 if (data == NULL) {
156 LOGE("malloc data failed");
157 break;
158 }
159 if (!GetScryptSaltFromSpec(data, params)) {
160 LOGE("malloc salt failed!");
161 break;
162 }
163 if (!GetScryptPasswordFromSpec(data, params)) {
164 LOGE("malloc password failed!");
165 break;
166 }
167 data->out = (unsigned char *)HcfMalloc(params->output.len, 0);
168 if (data->out == NULL) {
169 LOGE("malloc out failed!");
170 break;
171 }
172 data->n = params->n;
173 data->p = params->p;
174 data->r = params->r;
175 data->maxBytes = params->maxMem;
176 data->outLen = (int)params->output.len;
177 self->kdfData = data;
178 return HCF_SUCCESS;
179 } while (0);
180 FreeScryptData(&data);
181 return HCF_ERR_MALLOC;
182 }
183
OpensslScrypt(OpensslScryptSpiImpl * self,HcfBlob * output)184 static HcfResult OpensslScrypt(OpensslScryptSpiImpl *self, HcfBlob *output)
185 {
186 EVP_KDF *kdf = NULL;
187 EVP_KDF_CTX *kctx = NULL;
188 // need set 7 params
189 OSSL_PARAM params[7] = {};
190 OSSL_PARAM *p = params;
191
192 kdf = OpensslEvpKdfFetch(NULL, "SCRYPT", NULL);
193 if (kdf == NULL) {
194 LOGE("kdf fetch failed");
195 return HCF_ERR_CRYPTO_OPERATION;
196 }
197
198 kctx = OpensslEvpKdfCtxNew(kdf);
199 OpensslEvpKdfFree(kdf);
200 if (kctx == NULL) {
201 LOGE("kdf ctx new failed");
202 return HCF_ERR_CRYPTO_OPERATION;
203 }
204
205 *p++ = OpensslOsslParamConstructOctetString("pass", self->kdfData->password, self->kdfData->passwordLen);
206 *p++ = OpensslOsslParamConstructOctetString("salt", self->kdfData->salt, self->kdfData->saltLen);
207 *p++ = OpensslOsslParamConstructUint64("n", &self->kdfData->n);
208 *p++ = OpensslOsslParamConstructUint64("r", &self->kdfData->r);
209 *p++ = OpensslOsslParamConstructUint64("p", &self->kdfData->p);
210 *p++ = OpensslOsslParamConstructUint64("maxmem_bytes", &self->kdfData->maxBytes);
211 *p = OpensslOsslParamConstructEnd();
212 if (OpensslEvpKdfDerive(kctx, output->data, output->len, params) <= 0) {
213 HcfPrintOpensslError();
214 LOGE("EVP_KDF_derive failed");
215 OpensslEvpKdfCtxFree(kctx);
216 return HCF_ERR_CRYPTO_OPERATION;
217 }
218 LOGD("scrypt success");
219 OpensslEvpKdfCtxFree(kctx);
220 return HCF_SUCCESS;
221 }
222
EngineGenerateSecret(HcfKdfSpi * self,HcfKdfParamsSpec * paramsSpec)223 static HcfResult EngineGenerateSecret(HcfKdfSpi *self, HcfKdfParamsSpec *paramsSpec)
224 {
225 if (self == NULL || paramsSpec == NULL) {
226 LOGE("Invalid input parameter.");
227 return HCF_INVALID_PARAMS;
228 }
229 if (!HcfIsClassMatch((HcfObjectBase *)self, EngineGetKdfClass())) {
230 return HCF_INVALID_PARAMS;
231 }
232 OpensslScryptSpiImpl *scryptImpl = (OpensslScryptSpiImpl *)self;
233 if (paramsSpec->algName == NULL || strcmp(paramsSpec->algName, SCRYPT_ALG_NAME) != 0) {
234 LOGE("Not scrypt paramsSpec");
235 return HCF_INVALID_PARAMS;
236 }
237 HcfScryptParamsSpec *params = (HcfScryptParamsSpec *)paramsSpec;
238 if (!CheckScryptParams(params)) {
239 LOGE("params error");
240 return HCF_INVALID_PARAMS;
241 }
242 HcfResult res = InitScryptData(scryptImpl, params);
243 if (res != HCF_SUCCESS) {
244 LOGE("InitCipherData failed!");
245 return res;
246 }
247 res = OpensslScrypt(scryptImpl, ¶ms->output);
248 FreeScryptData(&(scryptImpl->kdfData));
249 return res;
250 }
251
HcfKdfScryptSpiCreate(HcfKdfDeriveParams * params,HcfKdfSpi ** spiObj)252 HcfResult HcfKdfScryptSpiCreate(HcfKdfDeriveParams *params, HcfKdfSpi **spiObj)
253 {
254 if (params == NULL || spiObj == NULL) {
255 LOGE("Invalid input parameter.");
256 return HCF_INVALID_PARAMS;
257 }
258 OpensslScryptSpiImpl *returnSpiImpl = (OpensslScryptSpiImpl *)HcfMalloc(sizeof(OpensslScryptSpiImpl), 0);
259 if (returnSpiImpl == NULL) {
260 LOGE("Failed to allocate returnImpl memory!");
261 return HCF_ERR_MALLOC;
262 }
263 returnSpiImpl->base.base.getClass = EngineGetKdfClass;
264 returnSpiImpl->base.base.destroy = EngineDestroyKdf;
265 returnSpiImpl->base.generateSecret = EngineGenerateSecret;
266 *spiObj = (HcfKdfSpi *)returnSpiImpl;
267 return HCF_SUCCESS;
268 }
269