ow
This commit is contained in:
commit
f05d2d215f
678 files changed
+73865
No files matched your search
@@ -0,0 +1,295 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using CryptographyRSA = System.Security.Cryptography.RSA; // 别名避免与当前类名冲突
|
||||
|
||||
namespace System
|
||||
{
|
||||
/// <summary>
|
||||
/// RSA操作类(跨平台实现)
|
||||
/// </summary>
|
||||
public class RSA
|
||||
{
|
||||
// 记录当前实例是否仅包含公钥(替代原来的 rsa.PublicOnly)
|
||||
private bool publicOnly;
|
||||
|
||||
/// <summary>
|
||||
/// 导出XML格式密钥对,如果convertToPublic含私钥的RSA将只返回公钥,仅含公钥的RSA不受影响
|
||||
/// </summary>
|
||||
public string ToXML(bool convertToPublic = false)
|
||||
{
|
||||
bool includePrivate = !publicOnly && !convertToPublic;
|
||||
return rsa.ToXmlString(includePrivate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 导出PEM PKCS#1格式密钥对,如果convertToPublic含私钥的RSA将只返回公钥,仅含公钥的RSA不受影响
|
||||
/// </summary>
|
||||
public string ToPEM_PKCS1(bool convertToPublic = false)
|
||||
{
|
||||
if (!publicOnly && !convertToPublic)
|
||||
{
|
||||
return rsa.ExportRSAPrivateKeyPem();
|
||||
}
|
||||
return rsa.ExportRSAPublicKeyPem();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 导出PEM PKCS#8格式密钥对,如果convertToPublic含私钥的RSA将只返回公钥,仅含公钥的RSA不受影响
|
||||
/// </summary>
|
||||
public string ToPEM_PKCS8(bool convertToPublic = false)
|
||||
{
|
||||
if (!publicOnly && !convertToPublic)
|
||||
{
|
||||
return rsa.ExportPkcs8PrivateKeyPem();
|
||||
}
|
||||
return rsa.ExportSubjectPublicKeyInfoPem();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加密字符串(utf-8),出错抛异常
|
||||
/// </summary>
|
||||
public string Encode(string str)
|
||||
{
|
||||
return RSA_Unit.Base64EncodeBytes(Encode(Encoding.UTF8.GetBytes(str)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加密数据,出错抛异常
|
||||
/// </summary>
|
||||
public byte[] Encode(byte[] data)
|
||||
{
|
||||
int blockLen = rsa.KeySize / 8 - 11;
|
||||
if (data.Length <= blockLen)
|
||||
{
|
||||
return rsa.Encrypt(data, RSAEncryptionPadding.Pkcs1);
|
||||
}
|
||||
|
||||
using (var dataStream = new MemoryStream(data))
|
||||
using (var enStream = new MemoryStream())
|
||||
{
|
||||
byte[] buffer = new byte[blockLen];
|
||||
int len = dataStream.Read(buffer, 0, blockLen);
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
byte[] block = new byte[len];
|
||||
Array.Copy(buffer, 0, block, 0, len);
|
||||
|
||||
byte[] enBlock = rsa.Encrypt(block, RSAEncryptionPadding.Pkcs1);
|
||||
enStream.Write(enBlock, 0, enBlock.Length);
|
||||
|
||||
len = dataStream.Read(buffer, 0, blockLen);
|
||||
}
|
||||
|
||||
return enStream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解密字符串(utf-8),解密异常返回null
|
||||
/// </summary>
|
||||
public string DecodeOrNull(string str)
|
||||
{
|
||||
if (string.IsNullOrEmpty(str))
|
||||
return null;
|
||||
|
||||
var bytes = RSA_Unit.Base64DecodeBytes(str);
|
||||
if (bytes == null)
|
||||
return null;
|
||||
|
||||
var decrypted = DecodeOrNull(bytes);
|
||||
if (decrypted == null)
|
||||
return null;
|
||||
|
||||
return Encoding.UTF8.GetString(decrypted);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解密数据,解密异常返回null
|
||||
/// </summary>
|
||||
public byte[] DecodeOrNull(byte[] data)
|
||||
{
|
||||
try
|
||||
{
|
||||
int blockLen = rsa.KeySize / 8;
|
||||
if (data.Length <= blockLen)
|
||||
{
|
||||
return rsa.Decrypt(data, RSAEncryptionPadding.Pkcs1);
|
||||
}
|
||||
|
||||
using (var dataStream = new MemoryStream(data))
|
||||
using (var deStream = new MemoryStream())
|
||||
{
|
||||
byte[] buffer = new byte[blockLen];
|
||||
int len = dataStream.Read(buffer, 0, blockLen);
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
byte[] block = new byte[len];
|
||||
Array.Copy(buffer, 0, block, 0, len);
|
||||
|
||||
byte[] deBlock = rsa.Decrypt(block, RSAEncryptionPadding.Pkcs1);
|
||||
deStream.Write(deBlock, 0, deBlock.Length);
|
||||
|
||||
len = dataStream.Read(buffer, 0, blockLen);
|
||||
}
|
||||
|
||||
return deStream.ToArray();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 对str进行签名,并指定hash算法(如:SHA256)
|
||||
/// </summary>
|
||||
public string Sign(string hash, string str)
|
||||
{
|
||||
return RSA_Unit.Base64EncodeBytes(Sign(hash, Encoding.UTF8.GetBytes(str)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 对data进行签名,并指定hash算法(如:SHA256)
|
||||
/// </summary>
|
||||
public byte[] Sign(string hash, byte[] data)
|
||||
{
|
||||
return rsa.SignData(data, new HashAlgorithmName(hash), RSASignaturePadding.Pkcs1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证字符串str的签名是否是sgin,并指定hash算法(如:SHA256)
|
||||
/// </summary>
|
||||
public bool Verify(string hash, string sgin, string str)
|
||||
{
|
||||
var bytes = RSA_Unit.Base64DecodeBytes(sgin);
|
||||
if (bytes == null)
|
||||
return false;
|
||||
|
||||
return Verify(hash, bytes, Encoding.UTF8.GetBytes(str));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证data的签名是否是sgin,并指定hash算法(如:SHA256)
|
||||
/// </summary>
|
||||
public bool Verify(string hash, byte[] sgin, byte[] data)
|
||||
{
|
||||
try
|
||||
{
|
||||
return rsa.VerifyData(data, sgin, new HashAlgorithmName(hash), RSASignaturePadding.Pkcs1);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private CryptographyRSA rsa;
|
||||
|
||||
public RSA() : this(2048)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用指定密钥大小创建一个新的RSA,出错抛异常
|
||||
/// </summary>
|
||||
public RSA(int keySize)
|
||||
{
|
||||
rsa = CryptographyRSA.Create();
|
||||
rsa.KeySize = keySize;
|
||||
publicOnly = false; // 新生成的密钥对包含私钥
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过指定的密钥,创建一个RSA,xml内可以只包含一个公钥或私钥,或都包含,出错抛异常
|
||||
/// </summary>
|
||||
public RSA(string xml)
|
||||
{
|
||||
rsa = CryptographyRSA.Create();
|
||||
rsa.FromXmlString(xml);
|
||||
|
||||
// 判断是否仅包含公钥
|
||||
publicOnly = false;
|
||||
try
|
||||
{
|
||||
rsa.ExportParameters(true); // 能导出私钥参数说明含私钥
|
||||
}
|
||||
catch (CryptographicException)
|
||||
{
|
||||
publicOnly = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过一个pem文件创建RSA,pem为公钥或私钥,出错抛异常
|
||||
/// </summary>
|
||||
public RSA(string pem, bool noop)
|
||||
{
|
||||
rsa = CryptographyRSA.Create();
|
||||
|
||||
// 1. 兼容文件路径
|
||||
string pemContent = pem;
|
||||
if (!pemContent.Contains("BEGIN"))
|
||||
{
|
||||
pemContent = File.ReadAllText(pem);
|
||||
}
|
||||
|
||||
// 2. 提取 Base64 部分(忽略标签)
|
||||
var match = Regex.Match(pemContent,
|
||||
@"-----BEGIN [^-]+-----([\s\S]*?)-----END [^-]+-----",
|
||||
RegexOptions.Singleline);
|
||||
if (!match.Success)
|
||||
throw new CryptographicException("无效的 PEM 格式。");
|
||||
|
||||
string base64 = match.Groups[1].Value
|
||||
.Replace("\r", "")
|
||||
.Replace("\n", "")
|
||||
.Replace(" ", "")
|
||||
.Replace("\t", "")
|
||||
.Trim();
|
||||
|
||||
byte[] der = Convert.FromBase64String(base64);
|
||||
|
||||
// 3. 依次尝试常见 RSA 密钥格式(顺序可调整)
|
||||
// 先尝试 PKCS#8 私钥,再尝试 PKCS#1 私钥,然后公钥
|
||||
try
|
||||
{
|
||||
rsa.ImportPkcs8PrivateKey(der, out _);
|
||||
publicOnly = false;
|
||||
return;
|
||||
}
|
||||
catch (CryptographicException) { }
|
||||
|
||||
try
|
||||
{
|
||||
rsa.ImportRSAPrivateKey(der, out _);
|
||||
publicOnly = false;
|
||||
return;
|
||||
}
|
||||
catch (CryptographicException) { }
|
||||
|
||||
try
|
||||
{
|
||||
rsa.ImportSubjectPublicKeyInfo(der, out _);
|
||||
publicOnly = true;
|
||||
return;
|
||||
}
|
||||
catch (CryptographicException) { }
|
||||
|
||||
try
|
||||
{
|
||||
rsa.ImportRSAPublicKey(der, out _);
|
||||
publicOnly = true;
|
||||
return;
|
||||
}
|
||||
catch (CryptographicException) { }
|
||||
|
||||
throw new CryptographicException("无法识别的 RSA 密钥格式。");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user