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