@@ -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(); | |||||
} | |||||
} |
@@ -4,9 +4,9 @@ using System.Text; | |||||
namespace shadowsocks_csharp.Encrypt | 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); | |||||
} | } | ||||
} | } |
@@ -26,59 +26,42 @@ namespace shadowsocks_csharp.Encrypt | |||||
: base(method, password) | : base(method, password) | ||||
{ | { | ||||
InitKey(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) | 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 | 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) | 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 | #region IDisposable | ||||
private bool _disposed; | private bool _disposed; | ||||
public void Dispose() | |||||
public override void Dispose() | |||||
{ | { | ||||
Dispose(true); | Dispose(true); | ||||
GC.SuppressFinalize(this); | GC.SuppressFinalize(this); | ||||
@@ -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() | |||||
{ | |||||
} | |||||
} | |||||
} |
@@ -100,11 +100,16 @@ namespace shadowsocks_csharp | |||||
public Socket remote; | public Socket remote; | ||||
public Socket connection; | public Socket connection; | ||||
// Size of receive buffer. | // Size of receive buffer. | ||||
public const int BufferSize = 1500; | |||||
public const int RecvSize = 16384; | |||||
public const int BufferSize = RecvSize + 32; | |||||
// remote receive buffer | // 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 | // 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. | // Received data string. | ||||
public StringBuilder sb = new StringBuilder(); | public StringBuilder sb = new StringBuilder(); | ||||
@@ -151,7 +156,7 @@ namespace shadowsocks_csharp | |||||
Console.WriteLine(e.ToString()); | Console.WriteLine(e.ToString()); | ||||
} | } | ||||
} | } | ||||
//encryptor.Dispose(); | |||||
((IDisposable)encryptor).Dispose(); | |||||
} | } | ||||
private void connectCallback(IAsyncResult ar) | private void connectCallback(IAsyncResult ar) | ||||
@@ -177,7 +182,7 @@ namespace shadowsocks_csharp | |||||
{ | { | ||||
try | try | ||||
{ | { | ||||
connection.BeginReceive(new byte[256], 0, 256, 0, | |||||
connection.BeginReceive(connetionRecvBuffer, 0, 256, 0, | |||||
new AsyncCallback(handshakeReceiveCallback), null); | new AsyncCallback(handshakeReceiveCallback), null); | ||||
} | } | ||||
catch (Exception e) | catch (Exception e) | ||||
@@ -223,7 +228,7 @@ namespace shadowsocks_csharp | |||||
// +----+-----+-------+------+----------+----------+ | // +----+-----+-------+------+----------+----------+ | ||||
// Skip first 3 bytes | // Skip first 3 bytes | ||||
// TODO validate | // TODO validate | ||||
connection.BeginReceive(new byte[3], 0, 3, 0, | |||||
connection.BeginReceive(connetionRecvBuffer, 0, 3, 0, | |||||
new AsyncCallback(handshakeReceive2Callback), null); | new AsyncCallback(handshakeReceive2Callback), null); | ||||
} | } | ||||
catch (Exception e) | catch (Exception e) | ||||
@@ -262,9 +267,9 @@ namespace shadowsocks_csharp | |||||
try | try | ||||
{ | { | ||||
connection.EndReceive(ar); | connection.EndReceive(ar); | ||||
remote.BeginReceive(remoteBuffer, 0, BufferSize, 0, | |||||
remote.BeginReceive(remoteRecvBuffer, 0, RecvSize, 0, | |||||
new AsyncCallback(pipeRemoteReceiveCallback), null); | new AsyncCallback(pipeRemoteReceiveCallback), null); | ||||
connection.BeginReceive(connetionBuffer, 0, BufferSize, 0, | |||||
connection.BeginReceive(connetionRecvBuffer, 0, RecvSize, 0, | |||||
new AsyncCallback(pipeConnectionReceiveCallback), null); | new AsyncCallback(pipeConnectionReceiveCallback), null); | ||||
} | } | ||||
catch (Exception e) | catch (Exception e) | ||||
@@ -283,8 +288,9 @@ namespace shadowsocks_csharp | |||||
if (bytesRead > 0) | 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 | else | ||||
{ | { | ||||
@@ -308,8 +314,9 @@ namespace shadowsocks_csharp | |||||
if (bytesRead > 0) | 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 | else | ||||
{ | { | ||||
@@ -329,7 +336,7 @@ namespace shadowsocks_csharp | |||||
try | try | ||||
{ | { | ||||
remote.EndSend(ar); | remote.EndSend(ar); | ||||
connection.BeginReceive(this.connetionBuffer, 0, BufferSize, 0, | |||||
connection.BeginReceive(this.connetionRecvBuffer, 0, RecvSize, 0, | |||||
new AsyncCallback(pipeConnectionReceiveCallback), null); | new AsyncCallback(pipeConnectionReceiveCallback), null); | ||||
} | } | ||||
catch (Exception e) | catch (Exception e) | ||||
@@ -344,7 +351,7 @@ namespace shadowsocks_csharp | |||||
try | try | ||||
{ | { | ||||
connection.EndSend(ar); | connection.EndSend(ar); | ||||
remote.BeginReceive(this.remoteBuffer, 0, BufferSize, 0, | |||||
remote.BeginReceive(this.remoteRecvBuffer, 0, RecvSize, 0, | |||||
new AsyncCallback(pipeRemoteReceiveCallback), null); | new AsyncCallback(pipeRemoteReceiveCallback), null); | ||||
} | } | ||||
catch (Exception e) | catch (Exception e) | ||||