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