• <li id="00i08"><input id="00i08"></input></li>
  • <sup id="00i08"><tbody id="00i08"></tbody></sup>
    <abbr id="00i08"></abbr>
  • 博客專欄

    EEPW首頁 > 博客 > 基于openssl3.0,已知ECC算法x,y如何構建公鑰的EVP_PKEY結構

    基于openssl3.0,已知ECC算法x,y如何構建公鑰的EVP_PKEY結構

    發布人:電子禪石 時間:2025-02-25 來源:工程師 發布文章

    前言

    在將項目從 OpenSSL 1.1 升級到 OpenSSL 3.0 的過程中,

    開發者可能會遇到許多 API 的變化和棄用,尤其是在處理橢圓曲線(ECC)相關的函數時。

    OpenSSL 3.0 引入了一些新的 API,并對原有的 EC 相關函數進行了替換或棄用。

    盡管如此,我們仍然可以使用這些新 API 來創建和處理 EVP_PKEY 結構,以滿足現代加密需求。在已知ECC算法公鑰下x,y以及算法NID的前提下,如何使用openssl-3.0中的接口構建EVP_PKEY結構呢?


    一、問題分析

    在openssl-1.1中,我們可以很輕松創建ECC公鑰,但在openssl-3.0中很多相關的API已經被

    替換或棄用,導致代碼無法使用。


    二、在openssl-1.1中的解決方案

    注:

    1.代碼實現中的返回值定義,日志輸出函數,內存釋放函數需自行實現。


    2.1使用ECC算法的NID構建EC_KEY結構

    1

    EC_KEY  ecPublicKey  = NULL;

    ecPublicKey = EC_KEY_new_by_curve_name(nid);

    if (NULL == (*ecPublicKey)) {

            LOG_E("EC_KEY_new_by_curve_name error : %ld, %s", ERR_get_error(), ERR_reason_error_string(ERR_get_error()));

            return -1;

    }

    2.2將公鑰的x,y轉換成大數BIGNUM


    BIGNUM* bnX = NULL;

        BIGNUM* bnY = NULL;

        bnX = BN_bin2bn(x, 32, NULL);

        if (NULL == bnX) {

            LOG_E("BN_bin2bn error : %ld, %s", ERR_get_error(), ERR_reason_error_string(ERR_get_error()));

            EC_KEY_free(*ecPublicKey);

            *ecPublicKey = NULL;

            return -1;

        }


        bnY = BN_bin2bn(y, 32, NULL);

        if (NULL == bnY) {

            LOG_E("BN_bin2bn error : %ld, %s", ERR_get_error(), ERR_reason_error_string(ERR_get_error()));

            EC_KEY_free(*ecPublicKey);

            *ecPublicKey = NULL;

            WY_OPENSSL_FREE(BIGNUM, bnX);

            return -1;

        }

    2.3將公鑰信息x,y大數存放在EC_KEY結構中

    1

    if (1 != EC_KEY_set_public_key_affine_coordinates(*ecPublicKey, bnX, bnY)) {

            LOG_E("BN_bin2bn : %ld, %s", ERR_get_error(), ERR_reason_error_string(ERR_get_error()));

            EC_KEY_free(*ecPublicKey);

            *ecPublicKey = NULL;

            WY_OPENSSL_FREE(BIGNUM, bnX);

            WY_OPENSSL_FREE(BIGNUM, bnY);

            return -1;

        }

    2.4完整代碼

    1

    int get_ec_public_key_from_x_y(const unsigned char *x, const unsigned char *y, int nid, EC_KEY **ecPublicKey)

    {

        if ((NULL == x) || (NULL == y)) {

            LOG_E("param error");

            return ERROR_PARAM;

        }


        if (NULL != (*ecPublicKey)) {

            WY_OPENSSL_FREE(EC_KEY, *ecPublicKey);

            *ecPublicKey = NULL;

        }

        

        *ecPublicKey = EC_KEY_new_by_curve_name(nid);

        if (NULL == (*ecPublicKey)) {

            LOG_E("EC_KEY_new_by_curve_name error : %ld, %s", ERR_get_error(), ERR_reason_error_string(ERR_get_error()));

            return -1;

        }


        BIGNUM* bnX = NULL;

        BIGNUM* bnY = NULL;

        bnX = BN_bin2bn(x, 32, NULL);

        if (NULL == bnX) {

            LOG_E("BN_bin2bn error : %ld, %s", ERR_get_error(), ERR_reason_error_string(ERR_get_error()));

            EC_KEY_free(*ecPublicKey);

            *ecPublicKey = NULL;

            return -1;

        }


        bnY = BN_bin2bn(y, 32, NULL);

        if (NULL == bnY) {

            LOG_E("BN_bin2bn error : %ld, %s", ERR_get_error(), ERR_reason_error_string(ERR_get_error()));

            EC_KEY_free(*ecPublicKey);

            *ecPublicKey = NULL;

            WY_OPENSSL_FREE(BIGNUM, bnX);

            return -1;

        }


        if (1 != EC_KEY_set_public_key_affine_coordinates(*ecPublicKey, bnX, bnY)) {

            LOG_E("BN_bin2bn : %ld, %s", ERR_get_error(), ERR_reason_error_string(ERR_get_error()));

            EC_KEY_free(*ecPublicKey);

            *ecPublicKey = NULL;

            WY_OPENSSL_FREE(BIGNUM, bnX);

            WY_OPENSSL_FREE(BIGNUM, bnY);

            return -1;

        }


        WY_OPENSSL_FREE(BIGNUM, bnX);

        WY_OPENSSL_FREE(BIGNUM, bnY);

        return 0;

    }


    int EC_KEY_to_EVP_PKEY(const EC_KEY *ecKey, EVP_PKEY **evpKey)

    {

        if (NULL == ecKey) {

            LOG_E("param error");

            return ERROR_PARAM;

        }


        if (NULL != (*evpKey)) {

            EVP_PKEY_free(*evpKey);

            *evpKey = NULL;

        }


        *evpKey = EVP_PKEY_new();

        if (NULL == (*evpKey)) {

            LOG_E("EVP_PKEY_new : %ld, %s", ERR_get_error(), ERR_reason_error_string(ERR_get_error()));

            return ERROR_EVP_PKEY_NEW;

        }


        if (1 != EVP_PKEY_set1_EC_KEY(*evpKey, (EC_KEY*)ecKey)) {

            LOG_E("EVP_PKEY_set1_EC_KEY : %ld, %s", ERR_get_error(), ERR_reason_error_string(ERR_get_error()));

            EVP_PKEY_free(*evpKey);

            *evpKey = NULL;

            return -1;

        }

        LOG_D("ec key to evp key success");

        return 0;

    }


    int get_evp_public_key_ecc(const unsigned char *, size_t keyLen, int nid, EVP_PKEY **evpKey)

    {

        if ((NULL == key) || (keyLen <= 0)) {

            LOG_E("param error");

            return ERROR_PARAM;

        }


        int ret = 0;

        unsigned char tmpPublicKey[1024] = {0};


        if (keyLen == 65) {

            memcpy(tmpPublicKey, key + 1, keyLen -1);

        } else if (keyLen == 64) {

            memcpy(tmpPublicKey, key, keyLen);

        } else {

            return ERROR_NOT_SUPPORT;

        }

        unsigned char tmpX[64] = {0};

        unsigned char tmpY[64] = {0};

        memcpy(tmpX, tmpPublicKey, 32);

        memcpy(tmpY, tmpPublicKey + 32, 32);

        LOG_H((const unsigned char*)tmpX, 32);

        LOG_H((const unsigned char*)tmpY, 32);

        EC_KEY *ecPublicKey = NULL;

        ret = get_ec_public_key_from_x_y(tmpX, tmpY, nid, &ecPublicKey);

        if (0 != ret) {

            LOG_E("get ec public key error");

            return ret;

        }


        ret = EC_KEY_to_EVP_PKEY(ecPublicKey, evpKey);

        if (0 != ret) {

            LOG_E("ec key to evp key error");

            EC_KEY_free(ecPublicKey);

            ecPublicKey = NULL;

            return ret;

        }

        EC_KEY_free(ecPublicKey);

        ecPublicKey = NULL;

        return ret;

    }

    三、在openssl-3.0中的解決方案

    注:

    1.代碼實現中的返回值定義,日志輸出函數,內存釋放函數需自行實現。

    2.如果x,y的二進制數據中包含0x00構建EVP_PKEY結構將失敗。


    /**

     * @brief                               通過x,y,以及算法的nid構建公鑰的EVP_PKEY結構

     *

     * @param x[in]                    ECC算法公鑰中,x的數據

     * @param y[in]                ECC算法公鑰中,y的數據

     * @param nid[in]                當前ECC算法的NID

     * @param evpPublicKey[out]                     公鑰的ECVP_PKEY結構

     *

     * @return                              0 - success, !0 - error

     */

    int get_evp_pkey_from_ecc_xy(const unsigned char *x, const unsigned char *y, int nid, 

    EVP_PKEY **evpPublicKey)

    {

    // 判斷參數是否為空

       if ((NULL == x) || (NULL == y) || (NULL == evpPublicKey)) {

           LOG_E("param error");

           return ERROR_PARAM;

       }


       if (NULL != (*evpPublicKey)) {

           WY_OPENSSL_FREE(EVP_PKEY, *evpPublicKey);

           *evpPublicKey = NULL;

       }


       unsigned char publicKey[512] = {0};

       int tmpPublicKeyLen = 0;

       char* algStr = NULL;

       switch (nid)

       {

       case NID_X9_62_prime256v1:

           algStr = "prime256v1";

           break;

       default:

           return ERROR_NOT_SUPPORT; 

           break;

       }


       size_t xLen = strlen((const char*)x);

       size_t yLen = strlen((const char*)y);

       // 用于表是數據的格式,通常使用0x04表示,構建公鑰數據: 格式: 0x04 + x + y

       int hea = POINT_CONVERSION_UNCOMPRESSED;

       memcpy(publicKey + tmpPublicKeyLen, (unsigned char*)&hea, 1);

       tmpPublicKeyLen += 1;

       memcpy(publicKey + tmpPublicKeyLen, x, xLen);

       tmpPublicKeyLen += xLen;

       memcpy(publicKey + tmpPublicKeyLen, y, yLen);

       size_t publicKeyLen = tmpPublicKeyLen + yLen;


    // 

       OSSL_PARAM_BLD *paramsBuild = OSSL_PARAM_BLD_new();

       if (NULL == paramsBuild) {

           LOG_E("OSSL_PARAM_BLD_new error : %ld, %s", ERR_get_error(), ERR_reason_error_string(ERR_get_error()));

           return 1;

       }

    // 將ECC算法名稱構建到結構體中

       OSSL_PARAM_BLD_push_utf8_string(paramsBuild, OSSL_PKEY_PARAM_GROUP_NAME, algStr, 0);

       // 將公鑰數據構建到結構體中

       OSSL_PARAM_BLD_push_octet_string(paramsBuild, OSSL_PKEY_PARAM_PUB_KEY, publicKey, publicKeyLen);

       // 將構建器中已經定義的參數轉換成可以被 OpenSSL 的其他部分使用的 OSSL_PARAM 數組

       OSSL_PARAM *params = OSSL_PARAM_BLD_to_param(paramsBuild);

       if (NULL == params) {

           LOG_E("OSSL_PARAM_BLD_to_param error : %ld, %s", ERR_get_error(), ERR_reason_error_string(ERR_get_error()));

           WY_OPENSSL_FREE(OSSL_PARAM_BLD, paramsBuild);

           return 1;

       }


    // 根據給定的算法名稱創建一個 EVP_PKEY_CTX 上下文

       EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL);

       if (NULL == ctx) {

           LOG_E("EVP_PKEY_CTX_new_from_name error : %ld, %s", ERR_get_error(), ERR_reason_error_string(ERR_get_error()));

           WY_OPENSSL_FREE(OSSL_PARAM_BLD, paramsBuild);

           return 1;

       }


       EVP_PKEY *tmpEvpPublicKey = NULL;

       EVP_PKEY_fromdata_init(ctx);

       int status = EVP_PKEY_fromdata(ctx, &tmpEvpPublicKey, EVP_PKEY_PUBLIC_KEY, params);

       if (status <= 0 || tmpEvpPublicKey == NULL) {

           LOG_E("status : %d", status);

           LOG_E("EVP_PKEY_fromdata error : %ld, %s", ERR_get_error(), ERR_reason_error_string(ERR_get_error()));

           WY_OPENSSL_FREE(OSSL_PARAM, params);

           WY_OPENSSL_FREE(OSSL_PARAM_BLD, paramsBuild);

           WY_OPENSSL_FREE(EVP_PKEY_CTX, ctx);

           return 1;

       }


       *evpPublicKey = EVP_PKEY_dup(tmpEvpPublicKey);


       WY_OPENSSL_FREE(EVP_PKEY, tmpEvpPublicKey);

       WY_OPENSSL_FREE(OSSL_PARAM, params);

       WY_OPENSSL_FREE(OSSL_PARAM_BLD, paramsBuild);

       WY_OPENSSL_FREE(EVP_PKEY_CTX, ctx);


       return 0;

    }



    ————————————————


                            

    原文鏈接:https://blog.csdn.net/dream_yaya/article/details/140553623


    *博客內容為網友個人發布,僅代表博主個人觀點,如有侵權請聯系工作人員刪除。



    關鍵詞: openssl

    技術專區

    關閉
    主站蜘蛛池模板: 长宁区| 赤峰市| 镇雄县| 舟山市| 稷山县| 临洮县| 彰化县| 赤城县| 普陀区| 和龙市| 新乡市| 开化县| 桃园县| 合川市| 泽州县| 马公市| 宁陕县| 呼伦贝尔市| 上林县| 福安市| 炉霍县| 合水县| 富平县| 桃园市| 牡丹江市| 攀枝花市| 漾濞| 双柏县| 霍城县| 博湖县| 苍梧县| 雷州市| 沂南县| 藁城市| 左贡县| 万盛区| 稻城县| 内江市| 连州市| 四平市| 嵊州市|