rsa大数加密c语言,C语言:基于OpenSSL-RSA实现RSA非对称加解密
关于OpenSSL的介绍和安装在此不多赘述,可以在网上找到很多相关资料,各位感兴趣可以去了解下(自觉对OpenSSL开源库只是初级使用阶段,也就不在此“秀下限”了),直接进入主题,本篇源码基于OpenSSL中RSA实现,除此之外还可以基于EVP实现。
示例代码:【RSA-1024bit-PKCS1Padding|x509公钥加密|pkcs12私钥解密】
****************************************************************************************
"crtdef.h":
#ifndef __CRTDEF_H
#define __CRTDEF_H
/* x509公钥文件 */
#define PUBKEY "/home/nemo/etc/rsa/public.cer"
/* pkcs12私钥文件及密码 */
#define PRIKEY "/home/nemo/etc/rsa/private_111111.pfx"
#define PRIPWD "111111"
/* 校验错误函数宏 */
#define CHECK( func ) { \
if( EXIT_FAILURE == (func) ){ \
exit( EXIT_FAILURE ); \
} \
}
#endif
****************************************************************************************
"rsa.c":
/* 算法:RSA-1024bit-PKCS1Padding
* 公钥加密:x509结构(.cer)
* 私钥解密:pkcs12结构(.pfx)+密码 */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "crtdef.h"
/* 公钥证书加密
* RSA(1024位)/PKCS1Padding算法
* 明文最大长度:128-11=117字节
* 密文长度:128字节
* 返回:成功则返回密文长度,失败则返回"EXIT_FAILURE" */
static int encryptRsa( char *plainData, char *cipherData, int plainDataSize )
{
int nResult = 0;
EVP_PKEY *pkey = NULL;
X509 *cert = NULL;
BIO *bn = NULL;
RSA *pubkey = NULL;
/* 01:加载所有的运算法则 */
OpenSSL_add_all_algorithms();
/* 02:解析cer公钥证书 */
/* 2.1.打开证书文件 */
bn = BIO_new_file( PUBKEY, "r" );
if( NULL == bn ){
nResult = EXIT_FAILURE;
fprintf( stderr, "BIO_new_file() Failed!\n" );
goto _err;
}
/* 2.2.读取X509结构 */
cert = PEM_read_bio_X509( bn, NULL, NULL, NULL );
if( NULL == cert ){
nResult = EXIT_FAILURE;
fprintf( stderr, "PEM_read_bio_X509() Failed!\n" );
goto _err;
}
/* 2.3.分解X509结构得到EVP_PKEY */
#if 0
cert = d2i_X509_bio( bn, NULL ); /* DER格式 */
#endif
cert = PEM_read_bio_X509( bn, NULL, NULL, NULL ); /* PEM格式 */
if( NULL == pkey ){
nResult = EXIT_FAILURE;
fprintf( stderr, "X509_get_pubkey() Failed!\n" );
ERR_print_errors_fp( stderr );
goto _err;
}
/* 03:EVP_PKEY转换成RSA的KEY */
pubkey = EVP_PKEY_get1_RSA( pkey );
if( NULL == pubkey ){
nResult = EXIT_FAILURE;
fprintf( stderr, "EVP_PKEY_get1_RSA() Failed!\n" );
ERR_print_errors_fp( stderr );
goto _err;
}
/* 04:公钥加密:RSA_PKCS1_PADDING */
nResult = RSA_public_encrypt( plainDataSize, (unsigned char *)plainData,
(unsigned char *)cipherData, pubkey, RSA_PKCS1_PADDING );
if( nResult < 0 ){
nResult = EXIT_FAILURE;
fprintf( stderr, "RSA_public_encrypt() Failed!\n" );
ERR_print_errors_fp( stderr );
goto _err;
}
_err:
/* 释放BIO */
if( bn != NULL ){
BIO_free( bn );
bn = NULL;
}
/* 释放X509 */
if( cert != NULL ){
X509_free( cert );
cert = NULL;
}
/* 释放EVP_PKEY */
if( pkey != NULL ){
EVP_PKEY_free( pkey );
pkey = NULL;
}
/* 释放RSA */
if( pubkey != NULL ){
RSA_free( pubkey );
pubkey = NULL;
}
/* 清空加载的内容 */
EVP_cleanup(); /* for EVP */
return nResult;
}
/* 私钥证书解密
* RSA(1024位)/PKCS1Padding算法
* 明文最大长度:128-11=117字节
* 密文长度(固定):128字节
* 返回:成功则返回明文长度,失败则返回"EXIT_FAILURE" */
static int decryptRsa( char *cipherData, char *plainData, int cipherDataSize )
{
int nResult = 0;
EVP_PKEY *pkey = NULL;
X509 *cert = NULL;
PKCS12 *p12 = NULL;
RSA *prikey = NULL;
FILE *fp = NULL;
/* 01:加载所有的运算法则 */
OpenSSL_add_all_algorithms();
/* 02:解析pfx私钥证书 */
/* 2.1.打开pfx文件 */
if( NULL == ( fp = fopen( PRIKEY, "rb" ) ) ){
nResult = EXIT_FAILURE;
fprintf( stderr, "fopen() Failed!\n" );
goto _err;
}
/* 2.2.读取PKCS12结构 */
p12 = d2i_PKCS12_fp( fp, NULL );
if( NULL == p12 ){
nResult = EXIT_FAILURE;
fprintf( stderr, "d2i_PKCS12_fp() Failed!\n" );
goto _err;
}
/* 2.3.分解PKCS12结构得到EVP_PKEY */
if( !PKCS12_parse( p12, PRIPWD, &pkey, &cert, NULL ) ){
nResult = EXIT_FAILURE;
fprintf( stderr, "PKCS12_parse() Failed!\n" );
ERR_print_errors_fp( stderr );
goto _err;
}
/* 03:EVP_PKEY转换成RSA的KEY */
prikey = EVP_PKEY_get1_RSA( pkey );
if( NULL == prikey ){
nResult = EXIT_FAILURE;
fprintf( stderr, "EVP_PKEY_get1_RSA() Failed!\n" );
ERR_print_errors_fp( stderr );
goto _err;
}
/* 04:私钥解密:RSA_PKCS1_PADDING */
nResult = RSA_private_decrypt( cipherDataSize, (unsigned char *)cipherData,
(unsigned char *)plainData, prikey, RSA_PKCS1_PADDING );
if( nResult < 0 ){
nResult = EXIT_FAILURE;
fprintf( stderr, "RSA_private_decrypt() Failed!\n" );
ERR_print_errors_fp( stderr );
goto _err;
}
_err:
/* 关闭证书文件 */
if( fp != NULL ){
fclose( fp );
fp = NULL;
}
/* 释放PKCS12 */
if( p12 != NULL ){
PKCS12_free( p12 );
p12 = NULL;
}
/* 释放X509 */
if( cert != NULL ){
X509_free( cert );
cert = NULL;
}
/* 释放EVP_PKEY */
if( pkey != NULL ){
EVP_PKEY_free( pkey );
pkey = NULL;
}
/* 释放RSA */
if( prikey != NULL ){
RSA_free( prikey );
prikey = NULL;
}
/* 清空加载的内容 */
EVP_cleanup(); /* for EVP */
return nResult;
}
/* 测试程序
* 01:公钥加密
* 02:针对加密好的密文使用私钥解密
* 目标:解密出的明文和最初的明文一致证明功能实现
* 命令行参数:最初的明文 */
int main( int argc, char *argv[] )
{
int i = 0;
int plainDataSize = 0;
int cipherDataSize = 0;
char plainData[128 + 1] = {0};
char cipherData[128 + 1] = {0};
/* 依赖命令行参数输入 */
if( 1 == argc ){
fprintf( stderr, "Usage:[%s ]\n", argv[0] );
exit( EXIT_FAILURE );
}
printf( "【初始明文】[%s]\n", argv[1] );
/* 01:公钥加密 */
CHECK( cipherDataSize = encryptRsa( argv[1], cipherData, strlen( argv[1] ) ) );
/* LOOP:鉴于密文极有可能存在不可打印字符故而转十六进制输出 */
printf( "【加密密文】[" );
for( i = 0; i < cipherDataSize; i ++ )
{
printf( "%02X", cipherData[i] );
}
printf( "]\n" );
/* 02:私钥解密 */
CHECK( plainDataSize = decryptRsa( cipherData, plainData, cipherDataSize ) );
printf( "【解密明文】[%s]\n", plainData );
exit( EXIT_SUCCESS );
}
****************************************************************************************
"Makefile":
#执行文件
bin=irsa
#目标文件
objects=rsa.o
#连接规则
$(bin):$(objects)
gcc -o ~/bin/$(bin) $(objects) -lssl -lcrypto -ldl
#清理对象
.PHONY:clean
clean:
-rm ~/bin/$(bin) $(objects)
****************************************************************************************
验证效果:
【P.S.】说明:
鉴于RSA非对称加解密算法明文长度有限,故而通常应用场景:通过对称加密算法(例如DES)加密明文,而通过RSA加密对称加密算法密钥,两者组合即数字信封;(以上示例代码是存粹的RSA裸加密解密)
"Makefile"中"gcc"和"-rm"行首是'Tab'键入的水平制表符'\t',非此会导致"make"失败;(因为编辑器的缘故无法准确表示)
关于公钥,若无公钥文件而是公钥明文串,则可以直接从中截取出模数和指数构建RSA结构,示例代码如下:
****************************************************************************************
模数
跳过公钥明文开头的7字节(十六进制即14字节),截取256字节十六进制(以1024bit为例)
指数
公钥明文末尾3字节(十六进制即6字节)
****************************************************************************************
char *moduleHex = "xxxxxxxxx"; /* 模数16进制[256Bytes] */
char *expandHex = "xxxxxxxxx"; /* 指数16进制 */
BIGNUM *bnn = NULL; /* 模数-大数 */
BIGNUM *bne = NULL; /* 指数-大数 */
RSA *pubkey = NULL;
/* 生成大数 */
bnn = BN_new();
bne = BN_new();
BN_hex2bn( &bnn, moduleHex );
BN_hex2bn( &bne, expandHex );
if( NULL == bnn || NULL == bne ){
fprintf( stderr, "BN_new() Failed!" );
ERR_print_errors_fp( stderr );
exit( EXIT_FAILURE );
}
/* 生成公钥 */
pubkey = RSA_new();
if( NULL == pubkey ){
fprintf( stderr, "RSA_new() Failed!" );
ERR_print_errors_fp( stderr );
exit( EXIT_FAILURE );
}
pubkey->n = bnn;
pubkey->e = bne;
/* 释放大数 */
if( bnn != NULL ){
BN_free( bnn );
bnn = NULL;
}
if( bne != NULL ){
BN_free( bne );
bne = NULL;
}
/* 释放公钥 */
if( pubkey != NULL ){
RSA_free( pubkey );
pubkey = NULL;
}
****************************************************************************************
rsa大数加密c语言,C语言:基于OpenSSL-RSA实现RSA非对称加解密相关推荐
- MacOS下使用C语言基于openssl库进行RSA加密解密
MacOS下使用C语言基于openssl库进行RSA加密解密 1 安装openssl并生成密钥 首先当然要安装openssl(这里记得看一下安装路径,应该是/usr/local/Cellar/open ...
- 基于CH375的嵌入式USB文件加解密系统的设计
基于CH375的嵌入式USB文件加解密系统的设计 [日期:2008-7-21] 来源:电子技术应用 作者:华中科技大学 电子与信息工程系, 湖北 武汉 430074 [字体:大 中 小] <s ...
- 基于Java的SQL Server数据库加解密系统设计与实现
目 录 摘 要 1 ABSTRACT 2 第1章 绪论 3 1.1 数据库加解密系统开发背景 3 1.2 国内外现状 3 1.3 本文的主要工作 4 1.4 论文的组织结构 4 第2章 数据库加密的基 ...
- 基于安卓系统的SM4-SM2/3加解密软件开发报告
目 录 第一章需求分析 1.1软件功能需求 1.2平台需求 1.3人员分工 第二章概要设计 2.1 软件开发平台 2.2 软件基本流程 2.3 UML图 第三章 程序详细设计 3.1 程序接口设计 3 ...
- 【crypto】基于crypto.js的web前端加解密系统实现
文章目录 一.概念介绍 1.1 crypto.js介绍 1.2 加密 / 哈希 / 编码 1.2.1 加密/解密 1.2.2 散列/哈希 1.2.3 BASE64编解码 二.加解密思想(以md5为例) ...
- python RSA非对称加解密模块[M2Crypto]
python 实现rsa对称加解密目前有三个库:rsa.pycryptodome.M2Crypto 前两个库只能实现公钥加密私钥解密,M2Crypto可以实现公私钥互相加解密 M2Crypto的安装: ...
- TLS 改变密码标准协议(Change Cipher Spec Protocol) 就是加密传输中每隔一段时间必须改变其加解密参数的协议...
SSL修改密文协议的设计目的是为了保障SSL传输过程的安全性,因为SSL协议要求客户端或服务器端每隔一段时间必须改变其加解密参数.当某一方要改变其加解密参数时,就发送一个简单的消息通知对方下一个要传送 ...
- 非对称加解密,私钥和公钥到底是谁来加密,谁来解密?
第一种用法:公钥加密,私钥解密.-- 用于加解密 第二种用法:私钥签名,公钥验签.-- 用于签名 有点混乱,不要去硬记,总结一下: 你只要想: 既然是加密,那肯定是不希望别人知道我的消息,所以只有我才 ...
- 基于AES算法的英文文字加解密
目录 一.理论基础 二.核心程序 三.仿真结论 一.理论基础 AES算法是一种对称加密算法,被广泛应用于数据加密和保护领域中.将介绍如何使用AES算法对英文文字进行加解密. 一.AES算法概述 AES ...
最新文章
- java.util.concurrent简介
- 空中楼阁成语故事,空中楼阁用来比喻什么?
- java中aop和aoc的区别_AOC与AOP的区别
- net.sf.json.JSONException: #39;object#39; is an array. Use JSONArray instead
- 机器学习笔记(二十二):逻辑回归中使用模型正则化
- 利用OneNET实现SIM868使用HTTP协议给服务器发送数据并显示
- java pdf 添加图片
- HearthBuddy卡组
- MyEclispe发布web项目-遁地龙卷风
- 银联在线支付对接流程以及签名算法
- Idea取消光标所在行颜色
- 浏览器缓存机制(强缓存和协商缓存)
- 「Python语法结构」数据类型与运算符示例(7)
- IDEA相关配置(特别完整)看完此篇就将所有的IDEA的相关配置都配置好了、设置鼠标滚轮修改字体大小、设置鼠标悬浮提示、设置主题、设置窗体及菜单的字体及字体大小、设置编辑区主题、通过插件更换主题
- HDU 3723 Delta Wave(卡特兰数+大数)
- 产品设计中的脉冲群(EFT)防护
- 学计算机 有什么好的二本大学排名,二本大学排名
- 崔庆才双十二要直播了!!!快来围观啊!!!
- latex梯度_一文学会基本的LaTeX公式输入
- jeesite 附件上传
热门文章
- android camera 降噪,照片噪点怎么去除?超详细!一步步教你进行相机降噪处理!...
- .NET Core微服务之路:文章系列和内容索引汇总 (v0.53)
- Android ---- Ijkplayer阅读native层源码之IjkMediaPlayer_prepareAsync(五)
- 个人号运营:我和微商学习,如何运营个人号?
- 服务器accept队列溢出及其解决
- 弘辽科技:不要小看微淘!微淘是商家专属的私域流量的大本营
- 个人网站备案起名_网站更换服务器空间后,需要重新备案吗?
- Go语言-Go interface 接口的最佳实践
- KANO模型分析法简介与应用
- 6.python解答蓝桥杯17年A组真题 迷宫