diff --git a/v2rayN/ServiceLib/Common/AesUtils.cs b/v2rayN/ServiceLib/Common/AesUtils.cs
new file mode 100644
index 00000000..f6ccf761
--- /dev/null
+++ b/v2rayN/ServiceLib/Common/AesUtils.cs
@@ -0,0 +1,128 @@
+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浏览器默认盐值
+
+ private static readonly string DefaultPassword =Utils.GetHomePath() + "AesUtils";
+
+ ///
+ /// Encrypt
+ ///
+ /// Plain text
+ /// Password for key derivation or direct key in ASCII bytes
+ /// Base64 encoded cipher text with IV
+ public static string Encrypt(string text, string password = null)
+ {
+ if (string.IsNullOrEmpty(text))
+ return string.Empty;
+
+ byte[] plaintext = Encoding.UTF8.GetBytes(text);
+ byte[] key = GetKey(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 or direct key in ASCII bytes
+ /// Plain text
+ public static string Decrypt(string cipherTextWithIv, string password = null)
+ {
+ if (string.IsNullOrEmpty(cipherTextWithIv))
+ return string.Empty;
+
+ byte[] cipherTextWithIvBytes = Convert.FromBase64String(cipherTextWithIv);
+ byte[] key = GetKey(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);
+
+ 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[] GetKey(string password)
+ {
+ if (string.IsNullOrEmpty(password))
+ {
+ return GetDefaultKey();
+ }
+ else
+ {
+ byte[] key = Encoding.ASCII.GetBytes(password);
+ if (key.Length != KeySize / 8)
+ {
+ throw new ArgumentException($"Password bytes length must be {KeySize / 8} bytes.");
+ }
+ return key;
+ }
+ }
+
+ private static byte[] GetDefaultKey()
+ {
+ using (Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(DefaultPassword, 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;
+ }
+ }
+ }
+}