700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > rsa大数加密c语言 C语言:基于OpenSSL-RSA实现RSA非对称加解密

rsa大数加密c语言 C语言:基于OpenSSL-RSA实现RSA非对称加解密

时间:2021-10-16 13:22:12

相关推荐

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;

}

****************************************************************************************

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。