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 }