• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &params->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