1 /*
2  * Copyright (C) 2023 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 "pbkdf2_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 "detailed_pbkdf2_params.h"
26 
27 #define PBKDF2_ALG_NAME "PBKDF2"
28 
29 typedef struct {
30     unsigned char *password;
31     int passwordLen;
32     int iter;
33     unsigned char *salt;
34     int saltLen;
35     unsigned char *out;
36     int outLen;
37 } HcfKdfData;
38 
39 typedef struct {
40     HcfKdfSpi base;
41     const EVP_MD *digestAlg;
42     HcfKdfData *kdfData;
43 } OpensslKdfSpiImpl;
44 
EngineGetKdfClass(void)45 static const char *EngineGetKdfClass(void)
46 {
47     return "OpensslKdf";
48 }
49 
HcfClearAndFreeUnsignedChar(unsigned char * blob,int len)50 static void HcfClearAndFreeUnsignedChar(unsigned char *blob, int len)
51 {
52     // when blob == null, len must be 0; in check func, len >= 0
53     if (blob == NULL) {
54         LOGD("The input blob is null, no need to free.");
55         return;
56     }
57     (void)memset_s(blob, len, 0, len);
58     HcfFree(blob);
59 }
60 
FreeKdfData(HcfKdfData ** data)61 static void FreeKdfData(HcfKdfData **data)
62 {
63     if (data == NULL || *data == NULL) {
64         return;
65     }
66     if ((*data)->out != NULL) {
67         HcfClearAndFreeUnsignedChar((*data)->out, (*data)->outLen);
68         (*data)->out = NULL;
69         (*data)->outLen = 0;
70     }
71     if ((*data)->salt != NULL) {
72         HcfClearAndFreeUnsignedChar((*data)->salt, (*data)->saltLen);
73         (*data)->salt = NULL;
74         (*data)->saltLen = 0;
75     }
76     if ((*data)->password != NULL) {
77         HcfClearAndFreeUnsignedChar((*data)->password, (*data)->passwordLen);
78         (*data)->password = NULL;
79         (*data)->passwordLen = 0;
80     }
81     HcfFree(*data);
82     *data = NULL;
83 }
84 
EngineDestroyKdf(HcfObjectBase * self)85 static void EngineDestroyKdf(HcfObjectBase *self)
86 {
87     if (self == NULL) {
88         LOGE("Self ptr is NULL!");
89         return;
90     }
91     if (!HcfIsClassMatch(self, EngineGetKdfClass())) {
92         LOGE("Class is not match.");
93         return;
94     }
95     OpensslKdfSpiImpl *impl = (OpensslKdfSpiImpl *)self;
96     FreeKdfData(&(impl->kdfData));
97     impl->digestAlg = NULL;
98     HcfFree(self);
99 }
100 
CheckPBKDF2Params(HcfPBKDF2ParamsSpec * params)101 static bool CheckPBKDF2Params(HcfPBKDF2ParamsSpec *params)
102 {
103     if (params->iterations < 1) {
104         LOGE("invalid kdf iter");
105         return false;
106     }
107     // openssl only support INT and blob attribute is size_t, it should samller than INT_MAX.
108     if (params->output.len > INT_MAX || params->salt.len > INT_MAX || params->password.len > INT_MAX) {
109         LOGE("beyond the length");
110         return false;
111     }
112     // when params password == nullptr, the size will be set 0 by openssl;
113     if (params->output.data == NULL || params->output.len == 0) {
114         LOGE("invalid output");
115         return false;
116     }
117     if (params->salt.data == NULL && params->salt.len == 0) {
118         LOGD("empty salt");
119         return true;
120     }
121     if (params->salt.data != NULL && params->salt.len != 0) {
122         return true;
123     }
124     return false;
125 }
126 
GetPBKDF2PasswordFromSpec(HcfKdfData * data,HcfPBKDF2ParamsSpec * params)127 static bool GetPBKDF2PasswordFromSpec(HcfKdfData *data, HcfPBKDF2ParamsSpec *params)
128 {
129     if (params->password.data != NULL && params->password.len != 0) {
130         data->password = (unsigned char *)HcfMalloc(params->password.len, 0);
131         if (data->password == NULL) {
132             return false;
133         }
134         (void)memcpy_s(data->password, params->password.len, params->password.data, params->password.len);
135         data->passwordLen = params->password.len;
136     } else {
137         data->passwordLen = 0;
138         data->password = NULL;
139     }
140     return true;
141 }
142 
GetPBKDF2SaltFromSpec(HcfKdfData * data,HcfPBKDF2ParamsSpec * params)143 static bool GetPBKDF2SaltFromSpec(HcfKdfData *data, HcfPBKDF2ParamsSpec *params)
144 {
145     if (params->salt.data != NULL) {
146         data->salt = (unsigned char *)HcfMalloc(params->salt.len, 0);
147         if (data->salt == NULL) {
148             return false;
149         }
150         (void)memcpy_s(data->salt, params->salt.len, params->salt.data, params->salt.len);
151         data->saltLen = params->salt.len;
152     } else {
153         data->salt = NULL;
154         data->saltLen = 0;
155     }
156     return true;
157 }
158 
159 
InitPBKDF2Data(OpensslKdfSpiImpl * self,HcfPBKDF2ParamsSpec * params)160 static HcfResult InitPBKDF2Data(OpensslKdfSpiImpl *self, HcfPBKDF2ParamsSpec *params)
161 {
162     HcfKdfData *data = (HcfKdfData *)HcfMalloc(sizeof(HcfKdfData), 0);
163     do {
164         if (data == NULL) {
165             LOGE("malloc data failed");
166             break;
167         }
168         if (!GetPBKDF2PasswordFromSpec(data, params)) {
169             LOGE("password malloc failed!");
170             break;
171         }
172         if (!GetPBKDF2SaltFromSpec(data, params)) {
173             LOGE("salt malloc failed!");
174             break;
175         }
176         data->out = (unsigned char *)HcfMalloc(params->output.len, 0);
177         if (data->out == NULL) {
178             LOGE("out malloc failed!");
179             break;
180         }
181         data->outLen = params->output.len;
182         data->iter = params->iterations;
183         self->kdfData = data;
184         return HCF_SUCCESS;
185     } while (0);
186     FreeKdfData(&data);
187     return HCF_ERR_MALLOC;
188 }
189 
OpensslPBKDF2(OpensslKdfSpiImpl * self,HcfPBKDF2ParamsSpec * params)190 static HcfResult OpensslPBKDF2(OpensslKdfSpiImpl *self, HcfPBKDF2ParamsSpec *params)
191 {
192     HcfKdfData *data = self->kdfData;
193     if (OpensslPkcs5Pbkdf2Hmac((char *)(data->password), data->passwordLen,
194         data->salt, data->saltLen, data->iter, self->digestAlg, data->outLen, data->out) != HCF_OPENSSL_SUCCESS) {
195         HcfPrintOpensslError();
196         LOGD("[error] pbkdf2 openssl failed!");
197         return HCF_ERR_CRYPTO_OPERATION;
198     }
199     (void)memcpy_s(params->output.data, data->outLen, data->out, data->outLen);
200     return HCF_SUCCESS;
201 }
202 
EngineGenerateSecret(HcfKdfSpi * self,HcfKdfParamsSpec * paramsSpec)203 static HcfResult EngineGenerateSecret(HcfKdfSpi *self, HcfKdfParamsSpec *paramsSpec)
204 {
205     if (self == NULL || paramsSpec == NULL) {
206         LOGE("Invalid input parameter.");
207         return HCF_INVALID_PARAMS;
208     }
209     if (!HcfIsClassMatch((HcfObjectBase *)self, EngineGetKdfClass())) {
210         return HCF_INVALID_PARAMS;
211     }
212     OpensslKdfSpiImpl *pbkdf2Impl = (OpensslKdfSpiImpl *)self;
213     if (paramsSpec->algName == NULL || strcmp(paramsSpec->algName, PBKDF2_ALG_NAME) != 0) {
214         LOGE("Not pbkdf2 paramsSpec");
215         return HCF_INVALID_PARAMS;
216     }
217     HcfPBKDF2ParamsSpec *params = (HcfPBKDF2ParamsSpec *)paramsSpec;
218     if (!CheckPBKDF2Params(params)) {
219         LOGE("params error");
220         return HCF_INVALID_PARAMS;
221     }
222     HcfResult res = InitPBKDF2Data(pbkdf2Impl, params);
223     if (res != HCF_SUCCESS) {
224         LOGE("InitCipherData failed!");
225         return HCF_INVALID_PARAMS;
226     }
227     res = OpensslPBKDF2(pbkdf2Impl, params);
228     FreeKdfData(&(pbkdf2Impl->kdfData));
229     return res;
230 }
231 
HcfKdfPBKDF2SpiCreate(HcfKdfDeriveParams * params,HcfKdfSpi ** spiObj)232 HcfResult HcfKdfPBKDF2SpiCreate(HcfKdfDeriveParams *params, HcfKdfSpi **spiObj)
233 {
234     if (params == NULL || spiObj == NULL) {
235         LOGE("Invalid input parameter.");
236         return HCF_INVALID_PARAMS;
237     }
238     EVP_MD *md = NULL;
239     HcfResult res = GetOpensslDigestAlg(params->md, &md);
240     if (res != HCF_SUCCESS || md == NULL) {
241         LOGE("get md failed");
242         return HCF_INVALID_PARAMS;
243     }
244     OpensslKdfSpiImpl *returnSpiImpl = (OpensslKdfSpiImpl *)HcfMalloc(sizeof(OpensslKdfSpiImpl), 0);
245     if (returnSpiImpl == NULL) {
246         LOGE("Failed to allocate returnImpl memory!");
247         return HCF_ERR_MALLOC;
248     }
249     returnSpiImpl->base.base.getClass = EngineGetKdfClass;
250     returnSpiImpl->base.base.destroy = EngineDestroyKdf;
251     returnSpiImpl->base.generateSecret = EngineGenerateSecret;
252     returnSpiImpl->digestAlg = md;
253     *spiObj = (HcfKdfSpi *)returnSpiImpl;
254     return HCF_SUCCESS;
255 }