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); + } + } +}