1/*
2 * Copyright (C) 2023-2024 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 "kdf.h"
17
18#include <securec.h>
19#include "memory.h"
20
21#include "config.h"
22#include "kdf_spi.h"
23#include "log.h"
24#include "params_parser.h"
25#include "pbkdf2_openssl.h"
26#include "hkdf_openssl.h"
27#include "utils.h"
28
29typedef HcfResult (*HcfKdfSpiCreateFunc)(HcfKdfDeriveParams *, HcfKdfSpi **);
30
31typedef struct {
32    HcfKdf base;
33    HcfKdfSpi *spiObj;
34    char algoName[HCF_MAX_ALGO_NAME_LEN];
35} HcfKdfImpl;
36
37typedef struct {
38    HcfAlgValue algo;
39    HcfKdfSpiCreateFunc createSpiFunc;
40} HcfKdfGenAbility;
41
42static void SetKdfType(HcfAlgParaValue value, HcfKdfDeriveParams *kdf)
43{
44    switch (value) {
45        case HCF_ALG_PBKDF2_DEFAULT:
46            kdf->algo = HCF_ALG_PKBDF2;
47            break;
48        case HCF_ALG_HKDF_DEFAULT:
49            kdf->algo = HCF_ALG_HKDF;
50            break;
51        default:
52            LOGE("Invalid algo %u.", value);
53            break;
54    }
55}
56
57static void SetDigest(HcfAlgParaValue value, HcfKdfDeriveParams *kdf)
58{
59    kdf->md = value;
60}
61
62static void SetMode(HcfAlgParaValue value, HcfKdfDeriveParams *kdf)
63{
64    kdf->mode = value;
65}
66
67static HcfResult ParseKdfParams(const HcfParaConfig *config, void *params)
68{
69    if (config == NULL || params == NULL) {
70        LOGE("Invalid Kdf params");
71        return HCF_INVALID_PARAMS;
72    }
73    HcfResult ret = HCF_SUCCESS;
74    HcfKdfDeriveParams *paramsObj = (HcfKdfDeriveParams *)params;
75    LOGD("Set Parameter: %s", config->tag);
76    switch (config->paraType) {
77        case HCF_ALG_TYPE:
78            SetKdfType(config->paraValue, paramsObj);
79            break;
80        case HCF_ALG_DIGEST:
81            SetDigest(config->paraValue, paramsObj);
82            break;
83        case HCF_ALG_MODE:
84            SetMode(config->paraValue, paramsObj);
85            break;
86        default:
87            ret = HCF_INVALID_PARAMS;
88            break;
89    }
90    return ret;
91}
92
93static const HcfKdfGenAbility KDF_ABILITY_SET[] = {
94    { HCF_ALG_PKBDF2, HcfKdfPBKDF2SpiCreate },
95    { HCF_ALG_HKDF, HcfKdfHkdfSpiCreate},
96};
97
98static HcfKdfSpiCreateFunc FindAbility(HcfKdfDeriveParams* params)
99{
100    for (uint32_t i = 0; i < (sizeof(KDF_ABILITY_SET) / sizeof(KDF_ABILITY_SET[0])); i++) {
101        if (KDF_ABILITY_SET[i].algo == params->algo) {
102            return KDF_ABILITY_SET[i].createSpiFunc;
103        }
104    }
105    LOGE("Algo not support! [Algo]: %d", params->algo);
106    return NULL;
107}
108
109// export interfaces
110static const char *GetKdfGeneratorClass(void)
111{
112    return "HcfKdfGenerator";
113}
114
115static const char *GetAlgoName(HcfKdf *self)
116{
117    if (self == NULL) {
118        LOGE("The input self ptr is NULL!");
119        return NULL;
120    }
121    if (!HcfIsClassMatch((HcfObjectBase *)self, GetKdfGeneratorClass())) {
122        return NULL;
123    }
124    return ((HcfKdfImpl *)self)->algoName;
125}
126
127static HcfResult GenerateSecret(HcfKdf *self, HcfKdfParamsSpec *paramsSpec)
128{
129    if (self == NULL || paramsSpec == NULL) {
130        LOGE("Invalid input parameter.");
131        return HCF_INVALID_PARAMS;
132    }
133    if (!HcfIsClassMatch((HcfObjectBase *)self, GetKdfGeneratorClass())) {
134        return HCF_INVALID_PARAMS;
135    }
136
137    HcfKdfImpl *tmp = (HcfKdfImpl *)self;
138    return tmp->spiObj->generateSecret(tmp->spiObj, paramsSpec);
139}
140
141static void DestroyKdf(HcfObjectBase *self)
142{
143    if (self == NULL) {
144        return;
145    }
146    if (!HcfIsClassMatch((HcfObjectBase *)self, GetKdfGeneratorClass())) {
147        return;
148    }
149    HcfKdfImpl *impl = (HcfKdfImpl *)self;
150    HcfObjDestroy(impl->spiObj);
151    impl->spiObj = NULL;
152    HcfFree(impl);
153}
154
155HcfResult HcfKdfCreate(const char *transformation, HcfKdf **returnObj)
156{
157    if ((!HcfIsStrValid(transformation, HCF_MAX_ALGO_NAME_LEN)) || (returnObj == NULL)) {
158        LOGE("Invalid input params while creating kdf!");
159        return HCF_INVALID_PARAMS;
160    }
161
162    HcfKdfDeriveParams params = { 0 };
163    if (ParseAndSetParameter(transformation, &params, ParseKdfParams) != HCF_SUCCESS) {
164        LOGE("Failed to parse params!");
165        return HCF_INVALID_PARAMS;
166    }
167    HcfKdfSpiCreateFunc createSpiFunc = FindAbility(&params);
168    if (createSpiFunc == NULL) {
169        LOGE("Not support this KDF func");
170        return HCF_NOT_SUPPORT;
171    }
172
173    HcfKdfImpl *returnGenerator = (HcfKdfImpl *)HcfMalloc(sizeof(HcfKdfImpl), 0);
174    if (returnGenerator == NULL) {
175        LOGE("Failed to allocate returnGenerator memory!");
176        return HCF_ERR_MALLOC;
177    }
178    if (strcpy_s(returnGenerator->algoName, HCF_MAX_ALGO_NAME_LEN, transformation) != EOK) {
179        LOGE("Failed to copy algoName!");
180        HcfFree(returnGenerator);
181        return HCF_INVALID_PARAMS;
182    }
183    HcfKdfSpi *spiObj = NULL;
184    HcfResult res = createSpiFunc(&params, &spiObj);
185    if (res != HCF_SUCCESS) {
186        LOGE("Failed to create spi object!");
187        HcfFree(returnGenerator);
188        return res;
189    }
190    returnGenerator->base.base.destroy = DestroyKdf;
191    returnGenerator->base.base.getClass = GetKdfGeneratorClass;
192    returnGenerator->base.generateSecret = GenerateSecret;
193    returnGenerator->base.getAlgorithm = GetAlgoName;
194    returnGenerator->spiObj = spiObj;
195
196    *returnObj = (HcfKdf *)returnGenerator;
197    return HCF_SUCCESS;
198}
199