1/*
2 * Copyright (C) 2022-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 "rand.h"
17
18#include <limits.h>
19#include <securec.h>
20#include "rand_spi.h"
21#ifdef CRYPTO_MBEDTLS
22#include "mbedtls_rand.h"
23#else
24#include "rand_openssl.h"
25#endif
26#include "log.h"
27#include "config.h"
28#include "memory.h"
29#include "utils.h"
30
31typedef HcfResult (*HcfRandSpiCreateFunc)(HcfRandSpi **);
32
33typedef struct {
34    HcfRand base;
35
36    HcfRandSpi *spiObj;
37
38    const char *algoName;
39} HcfRandImpl;
40
41typedef struct {
42    char *algoName;
43
44    HcfRandSpiCreateFunc createSpiFunc;
45} HcfRandAbility;
46
47static const char *GetRandClass(void)
48{
49    return "Rand";
50}
51
52static const HcfRandAbility RAND_ABILITY_SET[] = {
53#ifdef CRYPTO_MBEDTLS
54    { "MbedtlsRand", MbedtlsRandSpiCreate }
55#else
56    { "OpensslRand", HcfRandSpiCreate }
57#endif
58};
59
60static HcfRandSpiCreateFunc FindAbility(const char *algoName)
61{
62    for (uint32_t i = 0; i < (sizeof(RAND_ABILITY_SET) / sizeof(RAND_ABILITY_SET[0])); i++) {
63        if (strcmp(RAND_ABILITY_SET[i].algoName, algoName) == 0) {
64            return RAND_ABILITY_SET[i].createSpiFunc;
65        }
66    }
67    LOGE("Algo not support! [Algo]: %s", algoName);
68    return NULL;
69}
70
71static HcfResult GenerateRandom(HcfRand *self, int32_t numBytes, HcfBlob *random)
72{
73    if ((self == NULL) || (random == NULL)) {
74        LOGE("Invalid params!");
75        return HCF_INVALID_PARAMS;
76    }
77    if (numBytes <= 0) {
78        LOGE("Invalid numBytes!");
79        return HCF_INVALID_PARAMS;
80    }
81    if (!HcfIsClassMatch((HcfObjectBase *)self, GetRandClass())) {
82        LOGE("Class is not match.");
83        return HCF_INVALID_PARAMS;
84    }
85    return ((HcfRandImpl *)self)->spiObj->engineGenerateRandom(
86        ((HcfRandImpl *)self)->spiObj, numBytes, random);
87}
88
89static const char *GetAlgoName(HcfRand *self)
90{
91    if (self == NULL) {
92        LOGE("The input self ptr is NULL!");
93        return NULL;
94    }
95    if (!HcfIsClassMatch((HcfObjectBase *)self, GetRandClass())) {
96        LOGE("Class is not match!");
97        return NULL;
98    }
99    return ((HcfRandImpl *)self)->spiObj->engineGetAlgoName(((HcfRandImpl *)self)->spiObj);
100}
101
102static HcfResult SetSeed(HcfRand *self, HcfBlob *seed)
103{
104    if ((self == NULL) || (!HcfIsBlobValid(seed)) || (seed->len > INT_MAX)) {
105        LOGE("The input self ptr is NULL!");
106        return HCF_INVALID_PARAMS;
107    }
108    if (!HcfIsClassMatch((HcfObjectBase *)self, GetRandClass())) {
109        LOGE("Class is not match.");
110        return HCF_INVALID_PARAMS;
111    }
112    ((HcfRandImpl *)self)->spiObj->engineSetSeed(
113        ((HcfRandImpl *)self)->spiObj, seed);
114    return HCF_SUCCESS;
115}
116
117static void HcfRandDestroy(HcfObjectBase *self)
118{
119    if (self == NULL) {
120        LOGE("The input self ptr is NULL!");
121        return;
122    }
123    if (!HcfIsClassMatch((HcfObjectBase *)self, GetRandClass())) {
124        LOGE("Class is not match.");
125        return;
126    }
127    HcfRandImpl *impl = (HcfRandImpl *)self;
128    HcfObjDestroy(impl->spiObj);
129    HcfFree(impl);
130}
131
132HcfResult HcfRandCreate(HcfRand **random)
133{
134    if (random == NULL) {
135        LOGE("Invalid input params while creating rand!");
136        return HCF_INVALID_PARAMS;
137    }
138#ifdef CRYPTO_MBEDTLS
139    HcfRandSpiCreateFunc createSpiFunc = FindAbility("MbedtlsRand");
140#else
141    HcfRandSpiCreateFunc createSpiFunc = FindAbility("OpensslRand");
142#endif
143    if (createSpiFunc == NULL) {
144        LOGE("Algo not supported!");
145        return HCF_NOT_SUPPORT;
146    }
147    HcfRandImpl *returnRandApi = (HcfRandImpl *)HcfMalloc(sizeof(HcfRandImpl), 0);
148    if (returnRandApi == NULL) {
149        LOGE("Failed to allocate Rand Obj memory!");
150        return HCF_ERR_MALLOC;
151    }
152    HcfRandSpi *spiObj = NULL;
153    HcfResult res = createSpiFunc(&spiObj);
154    if (res != HCF_SUCCESS) {
155        LOGE("Failed to create spi object!");
156        HcfFree(returnRandApi);
157        return res;
158    }
159    returnRandApi->base.base.getClass = GetRandClass;
160    returnRandApi->base.base.destroy = HcfRandDestroy;
161    returnRandApi->base.generateRandom = GenerateRandom;
162    returnRandApi->base.getAlgoName = GetAlgoName;
163    returnRandApi->base.setSeed = SetSeed;
164    returnRandApi->spiObj = spiObj;
165    *random = (HcfRand *)returnRandApi;
166    return HCF_SUCCESS;
167}