* This file is part of the openHiTLS project.
*
* openHiTLS is licensed under the Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
#include "hitls_build.h"
#ifdef HITLS_CRYPTO_ECDH
#include <stdbool.h>
#include "crypt_errno.h"
#include "crypt_types.h"
#include "bsl_sal.h"
#include "bsl_err_internal.h"
#include "sal_atomic.h"
#include "crypt_utils.h"
#include "crypt_util_ctrl.h"
#include "crypt_bn.h"
#include "crypt_ecc.h"
#include "crypt_ecc_pkey.h"
#include "eal_pkey_local.h"
#include "crypt_ecdh.h"
#include "bsl_params.h"
#include "crypt_params_key.h"
CRYPT_ECDH_Ctx *CRYPT_ECDH_NewCtx(void)
{
ECC_Pkey *ctx = BSL_SAL_Calloc(1u, sizeof(ECC_Pkey));
if (ctx == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
return NULL;
}
ctx->useCofactorMode = true;
ctx->pointFormat = CRYPT_POINT_UNCOMPRESSED;
BSL_SAL_ReferencesInit(&(ctx->references));
return ctx;
}
CRYPT_ECDH_Ctx *CRYPT_ECDH_NewCtxEx(void *libCtx)
{
CRYPT_ECDH_Ctx *ctx = CRYPT_ECDH_NewCtx();
if (ctx == NULL) {
return NULL;
}
ctx->libCtx = libCtx;
return ctx;
}
CRYPT_EcdhPara *CRYPT_ECDH_NewPara(const CRYPT_EccPara *eccPara)
{
CRYPT_PKEY_ParaId id = GetCurveId(eccPara);
if (id == CRYPT_PKEY_PARAID_MAX) {
BSL_ERR_PUSH_ERROR(CRYPT_ECC_ERR_PARA);
return NULL;
}
return CRYPT_ECDH_NewParaById(id);
}
CRYPT_PKEY_ParaId CRYPT_ECDH_GetParaId(const CRYPT_ECDH_Ctx *ctx)
{
if (ctx == NULL) {
return CRYPT_PKEY_PARAID_MAX;
}
return ECC_GetParaId(ctx->para);
}
int32_t CRYPT_ECDH_SetPara(CRYPT_ECDH_Ctx *ctx, const CRYPT_EccPara *para)
{
if (ctx == NULL || para == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
return CRYPT_NULL_INPUT;
}
return ECC_SetPara(ctx, CRYPT_ECDH_NewPara(para));
}
int32_t CRYPT_ECDH_SetParaEx(CRYPT_ECDH_Ctx *ctx, const BSL_Param *para)
{
if (para == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
return CRYPT_NULL_INPUT;
}
CRYPT_EccPara eccPara = {0};
(void)GetConstParamValue(para, CRYPT_PARAM_EC_P, &(eccPara.p), &(eccPara.pLen));
(void)GetConstParamValue(para, CRYPT_PARAM_EC_A, &(eccPara.a), &(eccPara.aLen));
(void)GetConstParamValue(para, CRYPT_PARAM_EC_B, &(eccPara.b), &(eccPara.bLen));
(void)GetConstParamValue(para, CRYPT_PARAM_EC_N, &(eccPara.n), &(eccPara.nLen));
(void)GetConstParamValue(para, CRYPT_PARAM_EC_H, &(eccPara.h), &(eccPara.hLen));
(void)GetConstParamValue(para, CRYPT_PARAM_EC_X, &(eccPara.x), &(eccPara.xLen));
(void)GetConstParamValue(para, CRYPT_PARAM_EC_Y, &(eccPara.y), &(eccPara.yLen));
return CRYPT_ECDH_SetPara(ctx, &eccPara);
}
static int32_t ComputeShareKeyInputCheck(const CRYPT_ECDH_Ctx *ctx, const CRYPT_ECDH_Ctx *pubKey,
const uint8_t *shareKey, const uint32_t *shareKeyLen)
{
if ((ctx == NULL) || (pubKey == NULL) || (shareKey == NULL) || (shareKeyLen == NULL)) {
BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
return CRYPT_NULL_INPUT;
}
if ((ctx->prvkey == NULL) || (pubKey->pubkey == NULL)) {
BSL_ERR_PUSH_ERROR(CRYPT_ECDH_ERR_EMPTY_KEY);
return CRYPT_ECDH_ERR_EMPTY_KEY;
}
BN_BigNum *paraH = ECC_GetParaH(ctx->para);
if (paraH == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
return CRYPT_MEM_ALLOC_FAIL;
}
if (BN_IsOne(paraH) != true) {
BN_Destroy(paraH);
BSL_ERR_PUSH_ERROR(CRYPT_ECDH_ERR_INVALID_COFACTOR);
return CRYPT_ECDH_ERR_INVALID_COFACTOR;
}
BN_Destroy(paraH);
return CRYPT_SUCCESS;
}
int32_t CRYPT_ECDH_ComputeShareKey(const CRYPT_ECDH_Ctx *ctx, const CRYPT_ECDH_Ctx *pubKey,
uint8_t *shareKey, uint32_t *shareKeyLen)
{
int32_t ret = ComputeShareKeyInputCheck(ctx, pubKey, shareKey, shareKeyLen);
if (ret != CRYPT_SUCCESS) {
return ret;
}
CRYPT_Data shareKeyX = {shareKey, *shareKeyLen};
ECC_Point *sharePoint = ECC_NewPoint(ctx->para);
if (sharePoint == NULL) {
ret = CRYPT_MEM_ALLOC_FAIL;
BSL_ERR_PUSH_ERROR(ret);
goto EXIT;
}
* Currently, the cofactor of the prime curve is only 1, and no related calculation is required.
*/
ret = ECC_PointMul(ctx->para, sharePoint, ctx->prvkey, pubKey->pubkey);
if (ret != CRYPT_SUCCESS) {
BSL_ERR_PUSH_ERROR(ret);
goto EXIT;
}
ret = ECC_PointCheck(sharePoint);
if (ret != CRYPT_SUCCESS) {
BSL_ERR_PUSH_ERROR(ret);
goto EXIT;
}
ret = ECC_GetPoint(ctx->para, sharePoint, &shareKeyX, NULL);
if (ret != CRYPT_SUCCESS) {
BSL_ERR_PUSH_ERROR(ret);
goto EXIT;
}
*shareKeyLen = shareKeyX.len;
EXIT:
ECC_FreePoint(sharePoint);
return ret;
}
int32_t CRYPT_ECDH_Ctrl(CRYPT_ECDH_Ctx *ctx, int32_t opt, void *val, uint32_t len)
{
if (ctx == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
return CRYPT_NULL_INPUT;
}
switch (opt) {
case CRYPT_CTRL_GET_PARAID:
return CRYPT_CTRL_GET_NUM32_EX(ECC_GetParaId, ctx->para, val, len);
case CRYPT_CTRL_GET_BITS:
return CRYPT_CTRL_GET_NUM32_EX(ECC_PkeyGetBits, ctx, val, len);
case CRYPT_CTRL_GET_SECBITS:
return CRYPT_CTRL_GET_NUM32_EX(ECC_GetSecBits, ctx->para, val, len);
case CRYPT_CTRL_SET_PARA_BY_ID:
if (val == NULL || len != sizeof(int32_t)) {
BSL_ERR_PUSH_ERROR(CRYPT_INVALID_ARG);
return CRYPT_INVALID_ARG;
}
return ECC_SetPara(ctx, CRYPT_ECDH_NewParaById(*(int32_t *)val));
default:
return ECC_PkeyCtrl(ctx, opt, val, len);
}
}
int32_t CRYPT_ECDH_GetSecBits(const CRYPT_ECDH_Ctx *ctx)
{
if (ctx == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
return 0;
}
return ECC_GetSecBits(ctx->para);
}
#ifdef HITLS_CRYPTO_ECDH_CHECK
int32_t CRYPT_ECDH_Check(uint32_t checkType, const CRYPT_ECDH_Ctx *pkey1, const CRYPT_ECDH_Ctx *pkey2)
{
int32_t ret = ECC_PkeyCheck(pkey1, pkey2, checkType);
if (ret == CRYPT_ECC_PAIRWISE_CHECK_FAIL) {
BSL_ERR_PUSH_ERROR(CRYPT_ECDH_PAIRWISE_CHECK_FAIL);
return CRYPT_ECDH_PAIRWISE_CHECK_FAIL;
}
if (ret == CRYPT_ECC_INVALID_PRVKEY) {
BSL_ERR_PUSH_ERROR(CRYPT_ECDH_INVALID_PRVKEY);
return CRYPT_ECDH_INVALID_PRVKEY;
}
return ret;
}
#endif
#endif