diff --git a/shadowsocks-csharp/Controller/Service/TCPRelay.cs b/shadowsocks-csharp/Controller/Service/TCPRelay.cs index eb676ad2..eef5948c 100644 --- a/shadowsocks-csharp/Controller/Service/TCPRelay.cs +++ b/shadowsocks-csharp/Controller/Service/TCPRelay.cs @@ -125,7 +125,7 @@ namespace Shadowsocks.Controller { throw new ArgumentException("No server configured"); } - this.encryptor = EncryptorFactory.GetEncryptor(server.method, server.password, server.one_time_auth); + this.encryptor = EncryptorFactory.GetEncryptor(server.method, server.password, server.one_time_auth, false); this.server = server; } @@ -586,7 +586,7 @@ namespace Shadowsocks.Controller { return; } - encryptor.Encrypt(connetionRecvBuffer, bytesRead, connetionSendBuffer, out bytesToSend, false); + encryptor.Encrypt(connetionRecvBuffer, bytesRead, connetionSendBuffer, out bytesToSend); } remote.BeginSend(connetionSendBuffer, 0, bytesToSend, 0, new AsyncCallback(PipeRemoteSendCallback), null); diff --git a/shadowsocks-csharp/Controller/Service/UDPRelay.cs b/shadowsocks-csharp/Controller/Service/UDPRelay.cs index 9d3d3dcf..b449c412 100644 --- a/shadowsocks-csharp/Controller/Service/UDPRelay.cs +++ b/shadowsocks-csharp/Controller/Service/UDPRelay.cs @@ -74,12 +74,12 @@ namespace Shadowsocks.Controller } public void Send(byte[] data, int length) { - IEncryptor encryptor = EncryptorFactory.GetEncryptor(_server.method, _server.password, _server.one_time_auth); + IEncryptor encryptor = EncryptorFactory.GetEncryptor(_server.method, _server.password, _server.one_time_auth, true); byte[] dataIn = new byte[length - 3 + IVEncryptor.ONETIMEAUTH_BYTES]; Array.Copy(data, 3, dataIn, 0, length - 3); byte[] dataOut = new byte[length - 3 + 16 + IVEncryptor.ONETIMEAUTH_BYTES]; int outlen; - encryptor.Encrypt(dataIn, length - 3, dataOut, out outlen, true); + encryptor.Encrypt(dataIn, length - 3, dataOut, out outlen); _remote.SendTo(dataOut, outlen, SocketFlags.None, _remoteEndPoint); } public void Receive() @@ -97,7 +97,7 @@ namespace Shadowsocks.Controller byte[] dataOut = new byte[bytesRead]; int outlen; - IEncryptor encryptor = EncryptorFactory.GetEncryptor(_server.method, _server.password, _server.one_time_auth); + IEncryptor encryptor = EncryptorFactory.GetEncryptor(_server.method, _server.password, _server.one_time_auth, true); encryptor.Decrypt(_buffer, bytesRead, dataOut, out outlen); byte[] sendBuf = new byte[outlen + 3]; diff --git a/shadowsocks-csharp/Encryption/EncryptorBase.cs b/shadowsocks-csharp/Encryption/EncryptorBase.cs index 594e67bf..8285f165 100644 --- a/shadowsocks-csharp/Encryption/EncryptorBase.cs +++ b/shadowsocks-csharp/Encryption/EncryptorBase.cs @@ -8,16 +8,18 @@ namespace Shadowsocks.Encryption { public const int MAX_INPUT_SIZE = 32768; - protected EncryptorBase(string method, string password, bool onetimeauth) + protected EncryptorBase(string method, string password, bool onetimeauth, bool isudp) { Method = method; Password = password; OnetimeAuth = onetimeauth; + IsUDP = isudp; } protected string Method; protected string Password; protected bool OnetimeAuth; + protected bool IsUDP; protected byte[] GetPasswordHash() { @@ -26,7 +28,7 @@ namespace Shadowsocks.Encryption return hash; } - public abstract void Encrypt(byte[] buf, int length, byte[] outbuf, out int outlength, bool udp); + public abstract void Encrypt(byte[] buf, int length, byte[] outbuf, out int outlength); public abstract void Decrypt(byte[] buf, int length, byte[] outbuf, out int outlength); diff --git a/shadowsocks-csharp/Encryption/EncryptorFactory.cs b/shadowsocks-csharp/Encryption/EncryptorFactory.cs index d6c89b9f..f0e2d284 100644 --- a/shadowsocks-csharp/Encryption/EncryptorFactory.cs +++ b/shadowsocks-csharp/Encryption/EncryptorFactory.cs @@ -8,7 +8,7 @@ namespace Shadowsocks.Encryption { private static Dictionary _registeredEncryptors; - private static Type[] _constructorTypes = new Type[] { typeof(string), typeof(string), typeof(bool) }; + private static Type[] _constructorTypes = new Type[] { typeof(string), typeof(string), typeof(bool), typeof(bool) }; static EncryptorFactory() { @@ -27,7 +27,7 @@ namespace Shadowsocks.Encryption } } - public static IEncryptor GetEncryptor(string method, string password, bool onetimeauth) + public static IEncryptor GetEncryptor(string method, string password, bool onetimeauth, bool isudp) { if (string.IsNullOrEmpty(method)) { @@ -36,7 +36,7 @@ namespace Shadowsocks.Encryption method = method.ToLowerInvariant(); Type t = _registeredEncryptors[method]; ConstructorInfo c = t.GetConstructor(_constructorTypes); - IEncryptor result = (IEncryptor)c.Invoke(new object[] { method, password, onetimeauth }); + IEncryptor result = (IEncryptor)c.Invoke(new object[] { method, password, onetimeauth, isudp }); return result; } } diff --git a/shadowsocks-csharp/Encryption/IEncryptor.cs b/shadowsocks-csharp/Encryption/IEncryptor.cs index 33ce0816..b45c62c7 100644 --- a/shadowsocks-csharp/Encryption/IEncryptor.cs +++ b/shadowsocks-csharp/Encryption/IEncryptor.cs @@ -6,7 +6,7 @@ namespace Shadowsocks.Encryption { public interface IEncryptor : IDisposable { - void Encrypt(byte[] buf, int length, byte[] outbuf, out int outlength, bool udp); + void Encrypt(byte[] buf, int length, byte[] outbuf, out int outlength); void Decrypt(byte[] buf, int length, byte[] outbuf, out int outlength); } } diff --git a/shadowsocks-csharp/Encryption/IVEncryptor.cs b/shadowsocks-csharp/Encryption/IVEncryptor.cs index 8af5b9e5..52d1970b 100755 --- a/shadowsocks-csharp/Encryption/IVEncryptor.cs +++ b/shadowsocks-csharp/Encryption/IVEncryptor.cs @@ -40,8 +40,8 @@ namespace Shadowsocks.Encryption protected uint counter = 0; protected byte[] _keyBuffer = null; - public IVEncryptor(string method, string password, bool onetimeauth) - : base(method, password, onetimeauth) + public IVEncryptor(string method, string password, bool onetimeauth, bool isudp) + : base(method, password, onetimeauth, isudp) { InitKey(method, password); } @@ -183,38 +183,65 @@ namespace Shadowsocks.Encryption return hash; } - public override void Encrypt(byte[] buf, int length, byte[] outbuf, out int outlength, bool udp) + protected void reactBuffer4TCP(byte[] buf, ref int length) + { + if (!_encryptIVSent) + { + int headLen = getHeadLen(buf, length); + int dataLen = length - headLen; + buf[0] |= ONETIMEAUTH_FLAG; + byte[] hash = genOnetimeAuthHash(buf, headLen); + Buffer.BlockCopy(buf, headLen, buf, headLen + ONETIMEAUTH_BYTES + AUTH_BYTES, dataLen); + Buffer.BlockCopy(hash, 0, buf, headLen, ONETIMEAUTH_BYTES); + hash = genHash(buf, headLen + ONETIMEAUTH_BYTES + AUTH_BYTES, dataLen); + Buffer.BlockCopy(hash, 0, buf, headLen + ONETIMEAUTH_BYTES + CLEN_BYTES, ONETIMEAUTH_BYTES); + byte[] lenBytes = BitConverter.GetBytes((ushort)IPAddress.HostToNetworkOrder((short)dataLen)); + Buffer.BlockCopy(lenBytes, 0, buf, headLen + ONETIMEAUTH_BYTES, CLEN_BYTES); + length = headLen + ONETIMEAUTH_BYTES + AUTH_BYTES + dataLen; + } + else + { + byte[] hash = genHash(buf, 0, length); + Buffer.BlockCopy(buf, 0, buf, AUTH_BYTES, length); + byte[] lenBytes = BitConverter.GetBytes((ushort)IPAddress.HostToNetworkOrder((short)length)); + Buffer.BlockCopy(lenBytes, 0, buf, 0, CLEN_BYTES); + Buffer.BlockCopy(hash, 0, buf, CLEN_BYTES, ONETIMEAUTH_BYTES); + length += AUTH_BYTES; + } + } + + protected void reactBuffer4UDP(byte[] buf, ref int length) + { + buf[0] |= ONETIMEAUTH_FLAG; + byte[] hash = genOnetimeAuthHash(buf, length); + Buffer.BlockCopy(hash, 0, buf, length, ONETIMEAUTH_BYTES); + length += ONETIMEAUTH_BYTES; + } + + protected void reactBuffer(byte[] buf, ref int length) + { + if (OnetimeAuth && ivLen > 0) + { + if (!IsUDP) + { + reactBuffer4TCP(buf, ref length); + } + else + { + reactBuffer4UDP(buf, ref length); + } + } + } + + public override void Encrypt(byte[] buf, int length, byte[] outbuf, out int outlength) { if (!_encryptIVSent) { - _encryptIVSent = true; randBytes(outbuf, ivLen); initCipher(outbuf, true); outlength = length + ivLen; - if (OnetimeAuth && ivLen > 0) - { - if(!udp) - { - int headLen = getHeadLen(buf, length); - int dataLen = length - headLen; - buf[0] |= ONETIMEAUTH_FLAG; - byte[] hash = genOnetimeAuthHash(buf, headLen); - Buffer.BlockCopy(buf, headLen, buf, headLen + ONETIMEAUTH_BYTES + AUTH_BYTES, dataLen); - Buffer.BlockCopy(hash, 0, buf, headLen, ONETIMEAUTH_BYTES); - hash = genHash(buf, headLen + ONETIMEAUTH_BYTES + AUTH_BYTES, dataLen); - Buffer.BlockCopy(hash, 0, buf, headLen + ONETIMEAUTH_BYTES + CLEN_BYTES, ONETIMEAUTH_BYTES); - byte[] lenBytes = BitConverter.GetBytes((ushort)IPAddress.HostToNetworkOrder((short)dataLen)); - Buffer.BlockCopy(lenBytes, 0, buf, headLen + ONETIMEAUTH_BYTES, CLEN_BYTES); - length = headLen + ONETIMEAUTH_BYTES + AUTH_BYTES + dataLen; - } - else - { - buf[0] |= ONETIMEAUTH_FLAG; - byte[] hash = genOnetimeAuthHash(buf, length); - Buffer.BlockCopy(hash, 0, buf, length, ONETIMEAUTH_BYTES); - length += ONETIMEAUTH_BYTES; - } - } + reactBuffer(buf, ref length); + _encryptIVSent = true; lock (tempbuf) { cipherUpdate(true, length, buf, tempbuf); @@ -224,15 +251,7 @@ namespace Shadowsocks.Encryption } else { - if (OnetimeAuth && ivLen > 0) - { - byte[] hash = genHash(buf, 0, length); - Buffer.BlockCopy(buf, 0, buf, AUTH_BYTES, length); - byte[] lenBytes = BitConverter.GetBytes((ushort)IPAddress.HostToNetworkOrder((short)length)); - Buffer.BlockCopy(lenBytes, 0, buf, 0, CLEN_BYTES); - Buffer.BlockCopy(hash, 0, buf, CLEN_BYTES, ONETIMEAUTH_BYTES); - length += AUTH_BYTES; - } + reactBuffer(buf, ref length); outlength = length; cipherUpdate(true, length, buf, outbuf); } diff --git a/shadowsocks-csharp/Encryption/PolarSSLEncryptor.cs b/shadowsocks-csharp/Encryption/PolarSSLEncryptor.cs index 3aca3f72..3b3331f9 100755 --- a/shadowsocks-csharp/Encryption/PolarSSLEncryptor.cs +++ b/shadowsocks-csharp/Encryption/PolarSSLEncryptor.cs @@ -16,8 +16,8 @@ namespace Shadowsocks.Encryption private IntPtr _encryptCtx = IntPtr.Zero; private IntPtr _decryptCtx = IntPtr.Zero; - public PolarSSLEncryptor(string method, string password, bool onetimeauth) - : base(method, password, onetimeauth) + public PolarSSLEncryptor(string method, string password, bool onetimeauth, bool isudp) + : base(method, password, onetimeauth, isudp) { InitKey(method, password); } diff --git a/shadowsocks-csharp/Encryption/SodiumEncryptor.cs b/shadowsocks-csharp/Encryption/SodiumEncryptor.cs index 8ab8e255..a18d2a69 100755 --- a/shadowsocks-csharp/Encryption/SodiumEncryptor.cs +++ b/shadowsocks-csharp/Encryption/SodiumEncryptor.cs @@ -20,8 +20,8 @@ namespace Shadowsocks.Encryption protected ulong _encryptIC; protected ulong _decryptIC; - public SodiumEncryptor(string method, string password, bool onetimeauth) - : base(method, password, onetimeauth) + public SodiumEncryptor(string method, string password, bool onetimeauth, bool isudp) + : base(method, password, onetimeauth, isudp) { InitKey(method, password); } diff --git a/shadowsocks-csharp/Encryption/TableEncryptor.cs b/shadowsocks-csharp/Encryption/TableEncryptor.cs index 3f3c5f8c..4b6c8fe3 100644 --- a/shadowsocks-csharp/Encryption/TableEncryptor.cs +++ b/shadowsocks-csharp/Encryption/TableEncryptor.cs @@ -6,8 +6,8 @@ namespace Shadowsocks.Encryption public class TableEncryptor : EncryptorBase { - public TableEncryptor(string method, string password, bool onetimeauth) - : base(method, password, onetimeauth) + public TableEncryptor(string method, string password, bool onetimeauth, bool isudp) + : base(method, password, onetimeauth, isudp) { byte[] hash = GetPasswordHash(); // TODO endian @@ -31,7 +31,7 @@ namespace Shadowsocks.Encryption return new List(new string[]{"table"}); } - public override void Encrypt(byte[] buf, int length, byte[] outbuf, out int outlength, bool udp) + public override void Encrypt(byte[] buf, int length, byte[] outbuf, out int outlength) { byte[] result = new byte[length]; for (int i = 0; i < length; i++) diff --git a/test/UnitTest.cs b/test/UnitTest.cs index 70c001f3..1970e85f 100755 --- a/test/UnitTest.cs +++ b/test/UnitTest.cs @@ -31,21 +31,21 @@ namespace test int outLen2 = 0; var random = new Random(); random.NextBytes(plain); - encryptor.Encrypt(plain, plain.Length, cipher, out outLen, false); + encryptor.Encrypt(plain, plain.Length, cipher, out outLen); decryptor.Decrypt(cipher, outLen, plain2, out outLen2); Assert.AreEqual(plain.Length, outLen2); for (int j = 0; j < plain.Length; j++) { Assert.AreEqual(plain[j], plain2[j]); } - encryptor.Encrypt(plain, 1000, cipher, out outLen, false); + encryptor.Encrypt(plain, 1000, cipher, out outLen); decryptor.Decrypt(cipher, outLen, plain2, out outLen2); Assert.AreEqual(1000, outLen2); for (int j = 0; j < outLen2; j++) { Assert.AreEqual(plain[j], plain2[j]); } - encryptor.Encrypt(plain, 12333, cipher, out outLen, false); + encryptor.Encrypt(plain, 12333, cipher, out outLen); decryptor.Decrypt(cipher, outLen, plain2, out outLen2); Assert.AreEqual(12333, outLen2); for (int j = 0; j < outLen2; j++) @@ -84,8 +84,8 @@ namespace test { IEncryptor encryptor; IEncryptor decryptor; - encryptor = new PolarSSLEncryptor("aes-256-cfb", "barfoo!", false); - decryptor = new PolarSSLEncryptor("aes-256-cfb", "barfoo!", false); + encryptor = new PolarSSLEncryptor("aes-256-cfb", "barfoo!", false, false); + decryptor = new PolarSSLEncryptor("aes-256-cfb", "barfoo!", false, false); RunEncryptionRound(encryptor, decryptor); } } @@ -124,8 +124,8 @@ namespace test var random = new Random(); IEncryptor encryptor; IEncryptor decryptor; - encryptor = new PolarSSLEncryptor("rc4-md5", "barfoo!", false); - decryptor = new PolarSSLEncryptor("rc4-md5", "barfoo!", false); + encryptor = new PolarSSLEncryptor("rc4-md5", "barfoo!", false, false); + decryptor = new PolarSSLEncryptor("rc4-md5", "barfoo!", false, false); RunEncryptionRound(encryptor, decryptor); } } @@ -164,8 +164,8 @@ namespace test var random = new Random(); IEncryptor encryptor; IEncryptor decryptor; - encryptor = new SodiumEncryptor("salsa20", "barfoo!", false); - decryptor = new SodiumEncryptor("salsa20", "barfoo!", false); + encryptor = new SodiumEncryptor("salsa20", "barfoo!", false, false); + decryptor = new SodiumEncryptor("salsa20", "barfoo!", false, false); RunEncryptionRound(encryptor, decryptor); } }