如何在C项目中静态链接OpenSSL实现RSA加密
C项目静态接入OpenSSL实现RSA加密方案
通常动态链接OpenSSL时加-lcrypto即可,但目标系统无预装OpenSSL时,必须把OpenSSL的代码直接编进可执行文件,也就是静态链接,具体操作步骤如下:
1. 先编译对应目标环境的静态版OpenSSL
系统源里装的OpenSSL一般只带动态库,不能直接用来静态链接,需要自己编译静态库版本:
- 准备对应版本的OpenSSL源码,优先选1.1.1w、3.0/3.1这类长期支持版本,注意3.x和1.1.x的部分API有差异,按需选择即可
- 解压源码进入根目录,执行配置命令,指定独立安装路径、关闭动态库编译:
# 以x86_64 Linux环境为例,交叉编译换对应工具链即可 ./config no-shared no-asm --prefix=/opt/openssl-static -fPIC
参数说明:
no-shared:只生成静态库(.a后缀),不生成动态库(.so后缀)--prefix:指定静态库的独立安装目录,别和系统自带OpenSSL路径混了,避免覆盖系统文件no-asm:关闭汇编优化,规避部分小众架构下的编译兼容问题,x86/arm常规环境可以去掉这个参数-fPIC:生成位置无关代码,避免后续链接到主程序时出现重定位错误- 执行编译安装:
make -j$(nproc) make install
编译完成后,/opt/openssl-static/lib目录下的libcrypto.a就是需要的静态加密库,include目录是配套头文件。
2. 编写RSA加解密业务代码
静态链接时OpenSSL的API调用逻辑和动态链接完全一致,不需要改业务写法,参考最简RSA公钥加密示例:
#include <stdio.h> #include <string.h> #include <openssl/rsa.h> #include <openssl/pem.h> #include <openssl/err.h> // 2048位RSA用PKCS1填充时,单次加密最大明文长度为256-11=245字节 #define MAX_ENCRYPT_LEN 245 #define PUB_KEY_PATH "./test_pub.pem" int main() { // 初始化OpenSSL算法和错误栈 OpenSSL_add_all_algorithms(); ERR_load_CRYPTO_strings(); // 读取本地PEM格式公钥 FILE *pub_fp = fopen(PUB_KEY_PATH, "rb"); if (!pub_fp) { perror("公钥文件打开失败"); return 1; } RSA *rsa = PEM_read_RSA_PUBKEY(pub_fp, NULL, NULL, NULL); fclose(pub_fp); if (!rsa) { ERR_print_errors_fp(stderr); return 1; } unsigned char cipher_buf[256] = {0}; const char *plain_text = "static link openssl rsa test"; // 执行公钥加密 int cipher_len = RSA_public_encrypt( strlen(plain_text), (const unsigned char*)plain_text, cipher_buf, rsa, RSA_PKCS1_PADDING ); if (cipher_len == -1) { ERR_print_errors_fp(stderr); RSA_free(rsa); return 1; } printf("加密完成,密文长度:%d字节\n", cipher_len); // 清理资源 RSA_free(rsa); EVP_cleanup(); ERR_free_strings(); return 0; }
3. 编译时指定静态链接参数
编译时不要直接用系统默认的库搜索路径,要指向你自己编译的静态库路径,避免链到系统的动态库,示例编译命令:
gcc rsa_demo.c -o rsa_demo -I/opt/openssl-static/include -L/opt/openssl-static/lib -lcrypto -ldl -lpthread
参数说明:
-I:指定静态版OpenSSL的头文件路径,避免和系统头文件版本不匹配-L:指定静态库的搜索路径,优先在这个路径找库文件-lcrypto:链接加密库,因为这个路径下没有动态版libcrypto,会自动链接静态的libcrypto.a-ldl -lpthread:OpenSSL运行依赖的系统基础库,必须加上,不然会报符号找不到的链接错误
如果怕误链动态库,可以直接把静态库的全路径写到编译命令里,完全跳过库搜索逻辑:
gcc rsa_demo.c -o rsa_demo -I/opt/openssl-static/include /opt/openssl-static/lib/libcrypto.a -ldl -lpthread
4. 验证静态链接结果
编译完成后执行命令检查可执行文件的动态依赖:
ldd rsa_demo
如果输出里没有libcrypto.so相关的条目,就说明静态链接成功。这个编译出来的可执行文件可以直接拷贝到没有预装OpenSSL的目标系统上运行,不需要额外安装任何OpenSSL相关安装包。
注意避坑
- 编译OpenSSL静态库用的工具链,必须和编译你自己C程序的工具链完全一致,跨架构交叉编译时,静态库也要用对应架构的交叉工具链编译,不然会报架构不匹配的链接错误
- 如果编译OpenSSL 3.x版本时加了
no-deprecated参数,旧版RSA原生接口会被禁用,需要换成EVP通用接口实现RSA加解密,调用逻辑差异不大 - 如果对可执行文件体积敏感,编译OpenSSL时可以加对应
no-xxx参数关闭不需要的加密算法、功能模块,能大幅压缩静态库体积
内容的提问来源于stack exchange,提问作者zbx0310
相关产品推荐
相关产品推荐

