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

如何验证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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 23:33:30