• 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     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, &params->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