#include <openssl/rsa.h>
#include <openssl/pem.h>
/////////////////////////////////////////////////////////////// 加密解密
// 公钥加密
int RSA_public_encrypt(int flan,const unsigned char* from,unsigned char* to,RSA* rsa,int padding)
// 私钥加密
int RSA_private_decrypt(int flan,const unsigned char* from,unsigned char* to,RSA* rsa,int padding)
///////////////////////// 签名使用 //////////////////////
// 私钥加密
int RSA_private_encrypt(int flan,const unsigned char* from,unsigned char* to,RSA* rsa,int padding)
// 公钥解密
int RSA_public_decrypt(int flan,const unsigned char* from,unsigned char* to,RSA* rsa,int padding)
参数:
- flen: 要加密/解密的数据长度
长度 0 < flen <= 密钥长度-11
- from: 传入,要加密/解密的数据
- to: 传出,存储数据,加密->存储密文, 解密->存储明文
- rsa: 密钥:公钥/私钥
- padding: 指定填充方案,数据填充,不需要使用做
- RSA_PKCS1_PADDING -> 使用该方案会填充11字节
/////////////////////////////////////////////////////////////// 生成密钥对
// 创建bio对象
// 密钥对写磁盘文件的时候, 需要编码 -> base64
// 封装了fopen
BIO *BIO_new_file(const char *filename, const char *mode);
参数:
- filename: 文件名
- mode: 文件打开方式和fopen打开方式的指定相同
int PEM_write_bio_RSAPublicKey(BIO* bp, const RSA* r);
int PEM_write_bio_RSAPrivateKey(BIO* bp, const RSA* r, const EVP_CIPHER* enc,
unsigned char* kstr, int klen, pem_password_cb *cb, void* u);
RSA* PEM_read_bio_RSAPublicKey(BIO* bp, RSA** r, pem_password_cb *cb, void* u);
RSA* PEM_read_bio_RSAPrivateKey(BIO* bp, RSA** r, pem_password_cb *cb, void* u);
参数:
- bp: 通过BIO_new_file();函数得到该对象
- r: 传递一个RSA* rsa指针的地址, 传出参数-> 公钥/私钥
- cb: 回调函数, 用不到, 指定为NULL
- u: 给回调传参, 用不到, 指定为NULL
// 释放资源
BIO_free(bio);
///////////////////////////////////////////////////////////////
FILE* fd = fopen("xxxx.pem","w");
int PEM_write_RSAPublicKey(FILE* fp,const RSA* r);
int PEM_write_RSAPrivateKey(FILE* fp,const RSA* r,const EVP_CIPHER* enc,
unsigned char* kstr,int klen,pem_password_cb* cb,void* u);
参数:
- fp: 需要打开一个磁盘文件,并且指定写权限
- r: 存储了密钥对
//////// - 私钥独有的参数
- enc: 指定的加密算法 -> 堆成加密 -> NULL
- kstr: 对称加密的密钥 -> NULL
- klen: 密钥长度 -> 0
- cb:回调函数,用不到,NULL
- u: 给回调传参,用不到,NULL
/////////////////////////////////////////////////////////////// 从内存中读取
// 从内存中将参数rsa中的公钥提取出来
RSA* RSAPublicKey_dup(RSA* rsa);
// 从内存中将参数rsa中的私钥提取出来
RSA* RSAPrivateKey_dup(RSA* rsa);
签名
int RSA_sign(int type, const unsigned char *m, unsigned int m_length,
unsigned char *sigret, unsigned int *siglen, RSA *rsa);
参数:
- type: 使用的哈希算法
- NID_MD5
- NID_SHA1
- NID_SHA224
- .....
- m: 要进行签名的数据
- m_length: 要签名的数据长度
- 0 < m_length <= 秘钥长度-11
- sigret: 传出, 存储了签名之后的数据 -> 密文
- siglen: sigret密文长度
- rsa: 私钥
返回值: 判断函数状态
int RSA_verify(int type, const unsigned char *m, unsigned int m_length,
const unsigned char *sigbuf, unsigned int siglen, RSA *rsa);
参数:
- type: 使用的哈希算法, 和签名使用的哈希算法一致
- NID_MD5
- NID_SHA1
- NID_SHA224
- .....
- m: 进行签名的原始数据 -> 接收到的
- m_length: m参数字符串的长度
- sigbuf: 接收到的签名数据
- siglen: sigbuf接收到的签名数据的长度
- rsa: 公钥
返回值:
如果!=1: 失败
如果==1: 成功
代码演示
#include <iostream>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <cstdio>
void generateRsaKey()
{
// 创建RSA变量
RSA* rsa = RSA_new();
// 创建bignum对象并初始化
BIGNUM* e = BN_new();
BN_set_word(e,12345);
// 生成密钥对 -> 保存在内存中
RSA_generate_key_ex( rsa,1024,e,NULL );
//---------生成密钥对 1024代表密钥长度
// RSA_F4为公钥指数,一般情况下使用RSA_F4即可,
// RSA_generate_key( 1024,RSA_F4,NULL,NULL );
// 将密钥对写入到磁盘
#if 0
FILE* fp = fopen("public.pem","w"); // 写公钥
PEM_write_RSAPublicKey(fp,rsa);
fclose(fp);
fp = fopen("private.pem","w"); // 写私钥
PEM_write_RSAPrivateKey(fp,rsa,NULL,NULL,0,NULL,NULL);
fclose(fp);
#else
BIO* bio = BIO_new_file("public-1.pem","w");
PEM_write_bio_RSAPublicKey(bio,rsa);
// 释放资源
BIO_free(bio);
bio = BIO_new_file("private-1.pem","w");
PEM_write_bio_RSAPrivateKey(bio,rsa,NULL,NULL,0,NULL,NULL);
// 释放资源
BIO_free(bio);
#endif
// 密钥对写入文件的时候,需要编码 -> base64
}
int main()
{
generateRsaKey();
return 0;
}
加解密函数
// 公钥加密
string encryptPublicKey(){
// 准备要加密的数据
string test = "让编程改编世界";
// 准备密钥 - > 公钥
// 磁盘文件
BIO* bio = BIO_new_file("public-1.pem","r");
RSA* pubKey = RSA_new();
if( PEM_read_bio_RSAPublicKey(bio,&pubKey,NULL,NULL) == NULL )
{
cout<<"读密钥失败了..."<<endl;
return 0;
}
BIO_free(bio);
// 加密 -> 密文
// 通过函数计算密钥长度
int keyLen = RSA_size(pubKey);
char* buf = new char[keyLen];
// 返回值就是密文长度
int len = RSA_public_encrypt(test.size(),(unsigned char*)test.data(),(unsigned char*)buf,pubKey,RSA_PKCS1_PADDING);
// 将密文返回
return string(buf,len);
// 分发密钥
}
// 私钥解密
string decryptPrivateKey(string str){
BIO* bio = BIO_new_file("private-1.pem","r");
RSA* priKey = RSA_new();
if( PEM_read_bio_RSAPrivateKey(bio,&priKey,NULL,NULL) == NULL )
{
cout<<"读取私钥失败..."<<endl;
return string();
}
BIO_free(bio);
int keyLen = RSA_size(priKey);
char* buf = new char[keyLen];
// 原始数据的长度
int len = RSA_private_decrypt(str.size(),(const unsigned char*)str.data(),(unsigned char*)buf,priKey,RSA_PKCS1_PADDING);
cout<<buf<<endl;
return string(buf,len);
}
// 签名和验证签名
void rsaSigAndVerfiy()
{
// 签名数据
string str = "我叫小赵";
// 密钥
BIO* pubBio = BIO_new_file("public.pem","r");
RSA* pubKey = RSA_new();
if( PEM_read_bio_RSAPublicKey(pubBio,&pubKey,NULL,NULL) == NULL )
cout<< "读取私钥失败..."<<endl;
BIO_free(pubBio);
BIO* priBio = BIO_new_file("private.pem","r");
RSA* priKey = RSA_new();
if( PEM_read_bio_RSAPrivateKey(priBio,&priKey,NULL,NULL) == NULL )
cout<< "读取公钥失败..."<<endl;
BIO_free(priBio);
// 签名
int len = RSA_size(priKey);
unsigned char* out = new unsigned char[len];
unsigned int outLen = 0;
RSA_sign(NID_sha1,(const unsigned char*)str.data(),str.size(),out,&outLen,priKey);
// 要给到用户的数据
string sigbuf((char*)out,outLen);
// 验证签名
int ret = RSA_verify(NID_sha1,(const unsigned char*)str.data(),(unsigned int)str.size(),(const unsigned char*)sigbuf.data(),sigbuf.size(),pubKey);
cout<< ret <<endl;
}