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 #define TAG "nStackXDFile"
22 
23 #ifdef SSL_AND_CRYPTO_INCLUDED
GetRandBytes(uint8_t * buf,uint32_t len)24 int32_t GetRandBytes(uint8_t *buf, uint32_t len)
25 {
26     if (buf == NULL || len == 0) {
27         LOGE(TAG, "buf is NULL or illegal length %u", len);
28         return NSTACKX_EFAILED;
29     }
30     if (RAND_bytes(buf, (int)len) != 1) {
31         LOGE(TAG, "get rand_bytes failed");
32         return NSTACKX_EFAILED;
33     }
34     return NSTACKX_EOK;
35 }
36 
CreateCryptCtx()37 EVP_CIPHER_CTX *CreateCryptCtx()
38 {
39     LOGI(TAG, "openssl CreateCryptCtx");
40     EVP_CIPHER_CTX *ctx = NULL;
41     ctx = EVP_CIPHER_CTX_new();
42     return ctx;
43 }
44 
ClearCryptCtx(EVP_CIPHER_CTX * ctx)45 void ClearCryptCtx(EVP_CIPHER_CTX *ctx)
46 {
47     if (ctx != NULL) {
48         EVP_CIPHER_CTX_free(ctx);
49     }
50 }
51 
InitEncryptCtx(CryptPara * cryptPara)52 static int32_t InitEncryptCtx(CryptPara *cryptPara)
53 {
54     int32_t length;
55     const EVP_CIPHER *cipher = NULL;
56     if (cryptPara->cipherType == CIPHER_CHACHA) {
57         cipher = EVP_get_cipherbyname(CHACHA20_POLY1305_NAME);
58     } else if (cryptPara->cipherType == CIPHER_AES_GCM) {
59         switch (cryptPara->keylen) {
60             case AES_128_KEY_LENGTH:
61                 cipher = EVP_aes_128_gcm();
62                 break;
63             case AES_192_KEY_LENGTH:
64                 cipher = EVP_aes_192_gcm();
65                 break;
66             case AES_256_KEY_LENGTH:
67                 cipher = EVP_aes_256_gcm();
68                 break;
69             default:
70                 return NSTACKX_EFAILED;
71         }
72     }
73 
74     if (cryptPara->aadLen == 0 || cryptPara->ctx == NULL) {
75         return NSTACKX_EFAILED;
76     }
77 
78     cryptPara->ivLen = GCM_IV_LENGTH;
79 
80     if (GetRandBytes(cryptPara->iv, cryptPara->ivLen) != NSTACKX_EOK) {
81         LOGE(TAG, "get rand iv failed");
82         return NSTACKX_EFAILED;
83     }
84 
85     if (EVP_EncryptInit_ex(cryptPara->ctx, cipher, NULL, cryptPara->key, cryptPara->iv) == 0) {
86         LOGE(TAG, "encrypt init error");
87         return NSTACKX_EFAILED;
88     }
89     if (EVP_EncryptUpdate(cryptPara->ctx, NULL, &length, cryptPara->aad, (int32_t)cryptPara->aadLen) == 0) {
90         LOGE(TAG, "add aad error");
91         return NSTACKX_EFAILED;
92     }
93     return NSTACKX_EOK;
94 }
95 
AesGcmEncryptVec(AesVec * vec,uint32_t vecNum,CryptPara * cryptPara,uint8_t * outBuf,uint32_t outLen)96 uint32_t AesGcmEncryptVec(AesVec *vec, uint32_t vecNum, CryptPara *cryptPara, uint8_t *outBuf,
97                           uint32_t outLen)
98 {
99     int32_t length;
100     uint32_t retLen = 0;
101     if (vecNum == 0 || outLen <= GCM_ADDED_LEN || cryptPara == NULL ||
102         vec == NULL || outBuf == NULL) {
103         LOGE(TAG, "Invaid para");
104         return 0;
105     }
106     if (InitEncryptCtx(cryptPara) != NSTACKX_EOK) {
107         LOGE(TAG, "InitEncryptCtx error");
108         return 0;
109     }
110 
111     for (uint32_t i = 0; i < vecNum; i++) {
112         if ((outLen - GCM_ADDED_LEN) < (retLen + vec[i].len)) {
113             LOGE(TAG, "outBuf len %u is less to %u bytes input", outLen, retLen + vec[i].len);
114             return 0;
115         }
116         if (EVP_EncryptUpdate(cryptPara->ctx, outBuf + retLen, &length, vec[i].buf, (int32_t)vec[i].len) == 0 ||
117             length != (int)vec[i].len) {
118             LOGE(TAG, "encrypt data error");
119             return 0;
120         }
121         retLen += (uint32_t)length;
122     }
123     if (EVP_EncryptFinal_ex(cryptPara->ctx, outBuf + retLen, &length) == 0 || length != 0) {
124         LOGE(TAG, "encrypt final error");
125         return 0;
126     }
127     if (EVP_CIPHER_CTX_ctrl(cryptPara->ctx, EVP_CTRL_AEAD_GET_TAG, GCM_TAG_LENGTH, outBuf + retLen) == 0) {
128         LOGE(TAG, "get tag error.");
129         return 0;
130     }
131     retLen += GCM_TAG_LENGTH;
132     if (memcpy_s(outBuf + retLen, outLen - retLen, cryptPara->iv, cryptPara->ivLen) != EOK) {
133         LOGE(TAG, "pad iv error.");
134         return 0;
135     }
136     retLen += cryptPara->ivLen;
137     return retLen;
138 }
139 
AesGcmEncrypt(const uint8_t * inBuf,uint32_t inLen,CryptPara * cryptPara,uint8_t * outBuf,uint32_t outLen)140 uint32_t AesGcmEncrypt(const uint8_t *inBuf, uint32_t inLen, CryptPara *cryptPara, uint8_t *outBuf,
141                        uint32_t outLen)
142 {
143     AesVec vec;
144     vec.buf = inBuf;
145     vec.len = inLen;
146     return AesGcmEncryptVec(&vec, 1, cryptPara, outBuf, outLen);
147 }
148 
InitDecryptCtx(CryptPara * cryptPara)149 static int32_t InitDecryptCtx(CryptPara *cryptPara)
150 {
151     int32_t length;
152     const EVP_CIPHER *cipher = NULL;
153     if (cryptPara->cipherType == CIPHER_CHACHA) {
154         cipher = EVP_get_cipherbyname(CHACHA20_POLY1305_NAME);
155     } else if (cryptPara->cipherType == CIPHER_AES_GCM) {
156         switch (cryptPara->keylen) {
157             case AES_128_KEY_LENGTH:
158                 cipher = EVP_aes_128_gcm();
159                 break;
160             case AES_192_KEY_LENGTH:
161                 cipher = EVP_aes_192_gcm();
162                 break;
163             case AES_256_KEY_LENGTH:
164                 cipher = EVP_aes_256_gcm();
165                 break;
166             default:
167                 return NSTACKX_EFAILED;
168         }
169     }
170     if (cryptPara->ivLen != GCM_IV_LENGTH || cryptPara->aadLen == 0 || cryptPara->ctx == NULL) {
171         return NSTACKX_EFAILED;
172     }
173 
174     if (EVP_DecryptInit_ex(cryptPara->ctx, cipher, NULL, cryptPara->key, cryptPara->iv) == 0) {
175         LOGE(TAG, "decrypt init error");
176         return NSTACKX_EFAILED;
177     }
178     if (EVP_DecryptUpdate(cryptPara->ctx, NULL, &length, cryptPara->aad, (int32_t)cryptPara->aadLen) == 0) {
179         LOGE(TAG, "decrypt update error");
180         return NSTACKX_EFAILED;
181     }
182     return NSTACKX_EOK;
183 }
184 
AesGcmDecrypt(uint8_t * inBuf,uint32_t inLen,CryptPara * cryptPara,uint8_t * outBuf,uint32_t outLen)185 uint32_t AesGcmDecrypt(uint8_t *inBuf, uint32_t inLen, CryptPara *cryptPara, uint8_t *outBuf,
186                        uint32_t outLen)
187 {
188     int32_t length;
189     int32_t dataLen;
190     uint32_t retLen;
191     uint8_t buffer[AES_BLOCK_SIZE];
192     if (inLen <= GCM_ADDED_LEN || outLen < inLen - GCM_ADDED_LEN || cryptPara == NULL ||
193         inBuf == NULL || outBuf == NULL) {
194         LOGE(TAG, "Invaid para");
195         return 0;
196     }
197     cryptPara->ivLen = GCM_IV_LENGTH;
198     if (memcpy_s(cryptPara->iv, cryptPara->ivLen, inBuf + (inLen - GCM_IV_LENGTH), GCM_IV_LENGTH) != EOK) {
199         return 0;
200     }
201 
202     if (InitDecryptCtx(cryptPara) != NSTACKX_EOK) {
203         LOGE(TAG, "InitDecryptCtx error");
204         return 0;
205     }
206     dataLen = (int32_t)(inLen - GCM_ADDED_LEN);
207     if (EVP_DecryptUpdate(cryptPara->ctx, outBuf, &length, inBuf, dataLen) == 0 || length != dataLen) {
208         LOGE(TAG, "decrypt data error");
209         return 0;
210     }
211     retLen = (uint32_t)length;
212 
213     if (EVP_CIPHER_CTX_ctrl(cryptPara->ctx, EVP_CTRL_AEAD_SET_TAG, GCM_TAG_LENGTH, inBuf + dataLen) == 0) {
214         LOGE(TAG, "set tag error.");
215         return 0;
216     }
217 
218     if (EVP_DecryptFinal_ex(cryptPara->ctx, buffer, &length) == 0 || length != 0) {
219         LOGE(TAG, "data verify error");
220         return 0;
221     }
222     return retLen;
223 }
224 
IsCryptoIncluded(void)225 uint8_t IsCryptoIncluded(void)
226 {
227     return NSTACKX_TRUE;
228 }
229 
QueryCipherSupportByName(char * name)230 uint8_t QueryCipherSupportByName(char *name)
231 {
232     if (EVP_get_cipherbyname(name) != NULL) {
233         return NSTACKX_TRUE;
234     }
235 
236     LOGI(TAG, "devices no support %s", name);
237     return NSTACKX_FALSE;
238 }
239 
240 #else
GetRandBytes(uint8_t * buf,uint32_t len)241 int32_t GetRandBytes(uint8_t *buf, uint32_t len)
242 {
243     LOGI(TAG, "encryption not deployed");
244     return NSTACKX_EFAILED;
245 }
246 
CreateCryptCtx(void)247 EVP_CIPHER_CTX *CreateCryptCtx(void)
248 {
249     LOGI(TAG, "encryption not deployed");
250     EVP_CIPHER_CTX *ctx = NULL;
251     return ctx;
252 }
253 
ClearCryptCtx(EVP_CIPHER_CTX * ctx)254 void ClearCryptCtx(EVP_CIPHER_CTX *ctx)
255 {
256     LOGI(TAG, "encryption not deployed");
257     (void)ctx;
258 }
259 
AesGcmEncrypt(const uint8_t * inBuf,uint32_t inLen,CryptPara * cryptPara,uint8_t * outBuf,uint32_t outLen)260 uint32_t AesGcmEncrypt(const uint8_t *inBuf, uint32_t inLen, CryptPara *cryptPara, uint8_t *outBuf,
261                        uint32_t outLen)
262 {
263     (void)inBuf;
264     (void)inLen;
265     (void)cryptPara;
266     (void)outBuf;
267     (void)outLen;
268     LOGI(TAG, "encryption not deployed");
269     return 0;
270 }
271 
AesGcmDecrypt(uint8_t * inBuf,uint32_t inLen,CryptPara * cryptPara,uint8_t * outBuf,uint32_t outLen)272 uint32_t AesGcmDecrypt(uint8_t *inBuf, uint32_t inLen, CryptPara *cryptPara, uint8_t *outBuf,
273                        uint32_t outLen)
274 {
275     (void)inBuf;
276     (void)inLen;
277     (void)cryptPara;
278     (void)outBuf;
279     (void)outLen;
280     LOGI(TAG, "encryption not deployed");
281     return 0;
282 }
283 
IsCryptoIncluded(void)284 uint8_t IsCryptoIncluded(void)
285 {
286     return NSTACKX_FALSE;
287 }
288 
QueryCipherSupportByName(char * name)289 uint8_t QueryCipherSupportByName(char *name)
290 {
291     LOGI(TAG, "devices no support %s", name);
292     return NSTACKX_FALSE;
293 }
294 
295 #endif // SSL_AND_CRYPTO_INCLUDED
296