C++对RSA加密、解密的使用
这几天也是无聊,想改一下验证的加解密来着,后来想想如果并发量起来的话,反而会影响效率,但是代码已经写完了,放出来大家一起学习吧。代码包含C++、PHP完整的例子,没写加签、验签,这个不难。
支持中文、超大字符串加密(分段加密/解密)
期间卡了很久,发现php的base64_encode跟我C++写的base64_encode结果不一致,调试了很久才发现是被加密数据如果有中文的话,就会导致不一致。
所以放出来避免大家壁坑吧。
调用了 OpenSSL库,大家自己下载安装即可
https://static.52pojie.cn/static/image/hrline/1.gif
<?php
class Openssl
{
/**
* 配置信息.
* publicKey => string.
* privateKey => string.
*
* @var mixed
*/
protected $config;
/**
* 初始化.
*
* @Param array $config
*/
public function __construct($config)
{
$this->config = $config;
}
/**
* 获取密钥分段加密长度.
*
* @param Closure $keyClosure
*
* @Return int
*
* @throws Exception
*/
protected function getEncryptBlockLen($keyClosure)
{
$key_info = openssl_pkey_get_details($keyClosure);
if (!$key_info)
{
throw new Exception('获取密钥信息失败' . openssl_error_string());
}
// bits数除以8 减去padding长度,OPENSSL_PKCS1_PADDING 长度是11
// php openssl 默认填充方式是 OPENSSL_PKCS1_PADDING
return $key_info['bits'] / 8 - 11;
}
/**
* 获取密钥分段解密长度.
*
* @param Closure $keyClosure
*
* @return int
*
* @throws Exception
*/
protected function getDecryptBlockLen($keyClosure)
{
$key_info = openssl_pkey_get_details($keyClosure);
if (!$key_info)
{
throw new Exception('获取密钥信息失败' . openssl_error_string());
}
// bits数除以8得到字符长度
return $key_info['bits'] / 8;
}
/**
* 数据加密.
*
* @param string $text 需要加密的文本
* @param int $type 加密方式:1.公钥加密 2.私钥加密
*
* @return string
*
* @throws Exception
*/
public function encrypt($text, $type)
{
//获取密钥资源
$keyClosure = 1 == $type ? openssl_pkey_get_public($this->config['publicKey']) : openssl_pkey_get_private($this->config['privateKey']);
if (!$keyClosure)
{
throw new Exception('获取密钥失败,请检查密钥是否合法');
}
//RSA进行加密
$encrypt = '';
$plainData = str_split($text, $this->getEncryptBlockLen($keyClosure));
foreach ($plainData as $key => $encrypt_item)
{
$isEncrypted = (1 == $type) ? openssl_public_encrypt($encrypt_item, $encrypted, $keyClosure) : openssl_private_encrypt($encrypt_item, $encrypted, $keyClosure);
if (!$isEncrypted)
{
throw new Exception('加密数据失败,请检查密钥是否合法,' . openssl_error_string());
}
$encrypt .= $encrypted;
}
$encrypt = base64_encode($encrypt);
//返回
return $encrypt;
}
/**
* 数据解密.
*
* @param string $text 需要加密的文本
* @param int $type 加密方式:1.公钥加密 2.私钥加密
*
* @return string
*
* @throws Exception
* @throws
*/
public function decrypt($text, $type)
{
//获取密钥资源
$keyClosure = 1 == $type ? openssl_pkey_get_public($this->config['publicKey']) : openssl_pkey_get_private($this->config['privateKey']);
if (!$keyClosure)
{
throw new Exception('获取密钥失败,请检查密钥是否合法');
}
//RSA进行解密
$data = base64_decode($text);
$data = str_split($data, $this->getDecryptBlockLen($keyClosure));
$decrypt = '';
foreach ($data as $key => $chunk)
{
$isDecrypted = (1 == $type) ? openssl_public_decrypt($chunk, $encrypted, $keyClosure) : openssl_private_decrypt($chunk, $encrypted, $keyClosure);
if (!$isDecrypted)
{
throw new Exception('解密数据失败,请检查密钥是否合法,' . openssl_error_string());
}
$decrypt .= $encrypted;
}
//返回
return $decrypt;
}
}
//01.配置公钥私钥 publicKey:公钥 privateKey:私钥
$config = [
'publicKey' => '-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqUsK1vxiaPtlpKWrYOez
...省略..
mX1MJYsP9eP6FeGylvYIz/GtrUA7e4eHD1xriyEDwwpZ8EyNzYKTDAhktkyw55zS
nQIDAQAB
-----END PUBLIC KEY-----',
'privateKey' => '-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCpSwrW/GJo+2Wk
...省略..
Oc8mrEYKQyozBvV7SPgYew==
-----END PRIVATE KEY-----',
];
//02.初始化
$openssl = new Openssl($config);
//03.私钥加密->公钥解密
$a = "pwsLvMjnd2i*vS$!-6Pqiw9zp%wRc5d-N*oGcJ@=I!hj8A1测&OXvjEWUr7Yi3mC3h&*WDQlW_yj6u#F!os4%rQ试3AgX99gXqn4HJ";
echo '原始数据 : '. $a .'<br/>';
$privateEnData = $openssl->encrypt(base64_encode($a) , 2);//私钥加密
$publicDeData = $openssl->decrypt($privateEnData, 1); //公钥解密
echo '私钥加密数据 : '. $privateEnData .'<br/>';
echo '公钥解密数据 : '. base64_decode($publicDeData) .'<br/><br/><br/>';
//04.公钥加密->私钥解密
$b = "+i#JTRLN8#lOgyfGTEvrn5H@测lTk#tgu!2Zs%*+kFg2&ob_s5VkmWf试peK7Sbm!8SfPf70xyt6q7cou8Pef4RO4Sf5ad8B9D&Mfld";
echo '原始数据 : '. $b .'<br/>';
$publicEnData = $openssl->encrypt(base64_encode($b), 1); //公钥加密
$privateDeData = $openssl->decrypt($publicEnData, 2); //私钥解密
echo '公钥加密数据'. $publicEnData .'<br/>';
echo '私钥解密数据'. base64_decode($privateDeData) .'<br/>';
def.h
#include <windows.h>
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <cstring>
#include <stdio.h>
#include <string>
#include <vector>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/evp.h>
#include "rsas.h"
using namespace std;
#pragma comment(lib,"libcrypto.lib")
#pragma comment(lib,"WS2_32.lib")
#pragma comment(lib,"Crypt32.lib")
rsas.h
#include <assert.h>
std::string Base64Encode(const unsigned char* data, size_t size)
{
size_t base64_len = (size + 2) / 3 * 4;
if (base64_len == 0)
{
return "";
}
std::string ret;
ret.resize(base64_len);
EVP_EncodeBlock((unsigned char*)ret.data(), data, size);
return std::move(ret);
}
std::string Base64Decode(const std::string& src)
{
size_t srcLen = src.size();
if (srcLen % 4 != 0)
{
return "";
}
std::string ret1;
size_t destLen = (srcLen / 4) * 3;
ret1.resize(destLen);
//todo: 判断返回值
int ret = EVP_DecodeBlock((unsigned char*)ret1.data(), (const unsigned char*)src.c_str(), srcLen);
if (ret == -1)
{
//base64 decode failed
return "";
}
int i = 0;
while (src.at(--srcLen) == '=')
{
ret--;
if (++i > 2)
{
// input maybe not base64 str;
return "";
}
}
return std::move(ret1);
}
char* G2U(const char* gb2312)
{
int len = MultiByteToWideChar(CP_ACP, 0, gb2312, -1, NULL, 0);
wchar_t* wstr = new wchar_t;
memset(wstr, 0, len + 1);
MultiByteToWideChar(CP_ACP, 0, gb2312, -1, wstr, len);
len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
char* str = new char;
memset(str, 0, len + 1);
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, len, NULL, NULL);
if (wstr) delete[] wstr;
return str;
}
//UTF-8到GB2312的转换
char* U2G(const char* utf8)
{
int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0);
wchar_t* wstr = new wchar_t;
memset(wstr, 0, len + 1);
MultiByteToWideChar(CP_UTF8, 0, utf8, -1, wstr, len);
len = WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL);
char* str = new char;
memset(str, 0, len + 1);
WideCharToMultiByte(CP_ACP, 0, wstr, -1, str, len, NULL, NULL);
if (wstr) delete[] wstr;
return str;
}
/** 公钥加密*/
std::string encrypt_RSA_by_long_str_public_key(std::string publicKey, const std::string& data)
{
auto b = G2U(data.data());
auto c = Base64Encode((const unsigned char*)b, strlen(b));
std::string strRet;
//创建RSA指针
BIO* keybio = BIO_new_mem_buf((unsigned char*)publicKey.c_str(), -1);
RSA* rsa = RSA_new();
//rsa = PEM_read_bio_RSAPublicKey(keybio, &rsa, NULL, NULL);//这个失败,二脸萌壁..
rsa = PEM_read_bio_RSA_PUBKEY(keybio, &rsa, NULL, NULL);
if (!rsa)
{
BIO_free_all(keybio);
return std::string("");
}
int len = RSA_size(rsa);
char* decryptedText = (char*)malloc(len + 1);
memset(decryptedText, 0, len + 1);
int nClearDataLen = c.length();
int pdBlock = len - 11;
int nCount = (nClearDataLen / pdBlock) + 1;
//分段次数
unsigned char* pClearData = (unsigned char*)c.c_str();
//分段加密
for (int i = 0; i < nCount; i++)
{
int nSize = 0;
pdBlock = (nClearDataLen > pdBlock) ? pdBlock : nClearDataLen;
nSize = RSA_public_encrypt(pdBlock, (const unsigned char*)pClearData, (unsigned char*)decryptedText, rsa, RSA_PKCS1_PADDING);
pClearData += pdBlock;
nClearDataLen -= pdBlock;
if (nSize >= 0)
{
strRet += std::string(decryptedText, nSize);
}
}
// 释放内存
delete decryptedText;
BIO_free_all(keybio);
RSA_free(rsa);
return Base64Encode((const unsigned char*)strRet.c_str(), strRet.length());
}
/** 公钥解密*/
std::string decrypt_RSA_by_long_str_public_key(std::string publicKey, const std::string& data)
{
auto a = Base64Decode(data);
std::string strRet;
//创建RSA指针
BIO* keybio = BIO_new_mem_buf((unsigned char*)publicKey.c_str(), -1);
RSA* rsa = RSA_new();
//rsa = PEM_read_bio_RSAPublicKey(keybio, &rsa, NULL, NULL);//这个失败,二脸萌壁..
rsa = PEM_read_bio_RSA_PUBKEY(keybio, &rsa, NULL, NULL);
if (!rsa)
{
BIO_free_all(keybio);
return std::string("");
}
int len = RSA_size(rsa);
char* decryptedText = (char*)malloc(len + 1);
memset(decryptedText, 0, len + 1);
int nClearDataLen = a.length();
int pdBlock = len;
int nCount = (nClearDataLen / pdBlock) + 1;
//分段次数
unsigned char* pClearData = (unsigned char*)a.c_str();
//分段解密
for (int i = 0; i < nCount; i++)
{
int nSize = 0;
pdBlock = (nClearDataLen > pdBlock) ? pdBlock : nClearDataLen;
nSize = RSA_public_decrypt(pdBlock, (const unsigned char*)pClearData, (unsigned char*)decryptedText, rsa, RSA_PKCS1_PADDING);
pClearData += pdBlock;
nClearDataLen -= pdBlock;
if (nSize >= 0)
{
strRet += std::string(decryptedText, nSize);
}
}
// 释放内存
delete decryptedText;
BIO_free_all(keybio);
RSA_free(rsa);
std::stringbb = Base64Decode(strRet);
return U2G(bb.c_str());
}
/** 私钥加密*/
std::string encrypt_RSA_by_long_str_private_key(std::string privateKey, const std::string& data)
{
auto b = G2U(data.data());
auto c = Base64Encode((const unsigned char*)b, strlen(b));
std::string strRet;
//创建RSA指针
RSA* rsa = RSA_new();
BIO* keybio;
keybio = BIO_new_mem_buf((unsigned char*)privateKey.c_str(), -1);
rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa, NULL, NULL);
int len = RSA_size(rsa);
char* decryptedText = (char*)malloc(len + 1);
memset(decryptedText, 0, len + 1);
int nClearDataLen = c.length();
int pdBlock = len - 11;
int nCount = (nClearDataLen / pdBlock) + 1;
//分段次数
unsigned char* pClearData = (unsigned char*)c.c_str();
//分段加密
for (int i = 0; i < nCount; i++)
{
int nSize = 0;
pdBlock = (nClearDataLen > pdBlock) ? pdBlock : nClearDataLen;
nSize = RSA_private_encrypt(pdBlock, (const unsigned char*)pClearData, (unsigned char*)decryptedText, rsa, RSA_PKCS1_PADDING);
pClearData += pdBlock;
nClearDataLen -= pdBlock;
if (nSize >= 0)
{
strRet += std::string(decryptedText, nSize);
}
}
// 释放内存
delete decryptedText;
RSA_free(rsa);
return Base64Encode((const unsigned char*)strRet.c_str(), strRet.length());
}
/** 私钥解密*/
std::string decrypt_RSA_by_long_str_private_key(std::string privateKey, const std::string& data)
{
auto a = Base64Decode(data);
std::string strRet;
//创建RSA指针
RSA* rsa = RSA_new();
BIO* keybio;
keybio = BIO_new_mem_buf((unsigned char*)privateKey.c_str(), -1);
rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa, NULL, NULL);
int len = RSA_size(rsa);
char* decryptedText = (char*)malloc(len + 1);
memset(decryptedText, 0, len + 1);
int nClearDataLen = a.length();
int pdBlock = len;
int nCount = (nClearDataLen / pdBlock) + 1;
//分段次数
unsigned char* pClearData = (unsigned char*)a.c_str();
//分段解密
for (int i = 0; i < nCount; i++)
{
int nSize = 0;
pdBlock = (nClearDataLen > pdBlock) ? pdBlock : nClearDataLen;
nSize = RSA_private_decrypt(pdBlock, (const unsigned char*)pClearData, (unsigned char*)decryptedText, rsa, RSA_PKCS1_PADDING);
pClearData += pdBlock;
nClearDataLen -= pdBlock;
if (nSize >= 0)
{
strRet += std::string(decryptedText, nSize);
}
}
// 释放内存
delete decryptedText;
RSA_free(rsa);
std::stringbb = Base64Decode(strRet);
return U2G(bb.c_str());
}
main.cpp
#include "def.h"
int main()
{
//私钥
std::string pri = "-----BEGIN PRIVATE KEY-----\n"\
"MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCpSwrW/GJo+2Wk"\
//省略
"Oc8mrEYKQyozBvV7SPgYew==\n"\
"-----END PRIVATE KEY-----";
//公钥
std::string pub = "-----BEGIN PUBLIC KEY-----\n"\
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqUsK1vxiaPtlpKWrYOez"\
//省略
"mX1MJYsP9eP6FeGylvYIz/GtrUA7e4eHD1xriyEDwwpZ8EyNzYKTDAhktkyw55zS"\
"nQIDAQAB\n"\
"-----END PUBLIC KEY-----";
std::string a = "pwsLvMjnd2i*vS$!-6Pqiw9zp%wRc5d-N*oGcJ@=I!hj8A1测&OXvjEWUr7Yi3mC3h&*WDQlW_yj6u#F!os4%rQ试3AgX99gXqn4HJ";
cout << "原始数据 : " << a.c_str() << endl;
cout << endl;
auto enc_data_pri = encrypt_RSA_by_long_str_private_key(pri, a);
cout << "私钥加密数据 : " << enc_data_pri.c_str() << endl;
cout << endl;
auto dec_data_pub = decrypt_RSA_by_long_str_public_key(pub, enc_data_pri);
cout << "公钥解密数据 : " << dec_data_pub.c_str() << endl;
cout << endl;
cout << endl;
std::string b = "+i#JTRLN8#lOgyfGTEvrn5H@测lTk#tgu!2Zs%*+kFg2&ob_s5VkmWf试peK7Sbm!8SfPf70xyt6q7cou8Pef4RO4Sf5ad8B9D&Mfld";
cout << "原始数据 : " << b.c_str() << endl;
cout << endl;
auto enc_data_pub = encrypt_RSA_by_long_str_public_key(pub, b);
cout << "公钥加密 : " << enc_data_pub.c_str() << endl;
cout << endl;
auto dec_data_pri = decrypt_RSA_by_long_str_private_key(pri, enc_data_pub);
cout << "私钥解密 : " << dec_data_pri.c_str() << endl;
cout << endl;
cout << endl;
system("pause");
return 0;
}
测试结果:
Blog地址:https://3musen.com/2023/08/19/C++/C++%20%E4%BD%BF%E7%94%A8RSA%E5%8A%A0%E5%AF%86%E3%80%81%E8%A7%A3%E5%AF%86%E6%95%99%E7%A8%8B/ 优秀,谢谢分享 谢谢楼主分享 强悍学习了,膜拜 谢谢楼主分享 收藏学习代码
不错不错,谢谢分享
学习学习代码
页:
[1]