1 /*
2 * Copyright (C) 2021 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 #ifdef MBEDTLS_INCLUDED
17 #include "nstackx_mbedtls.h"
18 #include "nstackx_error.h"
19 #include "nstackx_log.h"
20 #include "securec.h"
21
22 #define TAG "nStackXMbedtls"
23
24 static pthread_mutex_t g_randomLock = PTHREAD_MUTEX_INITIALIZER;
25 static mbedtls_entropy_context g_mbedtlsEntropy;
26 static mbedtls_ctr_drbg_context g_mbedtlsCtrDrbg;
27
CreateCryptCtx(void)28 MBEDTLS_CTX *CreateCryptCtx(void)
29 {
30 LOGI(TAG, "mbedtls CreateCryptCtx");
31 return &g_mbedtlsCtrDrbg;
32 }
33
ClearCryptCtx(MBEDTLS_CTX * ctx)34 void ClearCryptCtx(MBEDTLS_CTX *ctx)
35 {
36 (void)ctx;
37 return;
38 }
39
MbedtlsGetRandomSeed(void)40 static int32_t MbedtlsGetRandomSeed(void)
41 {
42 static int inited = 0;
43
44 if (inited == 0) {
45 mbedtls_ctr_drbg_init(&g_mbedtlsCtrDrbg);
46 mbedtls_entropy_init(&g_mbedtlsEntropy);
47 int ret = mbedtls_ctr_drbg_seed(&g_mbedtlsCtrDrbg, mbedtls_entropy_func, &g_mbedtlsEntropy, NULL, 0);
48 if (ret != 0) {
49 LOGE(TAG, "gen random seed error, ret[%d]", ret);
50 return NSTACKX_EFAILED;
51 }
52 inited = 1;
53 }
54 return NSTACKX_EOK;
55 }
56
GetRandBytes(uint8_t * buf,uint32_t len)57 int32_t GetRandBytes(uint8_t *buf, uint32_t len)
58 {
59 int ret;
60 if (buf == NULL || len == 0) {
61 LOGE(TAG, "buf is NULL or illegal length %u", len);
62 return NSTACKX_EFAILED;
63 }
64
65 if (pthread_mutex_lock(&g_randomLock) != 0) {
66 LOGE(TAG, "lock failed");
67 return NSTACKX_EFAILED;
68 }
69 if (MbedtlsGetRandomSeed() != NSTACKX_EOK) {
70 LOGE(TAG, "MbedtlsGetRandomSeed error");
71 if (pthread_mutex_unlock(&g_randomLock) != 0) {
72 LOGE(TAG, "unlock failed");
73 }
74 return NSTACKX_EFAILED;
75 }
76
77 ret = mbedtls_ctr_drbg_random(&g_mbedtlsCtrDrbg, buf, len);
78 if (ret != 0) {
79 LOGE(TAG, "gen random error, ret[%d]", ret);
80 ret = NSTACKX_EFAILED;
81 }
82
83 if (pthread_mutex_unlock(&g_randomLock) != 0) {
84 LOGE(TAG, "unlock failed");
85 return NSTACKX_EFAILED;
86 }
87 return ret;
88 }
89
MbedAesGcmEncrypt(const CryptPara * cryptPara,const uint8_t * inBuf,uint32_t inLen,uint8_t * outBuf,uint32_t outLen)90 static uint32_t MbedAesGcmEncrypt(const CryptPara *cryptPara, const uint8_t *inBuf,
91 uint32_t inLen, uint8_t *outBuf, uint32_t outLen)
92 {
93 if ((cryptPara == NULL) || (inBuf == NULL) || (inLen == 0) || outBuf == NULL ||
94 (outLen < inLen + GCM_ADDED_LEN)) {
95 LOGE(TAG, "Encrypt invalid para");
96 return 0;
97 }
98
99 int ret;
100 unsigned char tagBuf[GCM_TAG_LENGTH] = {0};
101 mbedtls_gcm_context aesContext;
102 mbedtls_gcm_init(&aesContext);
103
104 ret = mbedtls_gcm_setkey(&aesContext, MBEDTLS_CIPHER_ID_AES, cryptPara->key, cryptPara->keylen * KEY_BITS_UNIT);
105 if (ret != 0) {
106 mbedtls_gcm_free(&aesContext);
107 return 0;
108 }
109
110 ret = mbedtls_gcm_crypt_and_tag(&aesContext, MBEDTLS_GCM_ENCRYPT, inLen, cryptPara->iv,
111 GCM_IV_LENGTH, cryptPara->aad, cryptPara->aadLen, inBuf, outBuf, GCM_TAG_LENGTH, tagBuf);
112 if (ret != 0) {
113 mbedtls_gcm_free(&aesContext);
114 return 0;
115 }
116
117 if (memcpy_s(outBuf + inLen, outLen - inLen, tagBuf, GCM_TAG_LENGTH) != 0) {
118 mbedtls_gcm_free(&aesContext);
119 return 0;
120 }
121
122 if (memcpy_s(outBuf + inLen + GCM_TAG_LENGTH, GCM_IV_LENGTH, cryptPara->iv, GCM_IV_LENGTH) != 0) {
123 mbedtls_gcm_free(&aesContext);
124 return 0;
125 }
126
127 mbedtls_gcm_free(&aesContext);
128 return (inLen + GCM_ADDED_LEN);
129 }
130
MbedChaChaEncrypt(const CryptPara * cryptPara,const uint8_t * inBuf,uint32_t inLen,uint8_t * outBuf,uint32_t outLen)131 static uint32_t MbedChaChaEncrypt(const CryptPara *cryptPara, const uint8_t *inBuf,
132 uint32_t inLen, uint8_t *outBuf, uint32_t outLen)
133 {
134 unsigned char tagBuf[GCM_TAG_LENGTH] = {0};
135 mbedtls_chachapoly_context ctx;
136 mbedtls_chachapoly_init(&ctx);
137 int ret = mbedtls_chachapoly_setkey(&ctx, cryptPara->key);
138 if (ret != 0) {
139 LOGE(TAG, "set key fail, ret %d", ret);
140 mbedtls_chachapoly_free(&ctx);
141 return 0;
142 }
143 ret = mbedtls_chachapoly_encrypt_and_tag(&ctx, inLen, cryptPara->iv,
144 cryptPara->aad, cryptPara->aadLen, inBuf, outBuf, tagBuf);
145 if (ret != 0) {
146 LOGE(TAG, "encrypt data fail, ret %d", ret);
147 mbedtls_chachapoly_free(&ctx);
148 return 0;
149 }
150
151 if (memcpy_s(outBuf + inLen, outLen - inLen, tagBuf, GCM_TAG_LENGTH) != 0) {
152 mbedtls_chachapoly_free(&ctx);
153 return 0;
154 }
155
156 if (memcpy_s(outBuf + inLen + GCM_TAG_LENGTH, GCM_IV_LENGTH, cryptPara->iv, GCM_IV_LENGTH) != 0) {
157 mbedtls_chachapoly_free(&ctx);
158 return 0;
159 }
160
161 mbedtls_chachapoly_free(&ctx);
162 return (inLen + GCM_ADDED_LEN);
163 }
164
AesGcmEncrypt(const uint8_t * inBuf,uint32_t inLen,CryptPara * cryptPara,uint8_t * outBuf,uint32_t outLen)165 uint32_t AesGcmEncrypt(const uint8_t *inBuf, uint32_t inLen, CryptPara *cryptPara, uint8_t *outBuf,
166 uint32_t outLen)
167 {
168 if (outLen <= GCM_ADDED_LEN || cryptPara == NULL || outBuf == NULL) {
169 return 0;
170 }
171 cryptPara->ivLen = GCM_IV_LENGTH;
172
173 if (GetRandBytes(cryptPara->iv, cryptPara->ivLen) != NSTACKX_EOK) {
174 LOGE(TAG, "get rand iv failed");
175 return 0;
176 }
177 if (cryptPara->cipherType == CIPHER_CHACHA) {
178 return MbedChaChaEncrypt(cryptPara, inBuf, inLen, outBuf, outLen);
179 }
180 return MbedAesGcmEncrypt(cryptPara, inBuf, inLen, outBuf, outLen);
181 }
182
MbedAesGcmDecrypt(const CryptPara * cryptPara,uint8_t * inBuf,uint32_t inLen,uint8_t * outBuf,uint32_t outLen)183 static uint32_t MbedAesGcmDecrypt(const CryptPara *cryptPara, uint8_t *inBuf, uint32_t inLen,
184 uint8_t *outBuf, uint32_t outLen)
185 {
186 if ((cryptPara == NULL) || (inBuf == NULL) || (inLen <= GCM_ADDED_LEN) || outBuf == NULL ||
187 (outLen < inLen - GCM_ADDED_LEN)) {
188 LOGE(TAG, "Decrypt invalid para");
189 return 0;
190 }
191
192 mbedtls_gcm_context aesContext;
193 mbedtls_gcm_init(&aesContext);
194 int ret = mbedtls_gcm_setkey(&aesContext, MBEDTLS_CIPHER_ID_AES, cryptPara->key,
195 cryptPara->keylen * KEY_BITS_UNIT);
196 if (ret != 0) {
197 LOGE(TAG, "Decrypt mbedtls_gcm_setkey fail");
198 mbedtls_gcm_free(&aesContext);
199 return 0;
200 }
201
202 int actualPlainLen = inLen - GCM_ADDED_LEN;
203 ret = mbedtls_gcm_auth_decrypt(&aesContext, inLen - GCM_ADDED_LEN, cryptPara->iv, GCM_IV_LENGTH,
204 cryptPara->aad, cryptPara->aadLen, inBuf + actualPlainLen, GCM_TAG_LENGTH, inBuf, outBuf);
205 if (ret != 0) {
206 LOGE(TAG, "Decrypt mbedtls_gcm_auth_decrypt fail");
207 mbedtls_gcm_free(&aesContext);
208 return 0;
209 }
210
211 mbedtls_gcm_free(&aesContext);
212 return actualPlainLen;
213 }
214
MbedChaChaDecrypt(const CryptPara * cryptPara,uint8_t * inBuf,uint32_t inLen,uint8_t * outBuf,uint32_t outLen)215 static uint32_t MbedChaChaDecrypt(const CryptPara *cryptPara, uint8_t *inBuf, uint32_t inLen,
216 uint8_t *outBuf, uint32_t outLen)
217 {
218 mbedtls_chachapoly_context ctx;
219 mbedtls_chachapoly_init(&ctx);
220 int ret = mbedtls_chachapoly_setkey(&ctx, cryptPara->key);
221 if (ret != 0) {
222 LOGE(TAG, "set key fail, ret %d", ret);
223 mbedtls_chachapoly_free(&ctx);
224 return NSTACKX_EFAILED;
225 }
226
227 uint32_t actualPlainLen = inLen - GCM_ADDED_LEN;
228 ret = mbedtls_chachapoly_encrypt_and_tag(&ctx, inLen - GCM_ADDED_LEN, cryptPara->iv,
229 cryptPara->aad, cryptPara->aadLen, inBuf, outBuf, inBuf + actualPlainLen);
230 if (ret != 0) {
231 LOGE(TAG, "Decrypt mbedtls_chachapoly_encrypt_and_tag fail");
232 mbedtls_chachapoly_free(&ctx);
233 return 0;
234 }
235
236 mbedtls_chachapoly_free(&ctx);
237 return actualPlainLen;
238 }
239
AesGcmDecrypt(uint8_t * inBuf,uint32_t inLen,CryptPara * cryptPara,uint8_t * outBuf,uint32_t outLen)240 uint32_t AesGcmDecrypt(uint8_t *inBuf, uint32_t inLen, CryptPara *cryptPara, uint8_t *outBuf,
241 uint32_t outLen)
242 {
243 if (inLen <= GCM_ADDED_LEN || outLen < inLen - GCM_ADDED_LEN || cryptPara == NULL ||
244 inBuf == NULL || outBuf == NULL) {
245 return 0;
246 }
247 cryptPara->ivLen = GCM_IV_LENGTH;
248 if (memcpy_s(cryptPara->iv, cryptPara->ivLen, inBuf + (inLen - GCM_IV_LENGTH), GCM_IV_LENGTH) != EOK) {
249 return 0;
250 }
251
252 if (cryptPara->cipherType == CIPHER_CHACHA) {
253 return MbedChaChaDecrypt(cryptPara, inBuf, inLen, outBuf, outLen);
254 }
255 return MbedAesGcmDecrypt(cryptPara, inBuf, inLen, outBuf, outLen);
256 }
257
IsCryptoIncluded(void)258 uint8_t IsCryptoIncluded(void)
259 {
260 return NSTACKX_TRUE;
261 }
262
QueryCipherSupportByName(char * name)263 uint8_t QueryCipherSupportByName(char *name)
264 {
265 int ret = mbedtls_version_check_feature(name);
266 if (ret != NSTACKX_EFAILED) {
267 return NSTACKX_TRUE;
268 }
269
270 LOGI(TAG, "devices no support %s", name);
271 return NSTACKX_FALSE;
272 }
273 #endif // MBEDTLS_INCLUDED
274