签名在 openssl 命令行中验证,但不在 C++ 代码中验证

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

我正在使用 openssl api 编写 C++ 代码来执行以下功能

openssl dgst -sha256 -verify public_key.pem -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-1 -signature signature.sig sw-description

以下是我尝试过的C++代码

#include <openssl/core_names.h>
#include <openssl/evp.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/types.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <iomanip>

bool verify_signature(const std::string& signature_file, const std::string& public_key_file, const std::string& data_file)
{
    // Read the signature file
    std::ifstream sig_file(signature_file, std::ios::binary);
    if (!sig_file.is_open()) {
        std::cerr << "Failed to open signature file: " << signature_file << std::endl;
        return false;
    }
    std::vector<unsigned char> signature((std::istreambuf_iterator<char>(sig_file)), std::istreambuf_iterator<char>());
    sig_file.close();

    
     BIO* publicKeyBio = BIO_new_file(public_key_file.c_str(), "rb");
    if (!publicKeyBio) {
        perror("Failed to open public key file");
        return false;
    }
    EVP_PKEY* pkey = PEM_read_bio_PUBKEY(publicKeyBio, nullptr, nullptr, nullptr);
   
    if (!pkey) {
        ERR_print_errors_fp(stderr);
         std::cout<<"22";
        return false;
    }
    
    
    // Read the data file
    std::ifstream data_file_stream(data_file, std::ios::binary);
    if (!data_file_stream.is_open()) {
        std::cerr << "Failed to open data file: " << data_file << std::endl;
        
        return false;
    }
    std::vector<unsigned char> data((std::istreambuf_iterator<char>(data_file_stream)), std::istreambuf_iterator<char>());
    data_file_stream.close();

    // Create a digest of the data using SHA-256
    EVP_MD_CTX* md_ctx = EVP_MD_CTX_new();
    if (!md_ctx) {
        std::cerr << "Failed to create message digest context" << std::endl;
       
        return false;
    }
    if (EVP_DigestInit_ex(md_ctx, EVP_sha256(), nullptr) != 1) {
        std::cerr << "Failed to initialize message digest context" << std::endl;
        EVP_MD_CTX_free(md_ctx);
      
        return false;
    }
    if (EVP_DigestUpdate(md_ctx, data.data(), data.size()) != 1) {
        std::cerr << "Failed to update message digest" << std::endl;
        EVP_MD_CTX_free(md_ctx);
      
        return false;
    }
    unsigned char digest[EVP_MAX_MD_SIZE];
    unsigned int digest_len;
    if (EVP_DigestFinal_ex(md_ctx, digest, &digest_len) != 1) {
        std::cerr << "Failed to finalize message digest" << std::endl;
        EVP_MD_CTX_free(md_ctx);
      
        return false;
    }
    
    
    EVP_MD_CTX_free(md_ctx);

    // Verify the signature using the public key and PSS padding scheme
   
    EVP_MD_CTX* verify_ctx = EVP_MD_CTX_new();
    if (!verify_ctx) {
        std::cerr << "Failed to create signature verification context" << std::endl;
        EVP_PKEY_free(pkey);
       
        return false;
    }
    if (EVP_DigestVerifyInit(verify_ctx, nullptr, EVP_sha256(), nullptr, pkey) != 1) {
        std::cerr << "Failed to initialize signature verification context" << std::endl;
        EVP_MD_CTX_free(verify_ctx);
        EVP_PKEY_free(pkey);
       
        return false;
    }
    if (EVP_PKEY_CTX_set_rsa_padding(EVP_MD_CTX_pkey_ctx(verify_ctx), RSA_PKCS1_PSS_PADDING) <= 0) {
        std::cerr << "Failed to set RSA-PSS padding in signature verification context" << std::endl;
        EVP_MD_CTX_free(verify_ctx);
        EVP_PKEY_free(pkey);
       
        return false;
    }
    if (EVP_PKEY_CTX_set_rsa_pss_saltlen(EVP_MD_CTX_pkey_ctx(verify_ctx), -1) <= 0) {
        std::cerr << "Failed to set RSA-PSS salt length in signature verification context" << std::endl;
        EVP_MD_CTX_free(verify_ctx);
        EVP_PKEY_free(pkey);
       
        return false;
    }
    
    
    if (EVP_DigestVerifyUpdate(verify_ctx, digest, digest_len) != 1) {
        ERR_print_errors_fp(stderr);
        EVP_MD_CTX_free(verify_ctx);
        EVP_PKEY_free(pkey);
        return false;
    }

    // Verify the signature
    if(EVP_DigestVerifyFinal(verify_ctx, signature.data(), signature.size()) != 1) 
    {
      ERR_print_errors_fp(stderr);
        std::cerr << "Signature verification failed" << std::endl;
        EVP_MD_CTX_free(verify_ctx);
        EVP_PKEY_free(pkey);
       
        return false;
    } 
    EVP_MD_CTX_free(verify_ctx);
    EVP_PKEY_free(pkey);
   

    std::cout << "Signature verification succeeded" << std::endl;
    return true;
}

int main()
{
    std::string signature_file = "signature_direct.sig";
    std::string public_key_file = "public_key.pem";
    std::string data_file = "sw.swu";

    if (!verify_signature(signature_file, public_key_file, data_file)) {
        std::cerr << "Signature verification failed" << std::endl;
        return 1;
    }

    return 0;
}

运行上面的 openssl 命令时,签名验证正常,但是在 C++ 代码中使用相同的文件时,签名验证失败。

有人可以帮忙吗,我的代码哪里错了?

c++11 security openssl
1个回答
0
投票

首先,

EVP_DigestVerifyUpdate
对数据本身进行操作,而不是对数据的哈希进行操作。所以你不应该对数据进行哈希处理。您应该直接将其传递给
EVP_DigestVerifyUpdate
。所以第一步:

  • 删除“使用 SHA-256 创建数据摘要”中的所有代码
  • 像这样打电话给
    EVP_DigestVerifyUpdate
if (EVP_DigestVerifyUpdate(verify_ctx, data.data(), data.size()) != 1) {
                                       ^^^^^^^^^^^^^^^^^^^^^^^^

接下来,

EVP_PKEY_CTX_set_*
方法采用
EVP_PKEY_CTX
。编译器可能会警告您这一点,但您随后告诉编译器您通过强制转换知道自己在做什么:

if (EVP_PKEY_CTX_set_rsa_padding(EVP_MD_CTX_pkey_ctx(verify_ctx), RSA_PKCS1_PSS_PADDING) <= 0) {

EVP_MD_CTX
EVP_PKEY_CTX
不同。这只会破坏上下文。

相反,您需要依赖这样一个事实:如果您要求,

EVP_DigestVerifyInit
将返回其 PKEY 上下文:

EVP_PKEY_CTX* pkey_ctx = NULL;

    if (EVP_DigestVerifyInit(verify_ctx, &pkey_ctx, EVP_sha256(), nullptr, pkey) != 1) {

有了

pkey_ctx
可用,您可以配置它:

if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) <= 0) {
                                 ^^^^^^^^

if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, -1) <= 0) {
                                     ^^^^^^^^

我还修改了

main()
中的文件名以匹配您在
openssl
命令中使用的名称。这样,这就是完整的代码:

/**
 * Equivalent to:
 openssl genrsa -out private_key.pem 2048
 openssl rsa -in private_key.pem -pubout -out public_key.pem
 echo testfile > sw-description
 openssl dgst -sha256 -sign private_key.pem -out signature.sig -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-1 sw-description
 openssl dgst -sha256 -verify public_key.pem -signature signature.sig -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-1 sw-description
*/

#include <openssl/core_names.h>
#include <openssl/evp.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/types.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <iomanip>

bool verify_signature(const std::string& signature_file, const std::string& public_key_file, const std::string& data_file)
{
    // Read the signature file
    std::ifstream sig_file(signature_file, std::ios::binary);
    if (!sig_file.is_open()) {
        std::cerr << "Failed to open signature file: " << signature_file << std::endl;
        return false;
    }
    std::vector<unsigned char> signature((std::istreambuf_iterator<char>(sig_file)), std::istreambuf_iterator<char>());
    sig_file.close();

    
     BIO* publicKeyBio = BIO_new_file(public_key_file.c_str(), "rb");
    if (!publicKeyBio) {
        perror("Failed to open public key file");
        return false;
    }
    EVP_PKEY* pkey = PEM_read_bio_PUBKEY(publicKeyBio, nullptr, nullptr, nullptr);
   
    if (!pkey) {
        ERR_print_errors_fp(stderr);
         std::cout<<"22";
        return false;
    }
    
    
    // Read the data file
    std::ifstream data_file_stream(data_file, std::ios::binary);
    if (!data_file_stream.is_open()) {
        std::cerr << "Failed to open data file: " << data_file << std::endl;
        
        return false;
    }
    std::vector<unsigned char> data((std::istreambuf_iterator<char>(data_file_stream)), std::istreambuf_iterator<char>());
    data_file_stream.close();

    // Verify the signature using the public key and PSS padding scheme
   
    EVP_MD_CTX* verify_ctx = EVP_MD_CTX_new();
    if (!verify_ctx) {
        std::cerr << "Failed to create signature verification context" << std::endl;
        EVP_PKEY_free(pkey);
       
        return false;
    }

    EVP_PKEY_CTX* pkey_ctx = NULL;

    if (EVP_DigestVerifyInit(verify_ctx, &pkey_ctx, EVP_sha256(), nullptr, pkey) != 1) {
        std::cerr << "Failed to initialize signature verification context" << std::endl;
        EVP_MD_CTX_free(verify_ctx);
        EVP_PKEY_free(pkey);
       
        return false;
    }
    if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) <= 0) {
        std::cerr << "Failed to set RSA-PSS padding in signature verification context" << std::endl;
        EVP_MD_CTX_free(verify_ctx);
        EVP_PKEY_free(pkey);
       
        return false;
    }
    if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, -1) <= 0) {
        std::cerr << "Failed to set RSA-PSS salt length in signature verification context" << std::endl;
        EVP_MD_CTX_free(verify_ctx);
        EVP_PKEY_free(pkey);
       
        return false;
    }
    
    
    if (EVP_DigestVerifyUpdate(verify_ctx, data.data(), data.size()) != 1) {
        ERR_print_errors_fp(stderr);
        EVP_MD_CTX_free(verify_ctx);
        EVP_PKEY_free(pkey);
        return false;
    }

    // Verify the signature
    if(EVP_DigestVerifyFinal(verify_ctx, signature.data(), signature.size()) != 1) 
    {
      ERR_print_errors_fp(stderr);
        std::cerr << "Signature verification failed" << std::endl;
        EVP_MD_CTX_free(verify_ctx);
        EVP_PKEY_free(pkey);
       
        return false;
    } 
    EVP_MD_CTX_free(verify_ctx);
    EVP_PKEY_free(pkey);
   

    std::cout << "Signature verification succeeded" << std::endl;
    return true;
}

int main()
{
    std::string signature_file = "signature.sig";
    std::string public_key_file = "public_key.pem";
    std::string data_file = "sw-description";

    if (!verify_signature(signature_file, public_key_file, data_file)) {
        std::cerr << "Signature verification failed" << std::endl;
        return 1;
    }

    return 0;
}
© www.soinside.com 2019 - 2024. All rights reserved.