Skip to content

Commit cc25e8d

Browse files
committed
feat(加密): 添加支持PKCS#1和PKCS#8格式的RSA加解密方法
添加EncryptBase64和DecryptBase64方法,支持PKCS#1和PKCS#8格式的密钥,自动处理分块加解密,并返回Base64格式结果。方法包含完善的异常处理和文档注释。
1 parent b7170a7 commit cc25e8d

1 file changed

Lines changed: 133 additions & 0 deletions

File tree

GameFrameX.Foundation.Encryption/RsaHelper.cs

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,139 @@ namespace GameFrameX.Foundation.Encryption;
1111
/// </summary>
1212
public sealed class RsaHelper
1313
{
14+
/// <summary>
15+
/// 使用公钥加密数据(支持Base64格式公钥)
16+
/// </summary>
17+
/// <remarks>
18+
/// 本方法支持以下两种公钥格式:
19+
/// 1. SubjectPublicKeyInfo(PKCS#8)格式
20+
/// 2. RSAPublicKey(PKCS#1)格式
21+
/// 当数据长度超过密钥长度限制时,自动采用分块加密。
22+
/// 加密后的结果采用Base64编码返回,便于网络传输和存储。
23+
/// </remarks>
24+
/// <param name="publicKey">Base64 格式的公钥字符串,支持 PKCS#1 与 PKCS#8 两种编码</param>
25+
/// <param name="content">待加密的明文字符串,将使用 UTF-8 编码转换为字节数组</param>
26+
/// <returns>Base64 格式的加密结果,可直接用于网络传输或持久化存储</returns>
27+
/// <exception cref="ArgumentException">当 publicKey 或 content 为 null 或空字符串时抛出</exception>
28+
/// <exception cref="CryptographicException">当公钥格式非法或加密过程失败时抛出</exception>
29+
public static string EncryptBase64(string publicKey, string content)
30+
{
31+
ArgumentException.ThrowIfNullOrEmpty(publicKey, nameof(publicKey));
32+
ArgumentException.ThrowIfNullOrEmpty(content, nameof(content));
33+
34+
using var rsa = RSA.Create();
35+
try
36+
{
37+
// 导入公钥
38+
// 注意:这里假设公钥是 PKCS#8 或 SubjectPublicKeyInfo 格式
39+
rsa.ImportSubjectPublicKeyInfo(Convert.FromBase64String(publicKey), out _);
40+
41+
// 将内容转换为字节数组
42+
var dataToEncrypt = Encoding.UTF8.GetBytes(content);
43+
44+
// 计算最大加密块大小 (KeySize / 8 - 11 for PKCS1)
45+
// 1024位密钥 -> 128字节 -> max 117字节
46+
int bufferSize = (rsa.KeySize / 8) - 11;
47+
48+
// 使用内存流存储加密后的数据
49+
using var outputStream = new MemoryStream();
50+
51+
int offset = 0;
52+
while (offset < dataToEncrypt.Length)
53+
{
54+
int currentBlockSize = Math.Min(bufferSize, dataToEncrypt.Length - offset);
55+
var chunk = new byte[currentBlockSize];
56+
Array.Copy(dataToEncrypt, offset, chunk, 0, currentBlockSize);
57+
58+
var encryptedChunk = rsa.Encrypt(chunk, RSAEncryptionPadding.Pkcs1);
59+
outputStream.Write(encryptedChunk, 0, encryptedChunk.Length);
60+
61+
offset += currentBlockSize;
62+
}
63+
64+
return Convert.ToBase64String(outputStream.ToArray());
65+
}
66+
catch (CryptographicException ex)
67+
{
68+
// 如果导入失败,尝试作为 RSAPublicKey (PKCS#1) 导入
69+
rsa.ImportRSAPublicKey(Convert.FromBase64String(publicKey), out _);
70+
var dataToEncrypt = Encoding.UTF8.GetBytes(content);
71+
72+
int bufferSize = (rsa.KeySize / 8) - 11;
73+
using var outputStream = new MemoryStream();
74+
75+
int offset = 0;
76+
while (offset < dataToEncrypt.Length)
77+
{
78+
int currentBlockSize = Math.Min(bufferSize, dataToEncrypt.Length - offset);
79+
var chunk = new byte[currentBlockSize];
80+
Array.Copy(dataToEncrypt, offset, chunk, 0, currentBlockSize);
81+
82+
var encryptedChunk = rsa.Encrypt(chunk, RSAEncryptionPadding.Pkcs1);
83+
outputStream.Write(encryptedChunk, 0, encryptedChunk.Length);
84+
85+
offset += currentBlockSize;
86+
}
87+
88+
return Convert.ToBase64String(outputStream.ToArray());
89+
}
90+
}
91+
92+
/// <summary>
93+
/// 使用私钥解密数据(支持Base64格式私钥)
94+
/// </summary>
95+
/// <remarks>
96+
/// 本方法支持以下两种私钥格式:
97+
/// 1. PKCS#8 格式私钥
98+
/// 2. PKCS#1 格式私钥
99+
/// 当密文长度超过密钥长度时,自动采用分块解密。
100+
/// 输入的密文需为Base64编码,解密后返回明文字符串。
101+
/// </remarks>
102+
/// <param name="privateKey">Base64 格式的私钥字符串,支持 PKCS#1 与 PKCS#8 两种编码</param>
103+
/// <param name="content">Base64 格式的加密内容,需与 EncryptBase64 方法生成的格式保持一致</param>
104+
/// <returns>解密后的明文字符串,使用 UTF-8 编码还原</returns>
105+
/// <exception cref="ArgumentException">当 privateKey 或 content 为 null 或空字符串时抛出</exception>
106+
/// <exception cref="FormatException">当 content 不是合法的 Base64 字符串时抛出</exception>
107+
/// <exception cref="CryptographicException">当私钥格式非法或解密过程失败时抛出</exception>
108+
public static string DecryptBase64(string privateKey, string content)
109+
{
110+
ArgumentException.ThrowIfNullOrEmpty(privateKey, nameof(privateKey));
111+
ArgumentException.ThrowIfNullOrEmpty(content, nameof(content));
112+
113+
using var rsa = RSA.Create();
114+
try
115+
{
116+
// 尝试导入 PKCS#8 格式私钥
117+
rsa.ImportPkcs8PrivateKey(Convert.FromBase64String(privateKey), out _);
118+
}
119+
catch (CryptographicException)
120+
{
121+
// 尝试导入 PKCS#1 格式私钥
122+
rsa.ImportRSAPrivateKey(Convert.FromBase64String(privateKey), out _);
123+
}
124+
125+
var dataToDecrypt = Convert.FromBase64String(content);
126+
127+
// RSA 解密块大小等于密钥长度(字节)
128+
int bufferSize = rsa.KeySize / 8;
129+
using var outputStream = new MemoryStream();
130+
131+
int offset = 0;
132+
while (offset < dataToDecrypt.Length)
133+
{
134+
int currentBlockSize = Math.Min(bufferSize, dataToDecrypt.Length - offset);
135+
var chunk = new byte[currentBlockSize];
136+
Array.Copy(dataToDecrypt, offset, chunk, 0, currentBlockSize);
137+
138+
var decryptedChunk = rsa.Decrypt(chunk, RSAEncryptionPadding.Pkcs1);
139+
outputStream.Write(decryptedChunk, 0, decryptedChunk.Length);
140+
141+
offset += currentBlockSize;
142+
}
143+
144+
return Encoding.UTF8.GetString(outputStream.ToArray());
145+
}
146+
14147
/// <summary>
15148
/// RSA算法提供程序实例
16149
/// </summary>

0 commit comments

Comments
 (0)