You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C语言中从公钥字符串创建OpenSSL的EVP_PKEY

问题:从PEM格式公钥字符串创建EVP_PKEY返回NULL

我在C语言中使用OpenSSL,需要通过外部共享的公钥对字符串做RSA PKCS1 OAEP(SHA1哈希)加密。自己生成密钥时加密逻辑能正常运行,但尝试从PEM格式的公钥字符串创建EVP_PKEY时,调用EVP_PKEY_new_raw_public_key返回NULL,无法继续加密。

错误代码片段:

int rsaEvpKeyGen(EVP_PKEY **outPK){
    EVP_PKEY * pkey = NULL;
    const char *pub_key_str = "-----BEGIN PUBLIC KEY-----\n"
                              "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1WRkqlsZbmaNWbOZr/M4\n"
                              "ddwXKjmHUJ8zn9hy0WE15A8T4xjNuzJ/ATKbz20/2wVgFEGTWPNCUjkUvFzr3mhN\n"
                              "v/YJXo5iXQDP3M6rVv/w3SXaiR9C8yhDxWUz7WX/clmj7vDvk5Iydgq07gVScx+\n"
                              "5DBVbGAx10jHSDSa7f/NXMn9yNHad4hN0i1l+tsTB39CFsNeVFr349y4R8HA5Zma\n"
                              "EKseLc8iKzkwEQcuyMn4znaFpnOL0CmSrYB5K1E9zmmtDhMvDs540ZotcH/xpJiV\n"
                              "XEdQOWGFN6rryeAKP8y+sMRfQLxoiTg37YfsxTscf0gzKBizoamTF3TjRUNM55aE\n"
                              "BwIDAQAB\n"
                              "-----END PUBLIC KEY-----";

    pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_RSA,NULL, (const unsigned char *) pub_key_str,
                                       strlen(pub_key_str) );

    tappa_printf("PKEY is null %d",pkey == NULL);
  
    *outPK =pkey;
    
    return 0;
}

解决方案

错误原因

EVP_PKEY_new_raw_public_key仅支持原始二进制格式的公钥(比如直接的RSA模数+指数字节流),而你传入的是带-----BEGIN PUBLIC KEY-----头的PEM格式Base64编码公钥,接口不匹配导致返回NULL。处理PEM格式公钥需要使用OpenSSL的PEM解析接口。

正确的PEM公钥解析代码

替换你的rsaEvpKeyGen函数为以下实现:

#include <openssl/pem.h>
#include <openssl/err.h>

int rsaEvpKeyGen(EVP_PKEY **outPK){
    EVP_PKEY *pkey = NULL;
    BIO *bio = NULL;
    const char *pub_key_str = "-----BEGIN PUBLIC KEY-----\n"
                              "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1WRkqlsZbmaNWbOZr/M4\n"
                              "ddwXKjmHUJ8zn9hy0WE15A8T4xjNuzJ/ATKbz20/2wVgFEGTWPNCUjkUvFzr3mhN\n"
                              "v/YJXo5iXQDP3M6rVv/w3SXaiR9C8yhDxWUz7WX/clmj7vDvk5Iydgq07gVScx+\n"
                              "5DBVbGAx10jHSDSa7f/NXMn9yNHad4hN0i1l+tsTB39CFsNeVFr349y4R8HA5Zma\n"
                              "EKseLc8iKzkwEQcuyMn4znaFpnOL0CmSrYB5K1E9zmmtDhMvDs540ZotcH/xpJiV\n"
                              "XEdQOWGFN6rryeAKP8y+sMRfQLxoiTg37YfsxTscf0gzKBizoamTF3TjRUNM55aE\n"
                              "BwIDAQAB\n"
                              "-----END PUBLIC KEY-----";

    // 创建内存BIO读取PEM字符串
    bio = BIO_new_mem_buf(pub_key_str, -1);
    if (!bio) {
        goto cleanup;
    }

    // 从BIO解析PEM格式公钥
    pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
    if (!pkey) {
        ERR_print_errors_fp(stderr); // 打印详细错误信息用于调试
        goto cleanup;
    }

    *outPK = pkey;
    pkey = NULL; // 避免cleanup阶段误释放

cleanup:
    if (bio) BIO_free(bio);
    if (pkey) EVP_PKEY_free(pkey);
    return (*outPK == NULL) ? 1 : 0;
}

补充:显式指定OAEP的SHA1哈希

你的加密函数仅设置了RSA_PKCS1_OAEP_PADDING,但OpenSSL默认OAEP哈希算法可能是SHA-256(版本差异),需显式指定SHA1以匹配需求,否则解密端会不兼容。在加密函数的EVP_PKEY_CTX_set_rsa_padding调用后添加:

// 设置OAEP使用SHA1哈希
if (EVP_PKEY_CTX_set_rsa_oaep_md(ctx, EVP_sha1()) <= 0) {
    cleanup(ctx, pkey, encrypted, NULL);
    return 10;
}

其他注意事项

  1. 加密结果是二进制数据,不能直接用%s格式化打印(tappa_print("\"ENCRYPTED: %s", (char *)encrypted);),会因遇到终止符截断,建议转为十六进制输出。
  2. 程序初始化时需调用OpenSSL_add_all_algorithms()和ERR_load_crypto_strings(),确保错误信息能正常打印。
  3. 所有OpenSSL资源(EVP_PKEY、EVP_PKEY_CTX、BIO等)必须在使用后释放,避免内存泄漏。

内容的提问来源于stack exchange,提问作者Lilvinco

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 19:24:55