• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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