From 9f448154701f022b9c32f0a7f0905a080f05f56e Mon Sep 17 00:00:00 2001 From: cryptochecktool Date: Tue, 26 Nov 2024 13:52:37 +0800 Subject: [PATCH] Create AesUtils.cs (#6161) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增AesUtils,替换掉DesUtils,提高安全性。 细节: 1.使用AES代替DES 2.正确使用IV调用方式 3.使用SHA256代替MD5进行密钥派生 4.使用PBKDF进行迭代生成密钥。 --- v2rayN/ServiceLib/Common/AesUtils.cs | 115 +++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 v2rayN/ServiceLib/Common/AesUtils.cs diff --git a/v2rayN/ServiceLib/Common/AesUtils.cs b/v2rayN/ServiceLib/Common/AesUtils.cs new file mode 100644 index 00000000..dec56742 --- /dev/null +++ b/v2rayN/ServiceLib/Common/AesUtils.cs @@ -0,0 +1,115 @@ +using System; +using System.IO; +using System.Security.Cryptography; +using System.Text; + +namespace ServiceLib.Common +{ + public class AesUtils + { + private const int KeySize = 256; // AES-256 + private const int IvSize = 16; // AES block size + private const int Iterations = 10000; + + private static readonly byte[] Salt = Encoding.ASCII.GetBytes("saltysalt".PadRight(16, ' '));//google浏览器默认盐值 + + /// + /// Encrypt + /// + /// Plain text + /// Password for key derivation + /// Base64 encoded cipher text with IV + public static string Encrypt(string text, string password) + { + if (string.IsNullOrEmpty(text)) + return string.Empty; + + if (string.IsNullOrEmpty(password)) + throw new ArgumentNullException("Password cannot be null."); + + byte[] plaintext = Encoding.UTF8.GetBytes(text); + byte[] key = GetDefaultKey(password); + byte[] iv = GenerateIv(); + + using (Aes aes = Aes.Create()) + { + aes.Key = key; + aes.IV = iv; + + using (MemoryStream ms = new MemoryStream()) + { + ms.Write(iv, 0, iv.Length); + + using (CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write)) + { + cs.Write(plaintext, 0, plaintext.Length); + cs.FlushFinalBlock(); + } + + byte[] cipherTextWithIv = ms.ToArray(); + return Convert.ToBase64String(cipherTextWithIv); + } + } + } + + /// + /// Decrypt + /// + /// Base64 encoded cipher text with IV + /// Password for key derivation + /// Plain text + public static string Decrypt(string cipherTextWithIv, string password) + { + if (string.IsNullOrEmpty(cipherTextWithIv)) + return string.Empty; + + if (string.IsNullOrEmpty(password)) + throw new ArgumentNullException("Password cannot be null."); + + byte[] cipherTextWithIvBytes = Convert.FromBase64String(cipherTextWithIv); + byte[] key = GetDefaultKey(password); + + byte[] iv = new byte[IvSize]; + Buffer.BlockCopy(cipherTextWithIvBytes, 0, iv, 0, IvSize); + + byte[] cipherText = new byte[cipherTextWithIvBytes.Length - IvSize]; + Buffer.BlockCopy(cipherTextWithIvBytes, IvSize, cipherText, 0, cipherText.Length - IvSize); + + using (Aes aes = Aes.Create()) + { + aes.Key = key; + aes.IV = iv; + + using (MemoryStream ms = new MemoryStream()) + { + using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write)) + { + cs.Write(cipherText, 0, cipherText.Length); + cs.FlushFinalBlock(); + } + + byte[] plainText = ms.ToArray(); + return Encoding.UTF8.GetString(plainText); + } + } + } + + private static byte[] GetDefaultKey(string password) + { + using (Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(password, Salt, Iterations, HashAlgorithmName.SHA256)) + { + return pbkdf2.GetBytes(KeySize / 8); + } + } + + private static byte[] GenerateIv() + { + using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider()) + { + byte[] iv = new byte[IvSize]; + rng.GetBytes(iv); + return iv; + } + } + } +}