OpenSSL3.0 - ECDSA 签名验证

问题描述 投票:0回答:1

我目前正在使用 OpenSSL3.0 编写一个 C++ 程序,该程序采用一串数据、EDCSA 签名,并使用存储在 .pem 文件中的 EC 公钥检查有效性。

目前我已尝试使用 EVP_DigestVerifyFinal() 但不太清楚如何使用新 API 导入我的 EC 密钥来执行验证,而不使用已弃用的函数。

我尝试过 OSSL_DECODER_from_data,将公钥作为 const unsigned char* 提供给它,但没能让它正常工作。

这是我的验证尝试

 bool SignatureEcDSA::testVerif(const unsigned char* sig, const char* msg)
    {
        std::string key_ = "-----BEGIN PUBLIC "
                           "KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEy687PNFBHUW3KIYrgrdGtCY5bdDGvnbMj1v/"
                           "APR71dBv0mD3UXNULjAKSWVc4ahfIddpfX/i2N9ppMxVljk8BA==\n-----END PUBLIC KEY-----";

        EVP_PKEY*   key   = nullptr;
        EVP_MD_CTX* mdctx = EVP_MD_CTX_new();

        //make key get from key_
        BIO* keybio = BIO_new_mem_buf(key_.c_str(), -1);
        if (keybio == nullptr) {

            return false;
        }
        key = PEM_read_bio_PUBKEY(keybio, &key, nullptr, nullptr);

        if (1 != EVP_DigestVerifyInit(mdctx, nullptr, EVP_sha256(), nullptr, key))
            return false;

        if (1 != EVP_DigestVerifyUpdate(mdctx, msg, strlen(msg))) {
            return false;
        }

        if (1 == EVP_DigestVerifyFinal(mdctx, sig, strlen((const char*) sig))) {
            return true;
        }
    }

这是我尝试制作OSSL_Decoder_from_data,它来自https://www.openssl.org/docs/man3.0/man3/OSSL_DECODER_from_bio.html

const char* key_ = "-----BEGIN PUBLIC "
                           "KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEy687PNFBHUW3KIYrgrdGtCY5bdDGvnbMj1v/"
                           "APR71dBv0mD3UXNULjAKSWVc4ahfIddpfX/i2N9ppMxVljk8BA==\n-----END PUBLIC KEY-----";

        OSSL_DECODER_CTX* dctx;
        EVP_PKEY*         pkey      = NULL;
        const char*       format    = "PEM"; /* NULL for any format */
        const char*       structure = NULL;  /* any structure */
        const char*       keytype   = "EC";  /* NULL for any key */
        auto*             data      = (const unsigned char*) key_;
        size_t            datalen   = sizeof(key_);

        dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, format, structure, keytype,
                                             OSSL_KEYMGMT_SELECT_KEYPAIR | OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS, NULL, NULL);
        if (dctx == NULL) {
            std::cout << "No decoder context" << std::endl;
        }
        if (OSSL_DECODER_from_data(dctx, &data, &datalen)) {
            std::cout << "OSSL_DECODER_from_data success" << std::endl;
        }
        else {
            std::cout << "OSSL_DECODER_from_data failed" << std::endl; //fails here
        }
        OSSL_DECODER_CTX_free(dctx);

这里仍然使用字符串作为初始 EC 密钥,但我想从文件中打开它。

如果有人对我如何完成这项工作有任何提示,我将不胜感激!

谢谢

编辑:

我在测试之前尝试过这里提出的解决方案,但它使用 PEM_read_bio_EC_PUBKEY 已弃用的函数:ECDSA 签名验证:Go vs OpenSSL

来自 https://www.openssl.org/docs/man3.0/man3/PEM_read_bio_EC_PUBKEY.html:应用程序应该使用 OSSL_ENCODER_to_bio() 和 OSSL_DECODER_from_bio(),但也没有设法使其工作。

c++ openssl ecdsa
1个回答
0
投票

看来您使用 OSSL_DECODER_from_data 方法走在正确的轨道上,以避免不推荐使用的函数。但是,您的代码中存在一些问题可能会导致该问题。

密钥长度问题: 在 OSSL_DECODER_from_data 尝试中,您使用 sizeof(key_) 来确定密钥数据的长度。这将为您提供指针的大小,而不是数据的实际长度。您应该使用 strlen(key_) 代替。

释放后的内存所有权和使用: 使用 OSSL_DECODER_from_data 时,解码器获取输入数据的所有权,因此在将其传递给解码器后不应修改或释放它。但是,在您的代码中,您尝试在使用解码器上下文之前释放它,这可能会导致未定义的行为。

这是代码的更正版本:

const char* key_ = "-----BEGIN PUBLIC "
               "KEY----- 
\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEy687PNFBHUW3KIYrgrdGtCY5bdDGvnbMj1v/"
               "APR71dBv0mD3UXNULjAKSWVc4ahfIddpfX/i2N9ppMxVljk8BA==\n----- 
END PUBLIC KEY-----";

OSSL_DECODER_CTX* dctx;
EVP_PKEY* pkey = NULL;
const char* format = "PEM";   // NULL for any format
const char* structure = NULL; // any structure
const char* keytype = "EC";    // NULL for any key
const unsigned char* data = (const unsigned char*)key_;
size_t datalen = strlen(key_); // Use strlen instead of sizeof

dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, format, structure, keytype,
                                 OSSL_KEYMGMT_SELECT_KEYPAIR | 
OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS, NULL, NULL);
if (dctx == NULL) {
std::cout << "No decoder context" << std::endl;
}
if (OSSL_DECODER_from_data(dctx, &data, &datalen)) {
std::cout << "OSSL_DECODER_from_data success" << std::endl;
// You can use 'pkey' for verification here
} else {
std::cout << "OSSL_DECODER_from_data failed" << std::endl;
}

// 不要在这里释放 dctx,因为它拥有“数据”的所有权 OSSL_DECODER_CTX_free(dctx);

请确保使用从 OSSL_DECODER_from_data 调用中获取的 pkey 相应地调整验证码的其余部分。

© www.soinside.com 2019 - 2024. All rights reserved.