#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;
}