• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * This file is part of the openHiTLS project.
3  *
4  * openHiTLS is licensed under the Mulan PSL v2.
5  * You can use this software according to the terms and conditions of the Mulan PSL v2.
6  * You may obtain a copy of Mulan PSL v2 at:
7  *
8  *     http://license.coscl.org.cn/MulanPSL2
9  *
10  * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11  * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12  * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13  * See the Mulan PSL v2 for more details.
14  */
15 
16 #include "hitls_build.h"
17 #if defined(HITLS_CRYPTO_CODECS) && defined(HITLS_CRYPTO_PROVIDER)
18 #include <stdint.h>
19 #include <string.h>
20 #include "securec.h"
21 #include "crypt_eal_codecs.h"
22 #include "crypt_eal_implprovider.h"
23 #include "crypt_provider.h"
24 #include "crypt_params_key.h"
25 #include "crypt_types.h"
26 #include "crypt_errno.h"
27 #include "decode_local.h"
28 #include "bsl_list.h"
29 #include "bsl_errno.h"
30 #include "bsl_err_internal.h"
31 
CreateDecoderNode(const char * format,const char * type,const char * targetFormat,const char * targetType,const BSL_Param * input)32 static CRYPT_DECODER_Node *CreateDecoderNode(const char *format, const char *type, const char *targetFormat,
33     const char *targetType, const BSL_Param *input)
34 {
35     CRYPT_DECODER_Node *decoderNode = BSL_SAL_Calloc(1, sizeof(CRYPT_DECODER_Node));
36     if (decoderNode == NULL) {
37         BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
38         return NULL;
39     }
40 
41     decoderNode->inData.format = format;
42     decoderNode->inData.type = type;
43     decoderNode->inData.data = (BSL_Param *)(uintptr_t)input;
44     decoderNode->outData.format = targetFormat;
45     decoderNode->outData.type = targetType;
46     return decoderNode;
47 }
48 
FreeDecoderNode(CRYPT_DECODER_Node * decoderNode)49 static void FreeDecoderNode(CRYPT_DECODER_Node *decoderNode)
50 {
51     if (decoderNode == NULL) {
52         return;
53     }
54     CRYPT_DECODE_FreeOutData(decoderNode->decoderCtx, decoderNode->outData.data);
55     BSL_SAL_Free(decoderNode);
56 }
57 
CRYPT_DECODE_PoolNewCtx(CRYPT_EAL_LibCtx * libCtx,const char * attrName,int32_t keyType,const char * format,const char * type)58 CRYPT_DECODER_PoolCtx *CRYPT_DECODE_PoolNewCtx(CRYPT_EAL_LibCtx *libCtx, const char *attrName,
59     int32_t keyType, const char *format, const char *type)
60 {
61     CRYPT_DECODER_PoolCtx *poolCtx = BSL_SAL_Calloc(1, sizeof(CRYPT_DECODER_PoolCtx));
62     if (poolCtx == NULL) {
63         BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
64         return NULL;
65     }
66 
67     poolCtx->libCtx = libCtx;
68     poolCtx->attrName = attrName;
69     poolCtx->decoders = BSL_LIST_New(sizeof(CRYPT_DECODER_Ctx));
70     if (poolCtx->decoders == NULL) {
71         BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
72         BSL_SAL_Free(poolCtx);
73         return NULL;
74     }
75 
76     poolCtx->decoderPath = BSL_LIST_New(sizeof(CRYPT_DECODER_Node));
77     if (poolCtx->decoderPath == NULL) {
78         BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
79         goto ERR;
80     }
81     poolCtx->inputFormat = format;
82     poolCtx->inputType = type;
83     poolCtx->inputKeyType = keyType;
84     poolCtx->targetFormat = NULL;
85     poolCtx->targetType = NULL;
86     return poolCtx;
87 ERR:
88     BSL_LIST_FREE(poolCtx->decoders, NULL);
89     BSL_SAL_Free(poolCtx);
90     return NULL;
91 }
92 
CRYPT_DECODE_PoolFreeCtx(CRYPT_DECODER_PoolCtx * poolCtx)93 void CRYPT_DECODE_PoolFreeCtx(CRYPT_DECODER_PoolCtx *poolCtx)
94 {
95     if (poolCtx == NULL) {
96         return;
97     }
98 
99     /* Free decoder path list and all decoder nodes */
100     if (poolCtx->decoderPath != NULL) {
101         BSL_LIST_FREE(poolCtx->decoderPath, (BSL_LIST_PFUNC_FREE)FreeDecoderNode);
102     }
103     /* Free decoder list and all decoder contexts */
104     if (poolCtx->decoders != NULL) {
105         BSL_LIST_FREE(poolCtx->decoders, (BSL_LIST_PFUNC_FREE)CRYPT_DECODE_Free);
106     }
107 
108     BSL_SAL_Free(poolCtx);
109 }
110 
SetDecodeType(void * val,int32_t valLen,const char ** targetValue)111 static int32_t SetDecodeType(void *val, int32_t valLen, const char **targetValue)
112 {
113     if (valLen == 0 || valLen > MAX_CRYPT_DECODE_FORMAT_TYPE_SIZE) {
114         BSL_ERR_PUSH_ERROR(CRYPT_INVALID_ARG);
115         return CRYPT_INVALID_ARG;
116     }
117     *targetValue = val;
118     return CRYPT_SUCCESS;
119 }
120 
SetFlagFreeOutData(CRYPT_DECODER_PoolCtx * poolCtx,void * val,int32_t valLen)121 static int32_t SetFlagFreeOutData(CRYPT_DECODER_PoolCtx *poolCtx, void *val, int32_t valLen)
122 {
123     if (valLen != sizeof(bool)) {
124         BSL_ERR_PUSH_ERROR(CRYPT_INVALID_ARG);
125         return CRYPT_INVALID_ARG;
126     }
127     if (poolCtx->decoderPath == NULL) {
128         BSL_ERR_PUSH_ERROR(CRYPT_INVALID_ARG);
129         return CRYPT_INVALID_ARG;
130     }
131     CRYPT_DECODER_Node *prevNode = BSL_LIST_GET_PREV(poolCtx->decoderPath);
132     if (prevNode == NULL) {
133         return CRYPT_SUCCESS;
134     }
135     bool isFreeOutData = *(bool *)val;
136     if (!isFreeOutData) {
137         prevNode->outData.data = NULL;
138     }
139     return CRYPT_SUCCESS;
140 }
141 
CRYPT_DECODE_PoolCtrl(CRYPT_DECODER_PoolCtx * poolCtx,int32_t cmd,void * val,int32_t valLen)142 int32_t CRYPT_DECODE_PoolCtrl(CRYPT_DECODER_PoolCtx *poolCtx, int32_t cmd, void *val, int32_t valLen)
143 {
144     if (poolCtx == NULL || val == NULL) {
145         BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
146         return CRYPT_NULL_INPUT;
147     }
148 
149     switch (cmd) {
150         case CRYPT_DECODE_POOL_CMD_SET_TARGET_TYPE:
151             return SetDecodeType(val, valLen, &poolCtx->targetType);
152         case CRYPT_DECODE_POOL_CMD_SET_TARGET_FORMAT:
153             return SetDecodeType(val, valLen, &poolCtx->targetFormat);
154         case CRYPT_DECODE_POOL_CMD_SET_FLAG_FREE_OUT_DATA:
155             return SetFlagFreeOutData(poolCtx, val, valLen);
156         default:
157             BSL_ERR_PUSH_ERROR(CRYPT_INVALID_ARG);
158             return CRYPT_INVALID_ARG;
159     }
160 }
161 
CollectDecoder(CRYPT_DECODER_Ctx * decoderCtx,void * args)162 static int32_t CollectDecoder(CRYPT_DECODER_Ctx *decoderCtx, void *args)
163 {
164     int32_t ret;
165     CRYPT_DECODER_PoolCtx *poolCtx = (CRYPT_DECODER_PoolCtx *)args;
166     if (poolCtx == NULL) {
167         BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
168         return CRYPT_NULL_INPUT;
169     }
170     // TODO: Filter the decoder by input format and type According to poolCtx
171     BSL_Param param[3] = {
172         {CRYPT_PARAM_DECODE_LIB_CTX, BSL_PARAM_TYPE_CTX_PTR, poolCtx->libCtx, 0, 0},
173         {CRYPT_PARAM_DECODE_TARGET_ATTR_NAME, BSL_PARAM_TYPE_OCTETS_PTR, (void *)(uintptr_t)poolCtx->attrName, 0, 0},
174         BSL_PARAM_END
175     };
176     ret = CRYPT_DECODE_SetParam(decoderCtx, param);
177     if (ret != CRYPT_SUCCESS) {
178         BSL_ERR_PUSH_ERROR(ret);
179         return ret;
180     }
181     ret = BSL_LIST_AddElement(poolCtx->decoders, decoderCtx, BSL_LIST_POS_END);
182     if (ret != BSL_SUCCESS) {
183         BSL_ERR_PUSH_ERROR(ret);
184         return ret;
185     }
186 
187     return CRYPT_SUCCESS;
188 }
189 
GetUsableDecoderFromPool(CRYPT_DECODER_PoolCtx * poolCtx,CRYPT_DECODER_Node * currNode)190 static CRYPT_DECODER_Ctx* GetUsableDecoderFromPool(CRYPT_DECODER_PoolCtx *poolCtx, CRYPT_DECODER_Node *currNode)
191 {
192     CRYPT_DECODER_Ctx *decoderCtx = NULL;
193     const char *curFormat = currNode->inData.format;
194     const char *curType = currNode->inData.type;
195     CRYPT_DECODER_Ctx *node = BSL_LIST_GET_FIRST(poolCtx->decoders);
196     while (node != NULL) {
197         decoderCtx = node;
198         if (decoderCtx == NULL || decoderCtx->decoderState != CRYPT_DECODER_STATE_UNTRIED) {
199             node = BSL_LIST_GET_NEXT(poolCtx->decoders);
200             continue;
201         }
202         /* Check if decoder matches the current node's input format and type */
203         if (curFormat != NULL && curType != NULL) {
204             if ((decoderCtx->inFormat != NULL && BSL_SAL_StrcaseCmp(decoderCtx->inFormat, curFormat) == 0) &&
205                 (decoderCtx->inType == NULL || BSL_SAL_StrcaseCmp(decoderCtx->inType, curType) == 0)) {
206                 break;
207             }
208         } else if (curFormat == NULL && curType != NULL) {
209             if (decoderCtx->inType == NULL || BSL_SAL_StrcaseCmp(decoderCtx->inType, curType) == 0) {
210                 break;
211             }
212         } else if (curFormat != NULL && curType == NULL) {
213             if (decoderCtx->inFormat != NULL && BSL_SAL_StrcaseCmp(decoderCtx->inFormat, curFormat) == 0) {
214                 break;
215             }
216         } else {
217             break;
218         }
219         node = BSL_LIST_GET_NEXT(poolCtx->decoders);
220     }
221     if (node != NULL) {
222         decoderCtx = node;
223         decoderCtx->decoderState = CRYPT_DECODER_STATE_TRING;
224     }
225     return node != NULL ? decoderCtx : NULL;
226 }
227 
UpdateDecoderPath(CRYPT_DECODER_PoolCtx * poolCtx,CRYPT_DECODER_Node * currNode)228 static int32_t UpdateDecoderPath(CRYPT_DECODER_PoolCtx *poolCtx, CRYPT_DECODER_Node *currNode)
229 {
230     /* Create new node */
231     CRYPT_DECODER_Node *newNode = CreateDecoderNode(currNode->outData.format, currNode->outData.type,
232         poolCtx->targetFormat, poolCtx->targetType, currNode->outData.data);
233     if (newNode == NULL) {
234         BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
235         return CRYPT_MEM_ALLOC_FAIL;
236     }
237     int32_t ret = BSL_LIST_AddElement(poolCtx->decoderPath, newNode, BSL_LIST_POS_END);
238     if (ret != BSL_SUCCESS) {
239         BSL_SAL_FREE(newNode);
240         BSL_ERR_PUSH_ERROR(ret);
241         return ret;
242     }
243     return CRYPT_SUCCESS;
244 }
245 
TryDecodeWithDecoder(CRYPT_DECODER_PoolCtx * poolCtx,CRYPT_DECODER_Node * currNode)246 static int32_t TryDecodeWithDecoder(CRYPT_DECODER_PoolCtx *poolCtx, CRYPT_DECODER_Node *currNode)
247 {
248     /* Convert password buffer to parameter if provided */
249     BSL_Param *decoderParam = NULL;
250     int32_t ret = CRYPT_DECODE_Decode(currNode->decoderCtx, currNode->inData.data, &decoderParam);
251     if (ret == CRYPT_SUCCESS) {
252         /* Get output format and type from decoder */
253         BSL_Param outParam[3] = {
254             {CRYPT_PARAM_DECODE_OUTPUT_FORMAT, BSL_PARAM_TYPE_OCTETS_PTR, NULL, 0, 0},
255             {CRYPT_PARAM_DECODE_OUTPUT_TYPE, BSL_PARAM_TYPE_OCTETS_PTR, NULL, 0, 0},
256             BSL_PARAM_END
257         };
258         ret = CRYPT_DECODE_GetParam(currNode->decoderCtx, outParam);
259         if (ret != CRYPT_SUCCESS) {
260             BSL_ERR_PUSH_ERROR(ret);
261             return ret;
262         }
263 
264         currNode->outData.data = decoderParam;
265         currNode->outData.format = outParam[0].value;
266         currNode->outData.type = outParam[1].value;
267         currNode->decoderCtx->decoderState = CRYPT_DECODER_STATE_SUCCESS;
268         ret = UpdateDecoderPath(poolCtx, currNode);
269         if (ret != CRYPT_SUCCESS) {
270             BSL_ERR_PUSH_ERROR(ret);
271             return ret;
272         }
273 
274         return CRYPT_SUCCESS;
275     } else {
276         /* Mark the node as tried */
277         currNode->decoderCtx->decoderState = CRYPT_DECODER_STATE_TRIED;
278         return CRYPT_DECODE_RETRY;
279     }
280 }
281 
ResetLastNode(CRYPT_DECODER_PoolCtx * poolCtx,CRYPT_DECODER_Node * currNode)282 static void ResetLastNode(CRYPT_DECODER_PoolCtx *poolCtx, CRYPT_DECODER_Node *currNode)
283 {
284     (void)currNode;
285     CRYPT_DECODER_Node *prevNode = BSL_LIST_GET_PREV(poolCtx->decoderPath);
286     /* Reset the out data of previous node if found */
287     if (prevNode != NULL) {
288         CRYPT_DECODE_FreeOutData(prevNode->decoderCtx, prevNode->outData.data);
289         prevNode->outData.data = NULL;
290         prevNode->decoderCtx = NULL;
291         prevNode->outData.format = poolCtx->targetFormat;
292         prevNode->outData.type = poolCtx->targetType;
293         (void)BSL_LIST_GET_NEXT(poolCtx->decoderPath);
294     } else {
295         (void)BSL_LIST_GET_FIRST(poolCtx->decoderPath);
296     }
297     BSL_LIST_DeleteCurrent(poolCtx->decoderPath, (BSL_LIST_PFUNC_FREE)FreeDecoderNode);
298     (void)BSL_LIST_GET_LAST(poolCtx->decoderPath);
299 }
300 
BackToLastLayerDecodeNode(CRYPT_DECODER_PoolCtx * poolCtx,CRYPT_DECODER_Node * currNode)301 static int32_t BackToLastLayerDecodeNode(CRYPT_DECODER_PoolCtx *poolCtx, CRYPT_DECODER_Node *currNode)
302 {
303     if (poolCtx == NULL || currNode == NULL) {
304         BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
305         return CRYPT_NULL_INPUT;
306     }
307     ResetLastNode(poolCtx, currNode);
308     /* Reset all decoders marked as tried to untried state */
309     CRYPT_DECODER_Ctx *decoderCtx = BSL_LIST_GET_FIRST(poolCtx->decoders);
310     while (decoderCtx != NULL) {
311         if (decoderCtx->decoderState == CRYPT_DECODER_STATE_TRIED) {
312             decoderCtx->decoderState = CRYPT_DECODER_STATE_UNTRIED;
313         }
314         decoderCtx = BSL_LIST_GET_NEXT(poolCtx->decoders);
315     }
316 
317     return CRYPT_SUCCESS;
318 }
319 
IsStrMatch(const char * source,const char * target)320 static bool IsStrMatch(const char *source, const char *target)
321 {
322     if (source == NULL && target == NULL) {
323         return true;
324     }
325     if (source == NULL || target == NULL) {
326         return false;
327     }
328     return BSL_SAL_StrcaseCmp(source, target) == 0;
329 }
330 
DecodeWithKeyChain(CRYPT_DECODER_PoolCtx * poolCtx,BSL_Param ** outParam)331 static int32_t DecodeWithKeyChain(CRYPT_DECODER_PoolCtx *poolCtx, BSL_Param **outParam)
332 {
333     int32_t ret;
334     CRYPT_DECODER_Ctx *decoderCtx = NULL;
335     CRYPT_DECODER_Node *currNode = BSL_LIST_GET_FIRST(poolCtx->decoderPath);
336     while (!BSL_LIST_EMPTY(poolCtx->decoderPath)) {
337         if (IsStrMatch(currNode->inData.format, poolCtx->targetFormat) &&
338             IsStrMatch(currNode->inData.type, poolCtx->targetType)) {
339             *outParam = currNode->inData.data;
340             return CRYPT_SUCCESS;
341         }
342         /* Get the usable decoder from the pool */
343         decoderCtx = GetUsableDecoderFromPool(poolCtx, currNode);
344         /* If the decoder is found, try to decode */
345         if (decoderCtx != NULL) {
346             currNode->decoderCtx = decoderCtx;
347             ret = TryDecodeWithDecoder(poolCtx, currNode);
348             if (ret == CRYPT_DECODE_RETRY) {
349                 continue;
350             }
351         } else {
352             ret = BackToLastLayerDecodeNode(poolCtx, currNode);
353         }
354         if (ret != CRYPT_SUCCESS) {
355             BSL_ERR_PUSH_ERROR(ret);
356             return ret;
357         }
358         CRYPT_DECODER_Node **curNodePtr = (CRYPT_DECODER_Node **)BSL_LIST_Curr(poolCtx->decoderPath);
359         currNode = curNodePtr == NULL ? NULL : *curNodePtr;
360     }
361 
362     BSL_ERR_PUSH_ERROR(CRYPT_DECODE_ERR_NO_USABLE_DECODER);
363     return CRYPT_DECODE_ERR_NO_USABLE_DECODER;
364 }
365 
366 typedef int32_t (*CRYPT_DECODE_ProviderProcessCb)(CRYPT_DECODER_Ctx *decoderCtx, void *args);
367 typedef struct {
368     CRYPT_DECODE_ProviderProcessCb cb;
369     void *args;
370 } CRYPT_DECODE_ProviderProcessArgs;
371 
ProcessEachProviderDecoder(CRYPT_EAL_ProvMgrCtx * ctx,void * args)372 static int32_t ProcessEachProviderDecoder(CRYPT_EAL_ProvMgrCtx *ctx, void *args)
373 {
374     CRYPT_DECODE_ProviderProcessArgs *processArgs = (CRYPT_DECODE_ProviderProcessArgs *)args;
375     CRYPT_DECODER_Ctx *decoderCtx = NULL;
376     CRYPT_EAL_AlgInfo *algInfos = NULL;
377     int32_t ret;
378 
379     if (ctx == NULL || args == NULL) {
380         BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
381         return CRYPT_NULL_INPUT;
382     }
383 
384     ret = CRYPT_EAL_ProviderQuery(ctx, CRYPT_EAL_OPERAID_DECODER, &algInfos);
385     if (ret == CRYPT_NOT_SUPPORT) {
386         return CRYPT_SUCCESS;
387     }
388     if (ret != CRYPT_SUCCESS) {
389         BSL_ERR_PUSH_ERROR(ret);
390         return ret;
391     }
392 
393     for (int32_t i = 0; algInfos != NULL && algInfos[i].algId != 0; i++) {
394         decoderCtx = CRYPT_DECODE_NewDecoderCtxByMethod(algInfos[i].implFunc, ctx, algInfos[i].attr);
395         if (decoderCtx == NULL) {
396             BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
397             return CRYPT_MEM_ALLOC_FAIL;
398         }
399         ret = processArgs->cb(decoderCtx, processArgs->args);
400         if (ret != CRYPT_SUCCESS) {
401             CRYPT_DECODE_Free(decoderCtx);
402             BSL_ERR_PUSH_ERROR(ret);
403             return ret;
404         }
405     }
406 
407     return CRYPT_SUCCESS;
408 }
409 
CRYPT_DECODE_ProviderProcessAll(CRYPT_EAL_LibCtx * ctx,CRYPT_DECODE_ProviderProcessCb cb,void * args)410 int32_t CRYPT_DECODE_ProviderProcessAll(CRYPT_EAL_LibCtx *ctx, CRYPT_DECODE_ProviderProcessCb cb, void *args)
411 {
412     if (cb == NULL) {
413         BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
414         return CRYPT_NULL_INPUT;
415     }
416     CRYPT_DECODE_ProviderProcessArgs processArgs = {
417         .cb = cb,
418         .args = args
419     };
420     int32_t ret = CRYPT_EAL_ProviderProcessAll(ctx, ProcessEachProviderDecoder, &processArgs);
421     if (ret != CRYPT_SUCCESS) {
422         return ret;
423     }
424 
425     return CRYPT_SUCCESS;
426 }
427 
CRYPT_DECODE_PoolDecode(CRYPT_DECODER_PoolCtx * poolCtx,const BSL_Param * inParam,BSL_Param ** outParam)428 int32_t CRYPT_DECODE_PoolDecode(CRYPT_DECODER_PoolCtx *poolCtx, const BSL_Param *inParam, BSL_Param **outParam)
429 {
430     if (poolCtx == NULL || inParam == NULL || outParam == NULL) {
431         BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
432         return CRYPT_NULL_INPUT;
433     }
434     if (*outParam != NULL) {
435         BSL_ERR_PUSH_ERROR(CRYPT_INVALID_ARG);
436         return CRYPT_INVALID_ARG;
437     }
438     int32_t ret = CRYPT_DECODE_ProviderProcessAll(poolCtx->libCtx, CollectDecoder, poolCtx);
439     if (ret != CRYPT_SUCCESS) {
440         return ret;
441     }
442     if (BSL_LIST_COUNT(poolCtx->decoders) == 0) {
443         BSL_ERR_PUSH_ERROR(CRYPT_DECODE_ERR_NO_DECODER);
444         return CRYPT_DECODE_ERR_NO_DECODER;
445     }
446     CRYPT_DECODER_Node *initialNode = CreateDecoderNode(poolCtx->inputFormat, poolCtx->inputType,
447         poolCtx->targetFormat, poolCtx->targetType, inParam);
448     if (initialNode == NULL) {
449         BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
450         return CRYPT_MEM_ALLOC_FAIL;
451     }
452     ret = BSL_LIST_AddElement(poolCtx->decoderPath, initialNode, BSL_LIST_POS_END);
453     if (ret != CRYPT_SUCCESS) {
454         BSL_SAL_Free(initialNode);
455         BSL_ERR_PUSH_ERROR(ret);
456         return ret;
457     }
458     return DecodeWithKeyChain(poolCtx, outParam);
459 }
460 
461 #endif /* HITLS_CRYPTO_CODECS && HITLS_CRYPTO_PROVIDER */
462