首页 > 解决方案 > 为了在 libcrypto 中与 CryptoAPI 兼容的签名,更改 PEM 编码的私钥/公钥对的字节序

问题描述

我正在编写一个程序,它能够签署和验证最初为 CryptoAPI(旧的 Windows 加密库)制作的签名。目标是能够从 linux 签名/验证。

但是,由于 CryptoAPI 和 libcrypto 具有不同的字节顺序,我似乎碰壁了。

我已经尝试颠倒要验证的签名的顺序(整个 128 字节的 RSA 加密块,带有填充和所有)。这似乎还不够,我正在努力寻找一个合适的直截了当的食谱来轻松地做到这一点。

我从另一个 stackoverflow 帖子中发现,您需要反转实际密钥的字节序。因此,我想知道是否有任何简单的方法可以做到这一点,我最好不必自己弄乱数据。

我将坚持验证,因为我假设相同的工作流程可以应用于私钥 PEM。情况是这样的:

我将公钥作为 PEM,使用命令转换

openssl rsa -pubin -inform MS\ PUBLICKEYBLOB -in pkey_mspublic.bin -outform PEM -out pubkey.pem

以下是我如何将 PEM 加载到 libcrypto 并验证签名:

BIO* certBio = BIO_new_mem_buf((void*)pubkey, -1);

RSA* rsa = NULL;
rsa = PEM_read_bio_RSA_PUBKEY(certBio, &rsa,NULL, NULL);

for (int i=0; i <signatureLength; i++)
{
   char tmp = expectedHashPtr[i];
   expectedHashPtr[i] = expectedHashPtr[signatureLength - 1 - i];
   expectedHashPtr[signatureLength - 1 - i] = tmp;
}

EVP_PKEY* pubKey  = EVP_PKEY_new();
EVP_PKEY_assign_RSA(pubKey, rsa);
std::cout << "pubkey size: " << EVP_PKEY_size(pubKey) << std::endl;
EVP_MD_CTX* mdctx = EVP_MD_CTX_create();

if(!(mdctx = EVP_MD_CTX_create())) std::cout << "ctx create fail" << std::endl;

if(1 != EVP_VerifyInit(mdctx, EVP_md5())) std::cout << "digest init fail" << std::endl;

if(1 != EVP_VerifyUpdate(mdctx, data, 512)) std::cout << "digest fail" << std::endl;

std::cout << "finishing verify" << std::endl;
if(1 == EVP_VerifyFinal(mdctx, (unsigned char*)expectedHashPtr, signatureLength, pubKey))
{
    /* Success */
    std::cout << "Success" << std::endl;
    return true;
}
else
{
    ERR_print_errors_fp(stderr);
    std::cout << "Fail" << std::endl;
    return false;
}

当我运行上面的代码时,我得到了填充错误,我认为这是因为我的键是错误的字节序,因此是错误的:

140278264301376:error:0407008A:rsa routines:RSA_padding_check_PKCS1_type_1:invalid padding:crypto/rsa/rsa_pk1.c:67:
140278264301376:error:04067072:rsa routines:rsa_ossl_public_decrypt:padding check failed:crypto/rsa/rsa_ossl.c:582:

所以,我的问题是,是否有一种快速简便的方法来处理 PEM 格式的公钥和私钥的字节序转换?我不想手动执行此操作,因为它必须按比例缩放。

标签: endiannesscryptoapilibcrypto

解决方案


推荐阅读