如何验证RSA密钥对有效性?解决OpenSSL中RSA无n参数问题
解决RSA密钥对验证问题
一、修复原代码的问题
你的代码失效是因为OpenSSL 3.0及以后版本对RSA结构体做了不透明处理,无法直接访问n成员,需要改用官方提供的访问函数RSA_get0_n()来获取模数。修改后的代码如下:
#include <openssl/rsa.h> #include <openssl/pem.h> #include <openssl/bn.h> int main() { // 实际使用时需补充文件指针,示例从本地文件读取密钥 FILE *pub_file = fopen("public.pem", "r"); FILE *priv_file = fopen("private.pem", "r"); RSA *pubkey = PEM_read_RSA_PUBKEY(pub_file, NULL, NULL, NULL); RSA *privkey = PEM_read_RSAPrivateKey(priv_file, NULL, NULL, NULL); if (pubkey && privkey) { const BIGNUM *pub_n = RSA_get0_n(pubkey); const BIGNUM *priv_n = RSA_get0_n(privkey); if (!BN_cmp(pub_n, priv_n)) { // 模数一致,密钥对初步匹配 printf("密钥对模数匹配\n"); } else { printf("密钥对模数不匹配\n"); } } // 释放资源 RSA_free(pubkey); RSA_free(privkey); fclose(pub_file); fclose(priv_file); return 0; }
二、更可靠的密钥对验证方法
仅验证模数一致只能做初步检查,更严谨的方式是用公钥加密一段数据,再用私钥解密验证结果,或用私钥签名、公钥验签,确保密钥对的功能完整性:
方法1:加解密测试
#include <openssl/rsa.h> #include <openssl/pem.h> #include <openssl/err.h> #include <string.h> int rsa_key_pair_validate(RSA *pubkey, RSA *privkey) { const char *test_data = "Test RSA Key Pair Validation"; int data_len = strlen(test_data); unsigned char encrypted[4096] = {0}; unsigned char decrypted[4096] = {0}; int enc_len, dec_len; // 公钥加密 enc_len = RSA_public_encrypt(data_len, (unsigned char*)test_data, encrypted, pubkey, RSA_PKCS1_PADDING); if (enc_len == -1) { ERR_print_errors_fp(stderr); return 0; } // 私钥解密 dec_len = RSA_private_decrypt(enc_len, encrypted, decrypted, privkey, RSA_PKCS1_PADDING); if (dec_len == -1) { ERR_print_errors_fp(stderr); return 0; } // 验证解密结果 decrypted[dec_len] = '\0'; return strcmp((char*)decrypted, test_data) == 0; } int main() { FILE *pub_file = fopen("public.pem", "r"); FILE *priv_file = fopen("private.pem", "r"); RSA *pubkey = PEM_read_RSA_PUBKEY(pub_file, NULL, NULL, NULL); RSA *privkey = PEM_read_RSAPrivateKey(priv_file, NULL, NULL, NULL); if (pubkey && privkey) { if (rsa_key_pair_validate(pubkey, privkey)) { printf("密钥对功能验证通过\n"); } else { printf("密钥对功能验证失败\n"); } } RSA_free(pubkey); RSA_free(privkey); fclose(pub_file); fclose(priv_file); return 0; }
方法2:使用OpenSSL 3.0+的EVP接口(推荐)
OpenSSL 3.0+推荐使用EVP抽象接口,兼容性更好:
#include <openssl/evp.h> #include <openssl/pem.h> #include <openssl/err.h> #include <string.h> int evp_rsa_key_pair_validate(EVP_PKEY *pubkey, EVP_PKEY *privkey) { const char *test_data = "Test EVP RSA Key Validation"; size_t data_len = strlen(test_data); unsigned char encrypted[4096] = {0}; unsigned char decrypted[4096] = {0}; size_t enc_len, dec_len; // 初始化加密上下文 EVP_PKEY_CTX *enc_ctx = EVP_PKEY_CTX_new(pubkey, NULL); if (!enc_ctx || EVP_PKEY_encrypt_init(enc_ctx) <= 0) { ERR_print_errors_fp(stderr); EVP_PKEY_CTX_free(enc_ctx); return 0; } EVP_PKEY_CTX_set_rsa_padding(enc_ctx, RSA_PKCS1_PADDING); // 执行加密 if (EVP_PKEY_encrypt(enc_ctx, NULL, &enc_len, (unsigned char*)test_data, data_len) <= 0) { ERR_print_errors_fp(stderr); EVP_PKEY_CTX_free(enc_ctx); return 0; } if (EVP_PKEY_encrypt(enc_ctx, encrypted, &enc_len, (unsigned char*)test_data, data_len) <= 0) { ERR_print_errors_fp(stderr); EVP_PKEY_CTX_free(enc_ctx); return 0; } EVP_PKEY_CTX_free(enc_ctx); // 初始化解密上下文 EVP_PKEY_CTX *dec_ctx = EVP_PKEY_CTX_new(privkey, NULL); if (!dec_ctx || EVP_PKEY_decrypt_init(dec_ctx) <= 0) { ERR_print_errors_fp(stderr); EVP_PKEY_CTX_free(dec_ctx); return 0; } EVP_PKEY_CTX_set_rsa_padding(dec_ctx, RSA_PKCS1_PADDING); // 执行解密 if (EVP_PKEY_decrypt(dec_ctx, NULL, &dec_len, encrypted, enc_len) <= 0) { ERR_print_errors_fp(stderr); EVP_PKEY_CTX_free(dec_ctx); return 0; } if (EVP_PKEY_decrypt(dec_ctx, decrypted, &dec_len, encrypted, enc_len) <= 0) { ERR_print_errors_fp(stderr); EVP_PKEY_CTX_free(dec_ctx); return 0; } EVP_PKEY_CTX_free(dec_ctx); // 验证结果 decrypted[dec_len] = '\0'; return strcmp((char*)decrypted, test_data) == 0; } int main() { FILE *pub_file = fopen("public.pem", "r"); FILE *priv_file = fopen("private.pem", "r"); EVP_PKEY *pubkey = PEM_read_PUBKEY(pub_file, NULL, NULL, NULL); EVP_PKEY *privkey = PEM_read_PrivateKey(priv_file, NULL, NULL, NULL); if (pubkey && privkey) { if (evp_rsa_key_pair_validate(pubkey, privkey)) { printf("EVP接口密钥对验证通过\n"); } else { printf("EVP接口密钥对验证失败\n"); } } EVP_PKEY_free(pubkey); EVP_PKEY_free(privkey); fclose(pub_file); fclose(priv_file); return 0; }
注意事项
- 编译时需链接OpenSSL库,示例命令:
gcc test_rsa.c -o test_rsa -lcrypto - 确保密钥文件为PEM格式,公钥通常以
-----BEGIN PUBLIC KEY-----开头,私钥以-----BEGIN RSA PRIVATE KEY-----或-----BEGIN PRIVATE KEY-----开头
内容的提问来源于stack exchange,提问作者Lamens
相关产品推荐
相关产品推荐

