背景:使用C#创建webapi服务器,有加密需求,想到了rsa非对称加密,又要保证js前端和c++后端都可以使用C#生成的公钥,经过查询与问询chartgpt,修改与测试,终于可用了,chartgpt的错误率太高了。
以下只写主要代码
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Encodings;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
//C#使用BouncyCastle库
class RSAHelper
{
private static readonly RsaKeyPairGenerator _rsa = new();
private static readonly AsymmetricCipherKeyPair _keyPair;
private static readonly string _publicKeyPem;
static RSAHelper()
{
_rsa.Init(new KeyGenerationParameters(new SecureRandom(), 2048));
_keyPair = _rsa.GenerateKeyPair();
/*
* 生成pem格式的公钥,如下形式:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjJpDOEk2JHCrbuMdQVm7
wREoI8SLwfCA6v/v0s1atPr+Rt8lELpLsBqkaFziwPfNQ+Fg6YyHZZSLFfMJiAeo
3ZGObExWEK22N1U7clzIPyYDmppqqg5fnelPIRe3oqobqKeVhrBjrSUjaUL04Qy8
Gp3bCQBesp2zoWor2lfy+28PpyUo6+kX1fFEUJhRLvBY4WSf8irB5cxnfZxusnzX
t2ZEBmxkSAUwa0AgrvDz7siIHMBB7wvJvnznafDC3hyw8pFTiPtBM2obwTkiiXLz
mYr4nTF/qv3lPSLwlw+ASu+JOr2JdzUKd/akoE7koprbTdysiCM6m3wrnTahrc7u
VwIDAQAB
-----END PUBLIC KEY-----
*/
using var stringWriter = new StringWriter();
var pemWriter = new PemWriter(stringWriter);
pemWriter.WriteObject(_keyPair.Public);
pemWriter.Writer.Flush();
_publicKeyPem = stringWriter.ToString();
}
// RSA加密,使用的是Pkcs1加密
public static string RSAEncrypt(string data)
{
var rsaEngine = new Pkcs1Encoding(new RsaEngine());
rsaEngine.Init(true, _keyPair.Public);
var bytesToEncrypt = Encoding.UTF8.GetBytes(data);
var encryptedBytes = rsaEngine.ProcessBlock(bytesToEncrypt, 0, bytesToEncrypt.Length);
return Convert.ToBase64String(encryptedBytes);
}
// RSA解密,使用的是Pkcs1解密
public static string RSADecrypt(string encryptedData)
{
var rsaEngine = new Pkcs1Encoding(new RsaEngine());
rsaEngine.Init(false, _keyPair.Private);
var encryptedBytes = Convert.FromBase64String(encryptedData);
var decryptedBytes = rsaEngine.ProcessBlock(encryptedBytes, 0, encryptedBytes.Length);
return Encoding.UTF8.GetString(decryptedBytes);
}
}
<!DOCTYPE html>
<html>
<head>
<title>JS使用jsencrypt</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jsencrypt/3.3.2/jsencrypt.min.js"></script>
</head>
<body>
<script>
// publicKeyPem 就是C#生成的pem格式公钥
function RSAEncrypt(publicKeyPem) {
var encrypt = new JSEncrypt();
encrypt.setPublicKey(publicKeyPem);
var encryptedData = encrypt.encrypt("要加密的数据");
return encryptedData ;
}
</script>
</body>
</html>
//C++使用CryptoPP
#include "rsa.h"
#include "base64.h"
#include "osrng.h"
#include "files.h"
#include <sstream>
#pragma comment(lib,"cryptlib")
// 加载pem格式的公钥,要去头去尾
std::string removePublicKeyLines(const std::string& input) {
std::string result;
std::istringstream iss(input);
std::string line;
while (std::getline(iss, line)) {
if (line.find("BEGIN PUBLIC KEY") == std::string::npos &&
line.find("END PUBLIC KEY") == std::string::npos) {
result += line + '\n';
}
}
return result;
}
CryptoPP::RSA::PublicKey LoadPublicKeyFromPEM(const std::string& pemString)
{
std::string pem = removePublicKeyLines(pemString);
// 解码Base64编码的PEM字符串
std::string base64;
CryptoPP::StringSource(pem, true, new CryptoPP::Base64Decoder(new CryptoPP::StringSink(base64)));
CryptoPP::RSA::PublicKey publicKey;
publicKey.Load(CryptoPP::StringStore(base64).Ref());
return publicKey;
}
// 使用PKCS1加密
std::string EncryptStringWithPublicKey(const std::string& plaintext, const CryptoPP::RSA::PublicKey& publicKey)
{
CryptoPP::AutoSeededRandomPool rng;
std::string ciphertext;
CryptoPP::RSAES_PKCS1v15_Encryptor encryptor(publicKey);
CryptoPP::StringSource(plaintext, true, new CryptoPP::PK_EncryptorFilter(rng, encryptor, new CryptoPP::StringSink(ciphertext)));
return ciphertext;
}
// base64编码
std::string Base64Encode(const std::string& input)
{
std::string encoded;
CryptoPP::StringSource(input, true,
new CryptoPP::Base64Encoder(
new CryptoPP::StringSink(encoded),
false // 不在输出中添加换行符
)
);
return encoded;
}