using System.Security.Cryptography;
using System.Text;
namespace OnlineMsgServer.Core
{
class RsaService
{
//用于服务端加密解密
private static readonly RSA _Rsa = RSA.Create();
private static readonly object _RsaLock = new();
//用于客户端加密
private static readonly RSA _PublicRsa = RSA.Create();
private static readonly object _PublicRsaLock = new();
///
/// 用客户端公钥加密
///
public static string EncryptForClient(string pkey, string msg)
{
lock (_PublicRsaLock)
{
_PublicRsa.ImportSubjectPublicKeyInfo(Convert.FromBase64String(pkey), out _);
// byte[] encrypt = _PublicRsa.Encrypt(Encoding.UTF8.GetBytes(msg), RSAEncryptionPadding.OaepSHA256);
// return Convert.ToBase64String(encrypt);
return RsaEncrypt(_PublicRsa, msg);
}
}
///
/// 导入服务端私钥
///
public static void LoadRsaPkey(SecurityConfig config)
{
lock (_RsaLock)
{
if (!string.IsNullOrWhiteSpace(config.ServerPrivateKeyBase64))
{
_Rsa.ImportPkcs8PrivateKey(Convert.FromBase64String(config.ServerPrivateKeyBase64), out _);
return;
}
if (!string.IsNullOrWhiteSpace(config.ServerPrivateKeyPath))
{
string pkey = File.ReadAllText(config.ServerPrivateKeyPath).Trim();
_Rsa.ImportPkcs8PrivateKey(Convert.FromBase64String(pkey), out _);
return;
}
if (config.AllowEphemeralServerKey)
{
OnlineMsgServer.Common.Log.Security("server_key_ephemeral", "using in-memory generated private key");
return;
}
throw new InvalidOperationException("服务端私钥未配置。请设置 SERVER_PRIVATE_KEY_B64 或 SERVER_PRIVATE_KEY_PATH。");
}
}
///
/// 以base64格式导出公钥字符串
///
/// 公钥字符串,base64格式
public static string GetRsaPublickKey()
{
lock (_RsaLock)
{
return Convert.ToBase64String(_Rsa.ExportSubjectPublicKeyInfo());
}
}
///
/// 服务端解密 base64编码
///
/// 密文
/// 原文字符串
public static string Decrypt(string secret)
{
lock (_RsaLock)
{
byte[] secretBytes = Convert.FromBase64String(secret);
int size = secretBytes.Length;
int blockSize = 256;
if (size % blockSize != 0)
{
throw new FormatException("ciphertext length invalid");
}
int blockCount = size / blockSize;
List decryptList = [];
for (int i = 0; i < blockCount; i++)
{
byte[] block = new byte[blockSize];
Array.Copy(secretBytes, i * blockSize, block, 0, blockSize);
byte[] decryptBlock = _Rsa.Decrypt(block, RSAEncryptionPadding.OaepSHA256);
decryptList.AddRange(decryptBlock);
}
// byte[] decrypt = _Rsa.Decrypt(Convert.FromBase64String(base64),
// RSAEncryptionPadding.OaepSHA256);
return Encoding.UTF8.GetString([.. decryptList]);
}
}
///
/// 服务端加密 base64编码
///
/// 原文字符串
/// 密文
public static string Encrypt(string src)
{
lock (_RsaLock)
{
return RsaEncrypt(_Rsa, src);
}
}
public static bool VerifySignature(string publicKeyBase64, string src, string signatureBase64)
{
lock (_PublicRsaLock)
{
try
{
_PublicRsa.ImportSubjectPublicKeyInfo(Convert.FromBase64String(publicKeyBase64), out _);
byte[] srcBytes = Encoding.UTF8.GetBytes(src);
byte[] signatureBytes = Convert.FromBase64String(signatureBase64);
return _PublicRsa.VerifyData(srcBytes, signatureBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
}
catch
{
return false;
}
}
}
public static bool IsPublicKeyValid(string publicKeyBase64)
{
lock (_PublicRsaLock)
{
try
{
_PublicRsa.ImportSubjectPublicKeyInfo(Convert.FromBase64String(publicKeyBase64), out _);
return true;
}
catch
{
return false;
}
}
}
private static string RsaEncrypt(RSA rsa, string src)
{
byte[] srcBytes = Encoding.UTF8.GetBytes(src);
int size = srcBytes.Length;
int blockSize = 190;
if (size == 0)
{
return "";
}
int blockCount = (size + blockSize - 1) / blockSize;
List encryptList = [];
for (int i = 0; i < blockCount; i++)
{
int len = Math.Min(blockSize, size - i * blockSize);
byte[] block = new byte[len];
Array.Copy(srcBytes, i * blockSize, block, 0, len);
byte[] encryptBlock = rsa.Encrypt(block, RSAEncryptionPadding.OaepSHA256);
encryptList.AddRange(encryptBlock);
}
return Convert.ToBase64String([.. encryptList]);
}
}
}