diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml
index 40bbf75d..cf05a8ea 100644
--- a/.github/workflows/dotnet.yml
+++ b/.github/workflows/dotnet.yml
@@ -48,18 +48,16 @@ jobs:
env:
GITHUB_TOKEN: '${{ secrets.ACTIONS_TOKEN }}'
with:
- tag_name: v1.2.0.4
- release_name: v1.2.0.4.${{ steps.date.outputs.today }}
+ tag_name: v1.2.0.5
+ release_name: v1.2.0.5.${{ steps.date.outputs.today }}
draft: false
prerelease: false
body: |
- 1. 新增排序
- 2. 新增网卡自定义掩码
- 3. 新增网卡端口转发
- 4. 新增托盘置顶
- 5. 移除linker.service,将windows service内置
- 6. windows下,需要重新卸载安装服务
- 7. 先更新所有客户端,再更新服务端(先更新服务端会获取不到客户端列表)
+ 1. UDP端口映射连接(无ssl加密)
+ 2. UDP打洞,纯净版(无ssl加密)
+ 3. 如果当前版本小于v1.2.0.4,则windows下需要重新卸载安装服务
+ 4. 先更新所有客户端,再更新服务端(先更新服务端会获取不到客户端列表)
+ 5. 用不上无加密UDP打洞的可以不更新
- name: upload win x86
id: upload-win-x86
diff --git a/linker.libs/Crypto.cs b/linker.libs/Crypto.cs
new file mode 100644
index 00000000..c2473abe
--- /dev/null
+++ b/linker.libs/Crypto.cs
@@ -0,0 +1,242 @@
+using System;
+using System.IO;
+using System.Security.Cryptography;
+using System.Text;
+
+namespace linker.libs
+{
+ public interface ICryptoFactory
+ {
+ ///
+ /// 对称加密
+ ///
+ ///
+ ///
+ public ISymmetricCrypto CreateSymmetric(string password);
+ ///
+ /// 非对称加密
+ ///
+ ///
+ ///
+ public IAsymmetricCrypto CreateAsymmetric(RsaKey key);
+ }
+
+ public sealed class CryptoFactory : ICryptoFactory
+ {
+ ///
+ /// 对称加密
+ ///
+ ///
+ ///
+ public ISymmetricCrypto CreateSymmetric(string password)
+ {
+ return new AesCrypto(password);
+ }
+ ///
+ /// 非对称加密
+ ///
+ ///
+ ///
+ public IAsymmetricCrypto CreateAsymmetric(RsaKey key)
+ {
+ return new RsaCrypto(key);
+ }
+ }
+
+ public interface ICrypto : IDisposable
+ {
+ public byte[] Encode(byte[] buffer);
+ public byte[] Encode(in ReadOnlyMemory buffer);
+ public Memory Decode(byte[] buffer);
+ public Memory Decode(in ReadOnlyMemory buffer);
+ }
+
+ ///
+ /// 非对称加密
+ ///
+ public interface IAsymmetricCrypto : ICrypto
+ {
+ public RsaKey Key { get; }
+ }
+ public sealed class RsaCrypto : IAsymmetricCrypto
+ {
+ RsaKey key = new RsaKey();
+
+ public RsaKey Key => key;
+ public RsaCrypto()
+ {
+ CreateKey();
+ }
+ public RsaCrypto(RsaKey key)
+ {
+ if (key != null)
+ {
+ this.key = key;
+ }
+ else
+ {
+ CreateKey();
+ }
+ }
+ public Memory Decode(byte[] buffer)
+ {
+ using RSACryptoServiceProvider coder = new RSACryptoServiceProvider();
+ coder.FromXmlString(key.PrivateKey);
+
+ int blockLen = coder.KeySize / 8;
+ if (buffer.Length <= blockLen)
+ {
+ return coder.Decrypt(buffer, false);
+ }
+
+ using MemoryStream dataStream = new MemoryStream(buffer);
+ using MemoryStream enStream = new MemoryStream();
+
+ byte[] data = new byte[blockLen];
+ while (true)
+ {
+ int len = dataStream.Read(data, 0, blockLen);
+ if (len == 0) break;
+
+ if (len == blockLen)
+ {
+ byte[] enBlock = coder.Decrypt(data, false);
+ enStream.Write(enBlock, 0, enBlock.Length);
+ }
+ else
+ {
+ byte[] block = new byte[len];
+ Array.Copy(data, 0, block, 0, len);
+
+ byte[] enBlock = coder.Decrypt(block, false);
+ enStream.Write(enBlock, 0, enBlock.Length);
+ break;
+ }
+ }
+ return enStream.ToArray();
+ }
+ public Memory Decode(in ReadOnlyMemory buffer)
+ {
+ return Decode(buffer.ToArray());
+ }
+ public byte[] Encode(byte[] buffer)
+ {
+ using RSACryptoServiceProvider coder = new RSACryptoServiceProvider();
+ coder.FromXmlString(key.PublicKey);
+
+ int blockLen = coder.KeySize / 8 - 11;
+ if (buffer.Length <= blockLen)
+ {
+ return coder.Encrypt(buffer, false);
+ }
+
+ using MemoryStream dataStream = new MemoryStream(buffer);
+ using MemoryStream enStream = new MemoryStream();
+
+ byte[] data = new byte[blockLen];
+ while (true)
+ {
+ int len = dataStream.Read(data, 0, blockLen);
+ if (len == 0) break;
+
+ if (len == blockLen)
+ {
+ byte[] enBlock = coder.Encrypt(data, false);
+ enStream.Write(enBlock, 0, enBlock.Length);
+ }
+ else
+ {
+ byte[] block = new byte[len];
+ Array.Copy(data, 0, block, 0, len);
+
+ byte[] enBlock = coder.Encrypt(block, false);
+ enStream.Write(enBlock, 0, enBlock.Length);
+ break;
+ }
+ }
+
+ return enStream.ToArray();
+ }
+
+ public byte[] Encode(in ReadOnlyMemory buffer)
+ {
+ return Encode(buffer.ToArray());
+ }
+
+ public void Dispose()
+ {
+ key = null;
+ }
+
+ private void CreateKey()
+ {
+ using RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
+ key.PrivateKey = rsa.ToXmlString(true);
+ key.PublicKey = rsa.ToXmlString(false);
+ }
+
+ }
+
+ public sealed class RsaKey
+ {
+ public string PrivateKey { get; set; }
+ public string PublicKey { get; set; }
+ }
+
+ public interface ISymmetricCrypto : ICrypto
+ {
+ public string Password { get; set; }
+ }
+ public sealed class AesCrypto : ISymmetricCrypto
+ {
+ private ICryptoTransform encryptoTransform;
+ private ICryptoTransform decryptoTransform;
+
+ public string Password { get; set; }
+
+ public AesCrypto(in string password)
+ {
+ Password = password;
+ using Aes aes = Aes.Create();
+ aes.Padding = PaddingMode.ANSIX923;
+ (aes.Key, aes.IV) = GenerateKeyAndIV(password);
+
+ encryptoTransform = aes.CreateEncryptor(aes.Key, aes.IV);
+ decryptoTransform = aes.CreateDecryptor(aes.Key, aes.IV);
+ }
+ public byte[] Encode(byte[] buffer)
+ {
+ return encryptoTransform.TransformFinalBlock(buffer, 0, buffer.Length);
+ }
+ public byte[] Encode(in ReadOnlyMemory buffer)
+ {
+ return Encode(buffer.ToArray());
+ }
+ public Memory Decode(byte[] buffer)
+ {
+ return decryptoTransform.TransformFinalBlock(buffer, 0, buffer.Length);
+ }
+ public Memory Decode(in ReadOnlyMemory buffer)
+ {
+ return Decode(buffer.ToArray());
+ }
+ public void Dispose()
+ {
+ encryptoTransform.Dispose();
+ decryptoTransform.Dispose();
+ }
+
+ private (byte[] Key, byte[] IV) GenerateKeyAndIV(in string password)
+ {
+ byte[] key = new byte[32];
+ byte[] iv = new byte[16];
+
+ using SHA384 sha = SHA384.Create();
+ byte[] hash = sha.ComputeHash(Encoding.UTF8.GetBytes(password));
+
+ Array.Copy(hash, 0, key, 0, 32);
+ Array.Copy(hash, 32, iv, 0, 16);
+ return (Key: key, IV: iv);
+ }
+ }
+}