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