From a5fbcb18a269280c6babe60f04c2706fc7d8b687 Mon Sep 17 00:00:00 2001 From: clowwindy Date: Sun, 2 Nov 2014 20:27:18 +0800 Subject: [PATCH] use less RAM --- shadowsocks-csharp/Encrypt/EncryptorBase.cs | 60 +++--- shadowsocks-csharp/Encrypt/IEncryptor.cs | 8 +- .../Encrypt/OpensslEncryptor.cs | 69 +++--- shadowsocks-csharp/Encrypt/TableEncryptor.cs | 198 +++++++++--------- shadowsocks-csharp/Local.cs | 35 ++-- 5 files changed, 184 insertions(+), 186 deletions(-) diff --git a/shadowsocks-csharp/Encrypt/EncryptorBase.cs b/shadowsocks-csharp/Encrypt/EncryptorBase.cs index 82ceeca8..5420cfb6 100644 --- a/shadowsocks-csharp/Encrypt/EncryptorBase.cs +++ b/shadowsocks-csharp/Encrypt/EncryptorBase.cs @@ -1,29 +1,31 @@ -using System.Security.Cryptography; -using System.Text; - -namespace shadowsocks_csharp.Encrypt -{ - public abstract class EncryptorBase - : IEncryptor - { - protected EncryptorBase(string method, string password) - { - Method = method; - Password = password; - } - - protected string Method; - protected string Password; - - protected byte[] GetPasswordHash() - { - byte[] inputBytes = Encoding.UTF8.GetBytes(Password); - byte[] hash = MD5.Create().ComputeHash(inputBytes); - return hash; - } - - public abstract byte[] Encrypt(byte[] buf, int length); - - public abstract byte[] Decrypt(byte[] buf, int length); - } -} +using System.Security.Cryptography; +using System.Text; + +namespace shadowsocks_csharp.Encrypt +{ + public abstract class EncryptorBase + : IEncryptor + { + protected EncryptorBase(string method, string password) + { + Method = method; + Password = password; + } + + protected string Method; + protected string Password; + + protected byte[] GetPasswordHash() + { + byte[] inputBytes = Encoding.UTF8.GetBytes(Password); + byte[] hash = MD5.Create().ComputeHash(inputBytes); + return hash; + } + + 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); + + public abstract void Dispose(); + } +} diff --git a/shadowsocks-csharp/Encrypt/IEncryptor.cs b/shadowsocks-csharp/Encrypt/IEncryptor.cs index 7675657a..b48828b6 100644 --- a/shadowsocks-csharp/Encrypt/IEncryptor.cs +++ b/shadowsocks-csharp/Encrypt/IEncryptor.cs @@ -4,9 +4,9 @@ using System.Text; namespace shadowsocks_csharp.Encrypt { - public interface IEncryptor - { - byte[] Encrypt(byte[] buf, int length); - byte[] Decrypt(byte[] buf, int length); + public interface IEncryptor : IDisposable + { + 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/Encrypt/OpensslEncryptor.cs b/shadowsocks-csharp/Encrypt/OpensslEncryptor.cs index d8548f4f..a3df5039 100644 --- a/shadowsocks-csharp/Encrypt/OpensslEncryptor.cs +++ b/shadowsocks-csharp/Encrypt/OpensslEncryptor.cs @@ -26,59 +26,42 @@ namespace shadowsocks_csharp.Encrypt : base(method, password) { InitKey(method, password); - } + } + + + static byte[] tempbuf = new byte[32768]; - public override byte[] Encrypt(byte[] buf, int length) + public override void Encrypt(byte[] buf, int length, byte[] outbuf, out int outlength) { if (_encryptCtx == IntPtr.Zero) - { - byte[] iv = new byte[ivLen]; - OpenSSL.RAND_bytes(iv, iv.Length); - InitCipher(ref _encryptCtx, iv, true); - int outLen = length + ivLen; - byte[] cipherText = new byte[outLen]; - OpenSSL.EVP_CipherUpdate(_encryptCtx, cipherText, out outLen, buf, length); - byte[] result = new byte[outLen + ivLen]; - Buffer.BlockCopy(iv, 0, result, 0, ivLen); - Buffer.BlockCopy(cipherText, 0, result, ivLen, outLen); - return result; + { + OpenSSL.RAND_bytes(outbuf, ivLen); + InitCipher(ref _encryptCtx, outbuf, true); + outlength = length + ivLen; + OpenSSL.EVP_CipherUpdate(_encryptCtx, tempbuf, out outlength, buf, length); + outlength = length + ivLen; + Buffer.BlockCopy(tempbuf, 0, outbuf, ivLen, outlength); } else { - int outLen = length + ivLen; - byte[] cipherText = new byte[outLen]; - OpenSSL.EVP_CipherUpdate(_encryptCtx, cipherText, out outLen, buf, length); - byte[] result = new byte[outLen]; - Buffer.BlockCopy(cipherText, 0, result, 0, outLen); - return result; + outlength = length; + OpenSSL.EVP_CipherUpdate(_encryptCtx, outbuf, out outlength, buf, length); } - } - - public override byte[] Decrypt(byte[] buf, int length) + } + + public override void Decrypt(byte[] buf, int length, byte[] outbuf, out int outlength) { if (_decryptCtx == IntPtr.Zero) - { - byte[] iv = new byte[ivLen]; - Buffer.BlockCopy(buf, 0, iv, 0, ivLen); - InitCipher(ref _decryptCtx, iv, false); - int outLen = length + ivLen; - outLen -= ivLen; - byte[] cipherText = new byte[outLen]; - byte[] subset = new byte[length - ivLen]; - Buffer.BlockCopy(buf, ivLen, subset, 0, length - ivLen); - OpenSSL.EVP_CipherUpdate(_decryptCtx, cipherText, out outLen, subset, length - ivLen); - byte[] result = new byte[outLen]; - Buffer.BlockCopy(cipherText, 0, result, 0, outLen); - return result; + { + InitCipher(ref _decryptCtx, buf, false); + outlength = length - ivLen; + Buffer.BlockCopy(buf, ivLen, tempbuf, 0, length - ivLen); + OpenSSL.EVP_CipherUpdate(_decryptCtx, outbuf, out outlength, tempbuf, length - ivLen); } - else + else { - int outLen = length + ivLen; - byte[] cipherText = new byte[outLen]; - OpenSSL.EVP_CipherUpdate(_decryptCtx, cipherText, out outLen, buf, length); - byte[] result = new byte[outLen]; - Buffer.BlockCopy(cipherText, 0, result, 0, outLen); - return result; + outlength = length; + OpenSSL.EVP_CipherUpdate(_decryptCtx, outbuf, out outlength, buf, length); } } @@ -146,7 +129,7 @@ namespace shadowsocks_csharp.Encrypt #region IDisposable private bool _disposed; - public void Dispose() + public override void Dispose() { Dispose(true); GC.SuppressFinalize(this); diff --git a/shadowsocks-csharp/Encrypt/TableEncryptor.cs b/shadowsocks-csharp/Encrypt/TableEncryptor.cs index 47c2643b..dc087160 100644 --- a/shadowsocks-csharp/Encrypt/TableEncryptor.cs +++ b/shadowsocks-csharp/Encrypt/TableEncryptor.cs @@ -1,96 +1,102 @@ -using System; - -namespace shadowsocks_csharp.Encrypt -{ - public class TableEncryptor - : EncryptorBase - { - public TableEncryptor(string method, string password) - : base(method, password) - { - byte[] hash = GetPasswordHash(); - // TODO endian - ulong a = BitConverter.ToUInt64(hash, 0); - for (int i = 0; i < 256; i++) - { - _encryptTable[i] = (byte)i; - } - for (int i = 1; i < 1024; i++) - { - _encryptTable = MergeSort(_encryptTable, a, i); - } - for (int i = 0; i < 256; i++) - { - _decryptTable[_encryptTable[i]] = (byte)i; - } - } - - public override byte[] Encrypt(byte[] buf, int length) - { - byte[] result = new byte[length]; - for (int i = 0; i < length; i++) - { - result[i] = _encryptTable[buf[i]]; - } - return result; - } - - public override byte[] Decrypt(byte[] buf, int length) - { - byte[] result = new byte[length]; - for (int i = 0; i < length; i++) - { - result[i] = _decryptTable[buf[i]]; - } - return result; - } - - private readonly byte[] _encryptTable = new byte[256]; - private readonly byte[] _decryptTable = new byte[256]; - - private static long Compare(byte x, byte y, ulong a, int i) - { - return (long)(a % (ulong)(x + i)) - (long)(a % (ulong)(y + i)); - } - - private byte[] MergeSort(byte[] array, ulong a, int j) - { - if (array.Length == 1) - { - return array; - } - int middle = array.Length / 2; - byte[] left = new byte[middle]; - for (int i = 0; i < middle; i++) - { - left[i] = array[i]; - } - byte[] right = new byte[array.Length - middle]; - for (int i = 0; i < array.Length - middle; i++) - { - right[i] = array[i + middle]; - } - left = MergeSort(left, a, j); - right = MergeSort(right, a, j); - - int leftptr = 0; - int rightptr = 0; - - byte[] sorted = new byte[array.Length]; - for (int k = 0; k < array.Length; k++) - { - if (rightptr == right.Length || ((leftptr < left.Length) && (Compare(left[leftptr], right[rightptr], a, j) <= 0))) - { - sorted[k] = left[leftptr]; - leftptr++; - } - else if (leftptr == left.Length || ((rightptr < right.Length) && (Compare(right[rightptr], left[leftptr], a, j)) <= 0)) - { - sorted[k] = right[rightptr]; - rightptr++; - } - } - return sorted; - } - } -} +using System; + +namespace shadowsocks_csharp.Encrypt +{ + public class TableEncryptor + : EncryptorBase + { + public TableEncryptor(string method, string password) + : base(method, password) + { + byte[] hash = GetPasswordHash(); + // TODO endian + ulong a = BitConverter.ToUInt64(hash, 0); + for (int i = 0; i < 256; i++) + { + _encryptTable[i] = (byte)i; + } + for (int i = 1; i < 1024; i++) + { + _encryptTable = MergeSort(_encryptTable, a, i); + } + for (int i = 0; i < 256; i++) + { + _decryptTable[_encryptTable[i]] = (byte)i; + } + } + + 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++) + { + outbuf[i] = _encryptTable[buf[i]]; + } + outlength = length; + } + + + public override void Decrypt(byte[] buf, int length, byte[] outbuf, out int outlength) + { + byte[] result = new byte[length]; + for (int i = 0; i < length; i++) + { + outbuf[i] = _decryptTable[buf[i]]; + } + outlength = length; + } + + private readonly byte[] _encryptTable = new byte[256]; + private readonly byte[] _decryptTable = new byte[256]; + + private static long Compare(byte x, byte y, ulong a, int i) + { + return (long)(a % (ulong)(x + i)) - (long)(a % (ulong)(y + i)); + } + + private byte[] MergeSort(byte[] array, ulong a, int j) + { + if (array.Length == 1) + { + return array; + } + int middle = array.Length / 2; + byte[] left = new byte[middle]; + for (int i = 0; i < middle; i++) + { + left[i] = array[i]; + } + byte[] right = new byte[array.Length - middle]; + for (int i = 0; i < array.Length - middle; i++) + { + right[i] = array[i + middle]; + } + left = MergeSort(left, a, j); + right = MergeSort(right, a, j); + + int leftptr = 0; + int rightptr = 0; + + byte[] sorted = new byte[array.Length]; + for (int k = 0; k < array.Length; k++) + { + if (rightptr == right.Length || ((leftptr < left.Length) && (Compare(left[leftptr], right[rightptr], a, j) <= 0))) + { + sorted[k] = left[leftptr]; + leftptr++; + } + else if (leftptr == left.Length || ((rightptr < right.Length) && (Compare(right[rightptr], left[leftptr], a, j)) <= 0)) + { + sorted[k] = right[rightptr]; + rightptr++; + } + } + return sorted; + } + + + public override void Dispose() + { + } + } +} diff --git a/shadowsocks-csharp/Local.cs b/shadowsocks-csharp/Local.cs index 87c2fe50..e70911cd 100755 --- a/shadowsocks-csharp/Local.cs +++ b/shadowsocks-csharp/Local.cs @@ -100,11 +100,16 @@ namespace shadowsocks_csharp public Socket remote; public Socket connection; // Size of receive buffer. - public const int BufferSize = 1500; + public const int RecvSize = 16384; + public const int BufferSize = RecvSize + 32; // remote receive buffer - public byte[] remoteBuffer = new byte[BufferSize]; + public byte[] remoteRecvBuffer = new byte[RecvSize]; + // remote send buffer + public byte[] remoteSendBuffer = new byte[BufferSize]; // connection receive buffer - public byte[] connetionBuffer = new byte[BufferSize]; + public byte[] connetionRecvBuffer = new byte[RecvSize]; + // connection send buffer + public byte[] connetionSendBuffer = new byte[BufferSize]; // Received data string. public StringBuilder sb = new StringBuilder(); @@ -151,7 +156,7 @@ namespace shadowsocks_csharp Console.WriteLine(e.ToString()); } } - //encryptor.Dispose(); + ((IDisposable)encryptor).Dispose(); } private void connectCallback(IAsyncResult ar) @@ -177,7 +182,7 @@ namespace shadowsocks_csharp { try { - connection.BeginReceive(new byte[256], 0, 256, 0, + connection.BeginReceive(connetionRecvBuffer, 0, 256, 0, new AsyncCallback(handshakeReceiveCallback), null); } catch (Exception e) @@ -223,7 +228,7 @@ namespace shadowsocks_csharp // +----+-----+-------+------+----------+----------+ // Skip first 3 bytes // TODO validate - connection.BeginReceive(new byte[3], 0, 3, 0, + connection.BeginReceive(connetionRecvBuffer, 0, 3, 0, new AsyncCallback(handshakeReceive2Callback), null); } catch (Exception e) @@ -262,9 +267,9 @@ namespace shadowsocks_csharp try { connection.EndReceive(ar); - remote.BeginReceive(remoteBuffer, 0, BufferSize, 0, + remote.BeginReceive(remoteRecvBuffer, 0, RecvSize, 0, new AsyncCallback(pipeRemoteReceiveCallback), null); - connection.BeginReceive(connetionBuffer, 0, BufferSize, 0, + connection.BeginReceive(connetionRecvBuffer, 0, RecvSize, 0, new AsyncCallback(pipeConnectionReceiveCallback), null); } catch (Exception e) @@ -283,8 +288,9 @@ namespace shadowsocks_csharp if (bytesRead > 0) { - byte[] buf = encryptor.Decrypt(remoteBuffer, bytesRead); - connection.BeginSend(buf, 0, buf.Length, 0, new AsyncCallback(pipeConnectionSendCallback), null); + int bytesToSend; + encryptor.Decrypt(remoteRecvBuffer, bytesRead, remoteSendBuffer, out bytesToSend); + connection.BeginSend(remoteSendBuffer, 0, bytesToSend, 0, new AsyncCallback(pipeConnectionSendCallback), null); } else { @@ -308,8 +314,9 @@ namespace shadowsocks_csharp if (bytesRead > 0) { - byte[] buf = encryptor.Encrypt(connetionBuffer, bytesRead); - remote.BeginSend(buf, 0, buf.Length, 0, new AsyncCallback(pipeRemoteSendCallback), null); + int bytesToSend; + encryptor.Encrypt(connetionRecvBuffer, bytesRead, connetionSendBuffer, out bytesToSend); + remote.BeginSend(connetionSendBuffer, 0, bytesToSend, 0, new AsyncCallback(pipeRemoteSendCallback), null); } else { @@ -329,7 +336,7 @@ namespace shadowsocks_csharp try { remote.EndSend(ar); - connection.BeginReceive(this.connetionBuffer, 0, BufferSize, 0, + connection.BeginReceive(this.connetionRecvBuffer, 0, RecvSize, 0, new AsyncCallback(pipeConnectionReceiveCallback), null); } catch (Exception e) @@ -344,7 +351,7 @@ namespace shadowsocks_csharp try { connection.EndSend(ar); - remote.BeginReceive(this.remoteBuffer, 0, BufferSize, 0, + remote.BeginReceive(this.remoteRecvBuffer, 0, RecvSize, 0, new AsyncCallback(pipeRemoteReceiveCallback), null); } catch (Exception e)