如何在C语言中用OpenSSL库自动生成密钥对并实现加解密?
在C语言中使用OpenSSL自动生成密钥对并实现加解密的完整指南
Got it!既然你已经能用固定密钥完成OpenSSL加解密了,那自动生成密钥对(不管是非对称的RSA密钥对,还是对称加密的随机密钥)其实都是OpenSSL的标准操作。下面我分情况给你拆解具体步骤,再附上可运行的代码示例,帮你快速落地。
一、非对称加密(RSA密钥对):公钥加密,私钥解密
如果你的场景需要跨主体安全传输数据,RSA是最常用的非对称加密选择。以下是完整实现步骤:
1. 初始化OpenSSL环境
首先要初始化OpenSSL的加密库,不同版本的初始化方式略有差异,这里推荐适配1.1.0+版本的新接口:
OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL); OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
如果是1.0.x版本,替换为:
SSL_library_init(); OpenSSL_add_all_algorithms(); ERR_load_crypto_strings();
2. 生成RSA密钥对
创建RSA结构体,指定密钥长度(推荐2048位及以上,兼顾安全和性能)和公钥指数(通常用RSA_F4即65537):
RSA *rsa = RSA_new(); BIGNUM *bne = BN_new(); BN_set_word(bne, RSA_F4); // 生成2048位密钥对 RSA_generate_key_ex(rsa, 2048, bne, NULL);
3. 提取/导出密钥(可选)
可以把公钥和私钥导出为PEM格式(方便存储或传输),也可以直接在内存中使用:
// 导出公钥到内存BIO BIO *pub_bio = BIO_new(BIO_s_mem()); PEM_write_bio_RSAPublicKey(pub_bio, rsa); // 导出私钥到内存BIO BIO *pri_bio = BIO_new(BIO_s_mem()); PEM_write_bio_RSAPrivateKey(pri_bio, rsa, NULL, NULL, 0, NULL, NULL);
4. 公钥加密数据
使用RSA_public_encrypt函数,注意明文长度不能超过密钥长度-11(PKCS#1 v1.5填充规则),2048位RSA最多加密245字节:
const char *plaintext = "Hello, OpenSSL RSA!"; unsigned char ciphertext[256]; // 2048位RSA加密后固定256字节 int cipher_len = RSA_public_encrypt(strlen(plaintext), (unsigned char*)plaintext, ciphertext, rsa, RSA_PKCS1_PADDING);
5. 私钥解密数据
用RSA_private_decrypt对应解密,填充方式要和加密一致:
unsigned char decrypted[256]; int decrypted_len = RSA_private_decrypt(cipher_len, ciphertext, decrypted, rsa, RSA_PKCS1_PADDING); decrypted[decrypted_len] = '\0'; // 添加字符串结束符
6. 清理资源
OpenSSL的结构体必须手动释放,避免内存泄漏:
RSA_free(rsa); BN_free(bne); BIO_free(pub_bio); BIO_free(pri_bio); EVP_cleanup(); ERR_free_strings();
二、完整可运行的RSA示例代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <openssl/rsa.h> #include <openssl/pem.h> #include <openssl/err.h> // 错误处理函数,打印OpenSSL错误信息 void handle_errors() { ERR_print_errors_fp(stderr); abort(); } int main() { // 初始化OpenSSL环境(适配1.1.0+) OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL); OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); RSA *rsa = NULL; BIGNUM *bne = NULL; const int bits = 2048; const unsigned long e = RSA_F4; // 创建并生成RSA密钥对 bne = BN_new(); if (!BN_set_word(bne, e)) handle_errors(); rsa = RSA_new(); if (!RSA_generate_key_ex(rsa, bits, bne, NULL)) handle_errors(); // 导出公钥和私钥到内存 BIO *pub_bio = BIO_new(BIO_s_mem()); BIO *pri_bio = BIO_new(BIO_s_mem()); if (!PEM_write_bio_RSAPublicKey(pub_bio, rsa)) handle_errors(); if (!PEM_write_bio_RSAPrivateKey(pri_bio, rsa, NULL, NULL, 0, NULL, NULL)) handle_errors(); // 打印密钥(可选,用于验证) char pub_key[2048], pri_key[4096]; int pub_len = BIO_read(pub_bio, pub_key, sizeof(pub_key)-1); int pri_len = BIO_read(pri_bio, pri_key, sizeof(pri_key)-1); pub_key[pub_len] = '\0'; pri_key[pri_len] = '\0'; printf("=== 生成的公钥 ===\n%s\n", pub_key); printf("=== 生成的私钥 ===\n%s\n", pri_key); // 准备明文并加密 const char *plaintext = "这是一段要加密的测试字符串!"; unsigned char ciphertext[256]; int cipher_len = RSA_public_encrypt(strlen(plaintext), (unsigned char*)plaintext, ciphertext, rsa, RSA_PKCS1_PADDING); if (cipher_len == -1) handle_errors(); printf("\n=== 加密后数据(十六进制) ===\n"); for (int i=0; i<cipher_len; i++) { printf("%02x", ciphertext[i]); } printf("\n"); // 解密数据 unsigned char decrypted[256]; int decrypted_len = RSA_private_decrypt(cipher_len, ciphertext, decrypted, rsa, RSA_PKCS1_PADDING); if (decrypted_len == -1) handle_errors(); decrypted[decrypted_len] = '\0'; printf("\n=== 解密后明文 ===\n%s\n", decrypted); // 清理所有资源 RSA_free(rsa); BN_free(bne); BIO_free(pub_bio); BIO_free(pri_bio); EVP_cleanup(); ERR_free_strings(); return 0; }
编译命令:
gcc -o rsa_demo rsa_demo.c -lcrypto
三、对称加密(AES):生成随机密钥+IV
如果你的场景是单主体加解密(比如本地存储),对称加密更高效。此时不需要密钥对,而是生成随机的密钥和初始化向量(IV):
核心步骤
- 用
RAND_bytes生成随机密钥(AES-128用16字节,AES-256用32字节)和IV(通常16字节) - 使用OpenSSL的EVP高级接口完成加解密(比低级接口更安全)
示例代码片段
#include <openssl/evp.h> #include <openssl/rand.h> // 生成AES-256密钥和IV unsigned char aes_key[32], aes_iv[16]; if (!RAND_bytes(aes_key, sizeof(aes_key)) || !RAND_bytes(aes_iv, sizeof(aes_iv))) { handle_errors(); } // 后续使用EVP_CIPHER_CTX_new()、EVP_EncryptInit_ex()等接口完成加解密
四、关键注意事项
- 密钥长度:RSA推荐至少2048位,1024位已被破解;AES推荐用256位。
- 填充方式:RSA推荐用
RSA_OAEP_PADDING(比PKCS#1更安全),对称加密默认用PKCS#7填充。 - 大文件加密:RSA只能加密小数据,大文件建议用混合加密:RSA加密AES密钥,AES加密文件。
- 随机数安全:生成密钥/IV时必须用
RAND_bytes(加密安全的随机数生成器),不能用普通的rand()。
内容的提问来源于stack exchange,提问作者a verma
相关产品推荐
相关产品推荐

