如何在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; }
其他注意事项
- 加密结果是二进制数据,不能直接用
%s格式化打印(tappa_print("\"ENCRYPTED: %s", (char *)encrypted);),会因遇到终止符截断,建议转为十六进制输出。 - 程序初始化时需调用
OpenSSL_add_all_algorithms()和ERR_load_crypto_strings(),确保错误信息能正常打印。 - 所有OpenSSL资源(
EVP_PKEY、EVP_PKEY_CTX、BIO等)必须在使用后释放,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Lilvinco
相关产品推荐
相关产品推荐

