• 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 #include "nstackx_openssl.h"
17 #include "nstackx_error.h"
18 #include "nstackx_log.h"
19 #include "securec.h"
20 
21 #if defined(SSL_AND_CRYPTO_INCLUDED) && defined(NSTACKX_WITH_LINUX_STANDARD)
22 #include <sys/auxv.h>
23 #endif
24 
25 #ifdef BUILD_FOR_WINDOWS
26 #if (defined(_MSC_VER) && !defined(__clang__)) || \
27     ((defined(__GNUC__) || defined(__clang__)) && defined(__AES__) && defined(__PCLMUL__))
28 #if defined(__GNC__)
29 #include <cpuid.h>
30 #elif define(_MSC_VER)
31 #include <intrin.h>
32 #endif
33 #include <immintrin.h>
34 
35 #define WINDOWS_AESNI_SUPPORT
36 #define WIN_AESNI_ECI_IDX 2
37 #endif
38 
39 #ifndef bit_AES
40 #define bit_AES (1<<25)
41 #endif
42 #endif // BUILD_FOR_WINDOWS
43 
44 #define TAG "nStackXDFile"
45 
46 #ifdef SSL_AND_CRYPTO_INCLUDED
GetRandBytes(uint8_t * buf,uint32_t len)47 int32_t GetRandBytes(uint8_t *buf, uint32_t len)
48 {
49     if (buf == NULL || len == 0) {
50         LOGE(TAG, "buf is NULL or illegal length %u", len);
51         return NSTACKX_EFAILED;
52     }
53     if (RAND_bytes(buf, (int)len) != 1) {
54         LOGE(TAG, "get rand_bytes failed");
55         return NSTACKX_EFAILED;
56     }
57     return NSTACKX_EOK;
58 }
59 
CreateCryptCtx()60 EVP_CIPHER_CTX *CreateCryptCtx()
61 {
62     LOGI(TAG, "openssl CreateCryptCtx");
63     EVP_CIPHER_CTX *ctx = NULL;
64     ctx = EVP_CIPHER_CTX_new();
65     return ctx;
66 }
67 
ClearCryptCtx(EVP_CIPHER_CTX * ctx)68 void ClearCryptCtx(EVP_CIPHER_CTX *ctx)
69 {
70     if (ctx != NULL) {
71         EVP_CIPHER_CTX_free(ctx);
72     }
73 }
GetCipher(CryptPara * cryptPara)74 static const EVP_CIPHER *GetCipher(CryptPara *cryptPara)
75 {
76     if (cryptPara->cipherType == CIPHER_CHACHA) {
77         return EVP_get_cipherbyname(CHACHA20_POLY1305_NAME);
78     } else if (cryptPara->cipherType == CIPHER_AES_GCM) {
79         switch (cryptPara->keylen) {
80             case AES_128_KEY_LENGTH:
81                 return EVP_aes_128_gcm();
82                 break;
83             case AES_192_KEY_LENGTH:
84                 return EVP_aes_192_gcm();
85                 break;
86             case AES_256_KEY_LENGTH:
87                 return EVP_aes_256_gcm();
88                 break;
89             default:
90                 return NULL;
91         }
92     }
93     return NULL;
94 }
InitEncryptCtx(CryptPara * cryptPara)95 static int32_t InitEncryptCtx(CryptPara *cryptPara)
96 {
97     int32_t length;
98     const EVP_CIPHER *cipher = GetCipher(cryptPara);
99 
100     if (cipher == NULL ||cryptPara->aadLen == 0 || cryptPara->ctx == NULL) {
101         return NSTACKX_EFAILED;
102     }
103 
104     cryptPara->ivLen = GCM_IV_LENGTH;
105 
106     if (GetRandBytes(cryptPara->iv, cryptPara->ivLen) != NSTACKX_EOK) {
107         LOGE(TAG, "get rand iv failed");
108         return NSTACKX_EFAILED;
109     }
110 
111     if (EVP_EncryptInit_ex(cryptPara->ctx, cipher, NULL, cryptPara->key, cryptPara->iv) == 0) {
112         LOGE(TAG, "encrypt init error");
113         return NSTACKX_EFAILED;
114     }
115     if (EVP_EncryptUpdate(cryptPara->ctx, NULL, &length, cryptPara->aad, (int32_t)cryptPara->aadLen) == 0) {
116         LOGE(TAG, "add aad error");
117         return NSTACKX_EFAILED;
118     }
119     return NSTACKX_EOK;
120 }
121 
AesGcmEncryptVec(AesVec * vec,uint32_t vecNum,CryptPara * cryptPara,uint8_t * outBuf,uint32_t outLen)122 uint32_t AesGcmEncryptVec(AesVec *vec, uint32_t vecNum, CryptPara *cryptPara, uint8_t *outBuf,
123                           uint32_t outLen)
124 {
125     int32_t length;
126     uint32_t retLen = 0;
127     if (vecNum == 0 || outLen <= GCM_ADDED_LEN || cryptPara == NULL ||
128         vec == NULL || outBuf == NULL) {
129         LOGE(TAG, "Invaid para");
130         return 0;
131     }
132     if (InitEncryptCtx(cryptPara) != NSTACKX_EOK) {
133         LOGE(TAG, "InitEncryptCtx error");
134         return 0;
135     }
136 
137     for (uint32_t i = 0; i < vecNum; i++) {
138         if ((outLen - GCM_ADDED_LEN) < (retLen + vec[i].len)) {
139             LOGE(TAG, "outBuf len %u is less to %u bytes input", outLen, retLen + vec[i].len);
140             return 0;
141         }
142         if (EVP_EncryptUpdate(cryptPara->ctx, outBuf + retLen, &length, vec[i].buf, (int32_t)vec[i].len) == 0 ||
143             length != (int)vec[i].len) {
144             LOGE(TAG, "encrypt data error");
145             return 0;
146         }
147         retLen += (uint32_t)length;
148     }
149     if (EVP_EncryptFinal_ex(cryptPara->ctx, outBuf + retLen, &length) == 0 || length != 0) {
150         LOGE(TAG, "encrypt final error");
151         return 0;
152     }
153     if (EVP_CIPHER_CTX_ctrl(cryptPara->ctx, EVP_CTRL_AEAD_GET_TAG, GCM_TAG_LENGTH, outBuf + retLen) == 0) {
154         LOGE(TAG, "get tag error.");
155         return 0;
156     }
157     retLen += GCM_TAG_LENGTH;
158     if (memcpy_s(outBuf + retLen, outLen - retLen, cryptPara->iv, cryptPara->ivLen) != EOK) {
159         LOGE(TAG, "pad iv error.");
160         return 0;
161     }
162     retLen += cryptPara->ivLen;
163     return retLen;
164 }
165 
AesGcmEncrypt(const uint8_t * inBuf,uint32_t inLen,CryptPara * cryptPara,uint8_t * outBuf,uint32_t outLen)166 uint32_t AesGcmEncrypt(const uint8_t *inBuf, uint32_t inLen, CryptPara *cryptPara, uint8_t *outBuf,
167                        uint32_t outLen)
168 {
169     AesVec vec;
170     vec.buf = inBuf;
171     vec.len = inLen;
172     return AesGcmEncryptVec(&vec, 1, cryptPara, outBuf, outLen);
173 }
174 
InitDecryptCtx(CryptPara * cryptPara)175 static int32_t InitDecryptCtx(CryptPara *cryptPara)
176 {
177     int32_t length;
178     const EVP_CIPHER *cipher = GetCipher(cryptPara);
179 
180     if (cipher == NULL || cryptPara->ivLen != GCM_IV_LENGTH || cryptPara->aadLen == 0 || cryptPara->ctx == NULL) {
181         return NSTACKX_EFAILED;
182     }
183 
184     if (EVP_DecryptInit_ex(cryptPara->ctx, cipher, NULL, cryptPara->key, cryptPara->iv) == 0) {
185         LOGE(TAG, "decrypt init error");
186         return NSTACKX_EFAILED;
187     }
188     if (EVP_DecryptUpdate(cryptPara->ctx, NULL, &length, cryptPara->aad, (int32_t)cryptPara->aadLen) == 0) {
189         LOGE(TAG, "decrypt update error");
190         return NSTACKX_EFAILED;
191     }
192     return NSTACKX_EOK;
193 }
194 
AesGcmDecrypt(uint8_t * inBuf,uint32_t inLen,CryptPara * cryptPara,uint8_t * outBuf,uint32_t outLen)195 uint32_t AesGcmDecrypt(uint8_t *inBuf, uint32_t inLen, CryptPara *cryptPara, uint8_t *outBuf,
196                        uint32_t outLen)
197 {
198     int32_t length;
199     int32_t dataLen;
200     uint32_t retLen;
201     uint8_t buffer[AES_BLOCK_SIZE];
202     if (inLen <= GCM_ADDED_LEN || outLen < inLen - GCM_ADDED_LEN || cryptPara == NULL ||
203         inBuf == NULL || outBuf == NULL) {
204         LOGE(TAG, "Invaid para");
205         return 0;
206     }
207     cryptPara->ivLen = GCM_IV_LENGTH;
208     if (memcpy_s(cryptPara->iv, cryptPara->ivLen, inBuf + (inLen - GCM_IV_LENGTH), GCM_IV_LENGTH) != EOK) {
209         return 0;
210     }
211 
212     if (InitDecryptCtx(cryptPara) != NSTACKX_EOK) {
213         LOGE(TAG, "InitDecryptCtx error");
214         return 0;
215     }
216     dataLen = (int32_t)(inLen - GCM_ADDED_LEN);
217     if (EVP_DecryptUpdate(cryptPara->ctx, outBuf, &length, inBuf, dataLen) == 0 || length != dataLen) {
218         LOGE(TAG, "decrypt data error");
219         return 0;
220     }
221     retLen = (uint32_t)length;
222 
223     if (EVP_CIPHER_CTX_ctrl(cryptPara->ctx, EVP_CTRL_AEAD_SET_TAG, GCM_TAG_LENGTH, inBuf + dataLen) == 0) {
224         LOGE(TAG, "set tag error.");
225         return 0;
226     }
227 
228     if (EVP_DecryptFinal_ex(cryptPara->ctx, buffer, &length) == 0 || length != 0) {
229         LOGE(TAG, "data verify error");
230         return 0;
231     }
232     return retLen;
233 }
234 
IsCryptoIncluded(void)235 uint8_t IsCryptoIncluded(void)
236 {
237     return NSTACKX_TRUE;
238 }
239 
QueryCipherSupportByName(char * name)240 uint8_t QueryCipherSupportByName(char *name)
241 {
242     if (EVP_get_cipherbyname(name) != NULL) {
243         return NSTACKX_TRUE;
244     }
245 
246     LOGI(TAG, "devices no support %s", name);
247     return NSTACKX_FALSE;
248 }
249 #ifdef NSTACKX_WITH_LINUX_STANDARD
250 #define AES_HWCAP (1UL << 3)
251 #define AES_HWCAP2 (1UL << 0)
252 
CheckAesCapability(void)253 static uint8_t CheckAesCapability(void)
254 {
255     uint8_t ret = NSTACKX_FALSE;
256     LOGI(TAG, "CheckAesCapability enter");
257     unsigned long hwcaps = getauxval(AT_HWCAP);
258     unsigned long hwcaps2 = getauxval(AT_HWCAP2);
259     if ((hwcaps & AES_HWCAP) || (hwcaps2 & AES_HWCAP2)) {
260         ret = NSTACKX_TRUE;
261     }
262     return ret;
263 }
264 #endif
265 
266 /* check CPU supports AES-NI hardware optimize */
IsSupportHardwareAesNi(void)267 uint8_t IsSupportHardwareAesNi(void)
268 {
269 #if defined(_WIN32) || defined(_WIN64)
270 #if defined(WINDOWS_AESNI_SUPPORT)
271     int32_t cpuInfo[] = {0, 0, 0, 0};
272     __cpuid(cpuInfo, 1);
273     return (cpuInfo[WIN_AESNI_ECI_IDX] & bit_AES) != 0;
274 #else
275     return NSTACKX_TRUE;
276 #endif // defined(WINDOWS_AESNI_SUPPORT)
277 
278 #else // linux
279 
280 #ifdef NSTACKX_WITH_LINUX_STANDARD
281     return CheckAesCapability();
282 #else
283     return NSTACKX_FALSE;
284 #endif
285 
286 #endif // defined(_WIN32) || defined(_WIN64)
287 }
288 
289 #else
GetRandBytes(uint8_t * buf,uint32_t len)290 int32_t GetRandBytes(uint8_t *buf, uint32_t len)
291 {
292     LOGI(TAG, "encryption not deployed");
293     return NSTACKX_EFAILED;
294 }
295 
CreateCryptCtx(void)296 EVP_CIPHER_CTX *CreateCryptCtx(void)
297 {
298     LOGI(TAG, "encryption not deployed");
299     EVP_CIPHER_CTX *ctx = NULL;
300     return ctx;
301 }
302 
ClearCryptCtx(EVP_CIPHER_CTX * ctx)303 void ClearCryptCtx(EVP_CIPHER_CTX *ctx)
304 {
305     LOGI(TAG, "encryption not deployed");
306     (void)ctx;
307 }
308 
AesGcmEncrypt(const uint8_t * inBuf,uint32_t inLen,CryptPara * cryptPara,uint8_t * outBuf,uint32_t outLen)309 uint32_t AesGcmEncrypt(const uint8_t *inBuf, uint32_t inLen, CryptPara *cryptPara, uint8_t *outBuf,
310                        uint32_t outLen)
311 {
312     (void)inBuf;
313     (void)inLen;
314     (void)cryptPara;
315     (void)outBuf;
316     (void)outLen;
317     LOGI(TAG, "encryption not deployed");
318     return 0;
319 }
320 
AesGcmDecrypt(uint8_t * inBuf,uint32_t inLen,CryptPara * cryptPara,uint8_t * outBuf,uint32_t outLen)321 uint32_t AesGcmDecrypt(uint8_t *inBuf, uint32_t inLen, CryptPara *cryptPara, uint8_t *outBuf,
322                        uint32_t outLen)
323 {
324     (void)inBuf;
325     (void)inLen;
326     (void)cryptPara;
327     (void)outBuf;
328     (void)outLen;
329     LOGI(TAG, "encryption not deployed");
330     return 0;
331 }
332 
IsCryptoIncluded(void)333 uint8_t IsCryptoIncluded(void)
334 {
335     return NSTACKX_FALSE;
336 }
337 
QueryCipherSupportByName(char * name)338 uint8_t QueryCipherSupportByName(char *name)
339 {
340     LOGI(TAG, "devices no support %s", name);
341     return NSTACKX_FALSE;
342 }
343 /* check CPU supports AES-NI hardware optimize */
IsSupportHardwareAesNi(void)344 uint8_t IsSupportHardwareAesNi(void)
345 {
346     LOGI(TAG, "no support AES-NI");
347     return NSTACKX_FALSE;
348 }
349 
350 #endif // SSL_AND_CRYPTO_INCLUDED
351