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 string Sign(string src) { lock (_RsaLock) { byte[] srcBytes = Encoding.UTF8.GetBytes(src); byte[] signatureBytes = _Rsa.SignData(srcBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); return Convert.ToBase64String(signatureBytes); } } 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]); } } }