@@ -6,13 +6,20 @@ EndProject | |||
Global | |||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | |||
Debug|Any CPU = Debug|Any CPU | |||
Debug|x86 = Debug|x86 | |||
Release|Any CPU = Release|Any CPU | |||
Release|x86 = Release|x86 | |||
EndGlobalSection | |||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | |||
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Debug|x86.ActiveCfg = Debug|x86 | |||
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Debug|x86.Build.0 = Debug|x86 | |||
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Debug|x86.Deploy.0 = Debug|x86 | |||
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Release|Any CPU.Build.0 = Release|Any CPU | |||
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Release|x86.ActiveCfg = Release|x86 | |||
{8C02D2F7-7CDB-4D55-9F25-CD03EF4AA062}.Release|x86.Build.0 = Release|x86 | |||
EndGlobalSection | |||
GlobalSection(SolutionProperties) = preSolution | |||
HideSolutionNode = FALSE | |||
@@ -2,18 +2,54 @@ | |||
using System.Collections.Generic; | |||
using System.Text; | |||
using System.Security.Cryptography; | |||
using OpenSSL.Core; | |||
using OpenSSL.Crypto; | |||
using System.Runtime.InteropServices; | |||
namespace shadowsocks_csharp | |||
{ | |||
class Encryptor | |||
class Encryptor : IDisposable | |||
{ | |||
public const int TYPE_TABLE = 1; | |||
public const int TYPE_RC4 = 2; | |||
public static string[] encryption_names = new string[] { | |||
"table", | |||
"rc4", | |||
"aes-256-cfb", | |||
"aes-192-cfb", | |||
"aes-128-cfb", | |||
"bf-cfb" | |||
}; | |||
public byte[] encryptTable = new byte[256]; | |||
public byte[] decryptTable = new byte[256]; | |||
public int method = TYPE_TABLE; | |||
public RC4 rc4 = null; | |||
public string method = "table"; | |||
public string password; | |||
public byte[] key; | |||
private RC4 rc4 = null; | |||
private Cipher cipher = null; | |||
private IntPtr encryptCTX; | |||
private IntPtr decryptCTX; | |||
private static Dictionary<string, byte[]> cachedKeys = new Dictionary<string, byte[]>(); | |||
private static Dictionary<string, Cipher> cachedCiphers = new Dictionary<string, Cipher>(); | |||
public void Dispose() | |||
{ | |||
if (encryptCTX != IntPtr.Zero) | |||
{ | |||
Native.EVP_CIPHER_CTX_cleanup(encryptCTX); | |||
Native.OPENSSL_free(encryptCTX); | |||
encryptCTX = IntPtr.Zero; | |||
} | |||
if (decryptCTX != IntPtr.Zero) | |||
{ | |||
Native.EVP_CIPHER_CTX_cleanup(decryptCTX); | |||
Native.OPENSSL_free(decryptCTX); | |||
decryptCTX = IntPtr.Zero; | |||
} | |||
} | |||
~Encryptor() { | |||
Dispose(); | |||
} | |||
private long compare(byte x, byte y, ulong a, int i) | |||
{ | |||
@@ -64,16 +100,21 @@ namespace shadowsocks_csharp | |||
byte[] inputBytes = System.Text.Encoding.UTF8.GetBytes(password); | |||
byte[] hash = md5.ComputeHash(inputBytes); | |||
encryptCTX = IntPtr.Zero; | |||
decryptCTX = IntPtr.Zero; | |||
this.method = method; | |||
this.password = password; | |||
if (method != null && method.ToLowerInvariant().Equals("rc4")) { | |||
Console.WriteLine("init rc4"); | |||
this.method = TYPE_RC4; | |||
rc4 = new RC4(); | |||
encryptTable = rc4.EncryptInitalize(hash); | |||
decryptTable = rc4.EncryptInitalize(hash); | |||
} else { | |||
} | |||
else if (method == "table" || method == "" || method == null) | |||
{ | |||
Console.WriteLine("init table"); | |||
this.method = TYPE_TABLE; | |||
// TODO endian | |||
var a = BitConverter.ToUInt64(hash, 0); | |||
@@ -90,32 +131,135 @@ namespace shadowsocks_csharp | |||
decryptTable[encryptTable[i]] = (byte)i; | |||
} | |||
} | |||
else | |||
{ | |||
initKey(password, method); | |||
} | |||
} | |||
private void initCipher(ref IntPtr ctx, byte[] iv, bool isCipher) | |||
{ | |||
ctx = Native.OPENSSL_malloc(Marshal.SizeOf(typeof(CipherContext.EVP_CIPHER_CTX))); | |||
int enc = isCipher ? 1 : 0; | |||
Native.EVP_CIPHER_CTX_init(ctx); | |||
Native.ExpectSuccess(Native.EVP_CipherInit_ex( | |||
ctx, this.cipher.Handle, IntPtr.Zero, null, null, enc)); | |||
Native.ExpectSuccess(Native.EVP_CIPHER_CTX_set_key_length(ctx, key.Length)); | |||
Native.ExpectSuccess(Native.EVP_CIPHER_CTX_set_padding(ctx, 1)); | |||
Native.ExpectSuccess(Native.EVP_CipherInit_ex( | |||
ctx, this.cipher.Handle, IntPtr.Zero, key, iv, enc)); | |||
} | |||
private void initKey(string password, string method) | |||
{ | |||
string k = method + ":" + password; | |||
if (cachedKeys.ContainsKey(k)) | |||
{ | |||
key = cachedKeys[k]; | |||
cipher = cachedCiphers[k]; | |||
return; | |||
} | |||
cipher = Cipher.CreateByName(method); | |||
if (cipher == null) | |||
{ | |||
throw new NullReferenceException(); | |||
} | |||
byte[] passbuf = System.Text.Encoding.UTF8.GetBytes(password); ; | |||
key = new byte[cipher.KeyLength]; | |||
byte[] iv = new byte[cipher.IVLength]; | |||
Native.EVP_BytesToKey(cipher.Handle, MessageDigest.MD5.Handle, null, passbuf, passbuf.Length, 1, key, iv); | |||
cachedKeys[k] = key; | |||
cachedCiphers[k] = cipher; | |||
} | |||
private byte[] sslEncrypt(byte[] buf, int length) | |||
{ | |||
if (encryptCTX == IntPtr.Zero) | |||
{ | |||
int ivLen = cipher.IVLength; | |||
byte[] iv = new byte[ivLen]; | |||
Native.RAND_bytes(iv, iv.Length); | |||
initCipher(ref encryptCTX, iv, true); | |||
int outLen = length + cipher.BlockSize; | |||
byte[] cipherText = new byte[outLen]; | |||
Native.EVP_CipherUpdate(encryptCTX, cipherText, out outLen, buf, length); | |||
byte[] result = new byte[outLen + ivLen]; | |||
System.Buffer.BlockCopy(iv, 0, result, 0, ivLen); | |||
System.Buffer.BlockCopy(cipherText, 0, result, ivLen, outLen); | |||
return result; | |||
} | |||
else | |||
{ | |||
int outLen = length + cipher.BlockSize; | |||
byte[] cipherText = new byte[outLen]; | |||
Native.EVP_CipherUpdate(encryptCTX, cipherText, out outLen, buf, length); | |||
byte[] result = new byte[outLen]; | |||
System.Buffer.BlockCopy(cipherText, 0, result, 0, outLen); | |||
return result; | |||
} | |||
} | |||
private byte[] sslDecrypt(byte[] buf, int length) | |||
{ | |||
if (decryptCTX == IntPtr.Zero) | |||
{ | |||
int ivLen = cipher.IVLength; | |||
byte[] iv = new byte[ivLen]; | |||
System.Buffer.BlockCopy(buf, 0, iv, 0, ivLen); | |||
initCipher(ref decryptCTX, iv, false); | |||
int outLen = length + cipher.BlockSize; | |||
outLen -= ivLen; | |||
byte[] cipherText = new byte[outLen]; | |||
byte[] subset = new byte[length - ivLen]; | |||
System.Buffer.BlockCopy(buf, ivLen, subset, 0, length - ivLen); | |||
Native.EVP_CipherUpdate(decryptCTX, cipherText, out outLen, subset, length - ivLen); | |||
byte[] result = new byte[outLen]; | |||
System.Buffer.BlockCopy(cipherText, 0, result, 0, outLen); | |||
return result; | |||
} | |||
else | |||
{ | |||
int outLen = length + cipher.BlockSize; | |||
byte[] cipherText = new byte[outLen]; | |||
Native.EVP_CipherUpdate(decryptCTX, cipherText, out outLen, buf, length); | |||
byte[] result = new byte[outLen]; | |||
System.Buffer.BlockCopy(cipherText, 0, result, 0, outLen); | |||
return result; | |||
} | |||
} | |||
public void Encrypt(byte[] buf, int length) | |||
public byte[] Encrypt(byte[] buf, int length) | |||
{ | |||
switch (method) | |||
{ | |||
case TYPE_TABLE: | |||
case "table": | |||
for (int i = 0; i < length; i++) | |||
buf[i] = encryptTable[buf[i]]; | |||
return buf; | |||
break; | |||
case TYPE_RC4: | |||
case "rc4": | |||
rc4.Encrypt(encryptTable, buf, length); | |||
return buf; | |||
break; | |||
default: | |||
return sslEncrypt(buf, length); | |||
} | |||
} | |||
public void Decrypt(byte[] buf, int length) | |||
public byte[] Decrypt(byte[] buf, int length) | |||
{ | |||
switch (method) | |||
{ | |||
case TYPE_TABLE: | |||
case "table": | |||
for (int i = 0; i < length; i++) | |||
buf[i] = decryptTable[buf[i]]; | |||
return buf; | |||
break; | |||
case TYPE_RC4: | |||
case "rc4": | |||
rc4.Decrypt(decryptTable, buf, length); | |||
return buf; | |||
break; | |||
default: | |||
return sslDecrypt(buf, length); | |||
} | |||
} | |||
} | |||
@@ -81,16 +81,16 @@ | |||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); | |||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); | |||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); | |||
this.tableLayoutPanel1.Size = new System.Drawing.Size(203, 131); | |||
this.tableLayoutPanel1.Size = new System.Drawing.Size(196, 131); | |||
this.tableLayoutPanel1.TabIndex = 0; | |||
// | |||
// label5 | |||
// | |||
this.label5.Anchor = System.Windows.Forms.AnchorStyles.Right; | |||
this.label5.AutoSize = true; | |||
this.label5.Location = new System.Drawing.Point(12, 110); | |||
this.label5.Location = new System.Drawing.Point(11, 111); | |||
this.label5.Name = "label5"; | |||
this.label5.Size = new System.Drawing.Size(58, 15); | |||
this.label5.Size = new System.Drawing.Size(52, 13); | |||
this.label5.TabIndex = 8; | |||
this.label5.Text = "Encryptor"; | |||
// | |||
@@ -98,9 +98,9 @@ | |||
// | |||
this.label1.Anchor = System.Windows.Forms.AnchorStyles.Right; | |||
this.label1.AutoSize = true; | |||
this.label1.Location = new System.Drawing.Point(14, 5); | |||
this.label1.Location = new System.Drawing.Point(12, 6); | |||
this.label1.Name = "label1"; | |||
this.label1.Size = new System.Drawing.Size(56, 15); | |||
this.label1.Size = new System.Drawing.Size(51, 13); | |||
this.label1.TabIndex = 0; | |||
this.label1.Text = "Server IP"; | |||
// | |||
@@ -108,9 +108,9 @@ | |||
// | |||
this.label2.Anchor = System.Windows.Forms.AnchorStyles.Right; | |||
this.label2.AutoSize = true; | |||
this.label2.Location = new System.Drawing.Point(3, 31); | |||
this.label2.Location = new System.Drawing.Point(3, 32); | |||
this.label2.Name = "label2"; | |||
this.label2.Size = new System.Drawing.Size(67, 15); | |||
this.label2.Size = new System.Drawing.Size(60, 13); | |||
this.label2.TabIndex = 1; | |||
this.label2.Text = "Server Port"; | |||
// | |||
@@ -122,8 +122,14 @@ | |||
this.comboBox1.ItemHeight = 13; | |||
this.comboBox1.Items.AddRange(new object[] { | |||
"table", | |||
"aes-256-cfb", | |||
"aes-192-cfb", | |||
"aes-128-cfb", | |||
"bf-cfb", | |||
"cast5-cfb", | |||
"des-cfb", | |||
"rc4"}); | |||
this.comboBox1.Location = new System.Drawing.Point(76, 107); | |||
this.comboBox1.Location = new System.Drawing.Point(69, 107); | |||
this.comboBox1.Name = "comboBox1"; | |||
this.comboBox1.Size = new System.Drawing.Size(124, 21); | |||
this.comboBox1.TabIndex = 9; | |||
@@ -132,9 +138,9 @@ | |||
// | |||
this.label3.Anchor = System.Windows.Forms.AnchorStyles.Right; | |||
this.label3.AutoSize = true; | |||
this.label3.Location = new System.Drawing.Point(9, 57); | |||
this.label3.Location = new System.Drawing.Point(10, 58); | |||
this.label3.Name = "label3"; | |||
this.label3.Size = new System.Drawing.Size(61, 15); | |||
this.label3.Size = new System.Drawing.Size(53, 13); | |||
this.label3.TabIndex = 2; | |||
this.label3.Text = "Password"; | |||
// | |||
@@ -142,16 +148,16 @@ | |||
// | |||
this.label4.Anchor = System.Windows.Forms.AnchorStyles.Right; | |||
this.label4.AutoSize = true; | |||
this.label4.Location = new System.Drawing.Point(8, 83); | |||
this.label4.Location = new System.Drawing.Point(8, 84); | |||
this.label4.Name = "label4"; | |||
this.label4.Size = new System.Drawing.Size(62, 15); | |||
this.label4.Size = new System.Drawing.Size(55, 13); | |||
this.label4.TabIndex = 3; | |||
this.label4.Text = "Proxy Port"; | |||
// | |||
// textBox1 | |||
// | |||
this.textBox1.Anchor = System.Windows.Forms.AnchorStyles.Left; | |||
this.textBox1.Location = new System.Drawing.Point(76, 3); | |||
this.textBox1.Location = new System.Drawing.Point(69, 3); | |||
this.textBox1.Name = "textBox1"; | |||
this.textBox1.Size = new System.Drawing.Size(124, 20); | |||
this.textBox1.TabIndex = 4; | |||
@@ -160,7 +166,7 @@ | |||
// textBox2 | |||
// | |||
this.textBox2.Anchor = System.Windows.Forms.AnchorStyles.Left; | |||
this.textBox2.Location = new System.Drawing.Point(76, 29); | |||
this.textBox2.Location = new System.Drawing.Point(69, 29); | |||
this.textBox2.Name = "textBox2"; | |||
this.textBox2.Size = new System.Drawing.Size(124, 20); | |||
this.textBox2.TabIndex = 5; | |||
@@ -169,7 +175,7 @@ | |||
// textBox3 | |||
// | |||
this.textBox3.Anchor = System.Windows.Forms.AnchorStyles.Left; | |||
this.textBox3.Location = new System.Drawing.Point(76, 55); | |||
this.textBox3.Location = new System.Drawing.Point(69, 55); | |||
this.textBox3.Name = "textBox3"; | |||
this.textBox3.Size = new System.Drawing.Size(124, 20); | |||
this.textBox3.TabIndex = 6; | |||
@@ -178,7 +184,7 @@ | |||
// textBox4 | |||
// | |||
this.textBox4.Anchor = System.Windows.Forms.AnchorStyles.Left; | |||
this.textBox4.Location = new System.Drawing.Point(76, 81); | |||
this.textBox4.Location = new System.Drawing.Point(69, 81); | |||
this.textBox4.Name = "textBox4"; | |||
this.textBox4.Size = new System.Drawing.Size(124, 20); | |||
this.textBox4.TabIndex = 7; | |||
@@ -201,32 +207,32 @@ | |||
this.QuitItem}); | |||
this.contextMenuStrip1.Name = "contextMenuStrip1"; | |||
this.contextMenuStrip1.RenderMode = System.Windows.Forms.ToolStripRenderMode.System; | |||
this.contextMenuStrip1.Size = new System.Drawing.Size(123, 82); | |||
this.contextMenuStrip1.Size = new System.Drawing.Size(112, 76); | |||
// | |||
// ConfigItem | |||
// | |||
this.ConfigItem.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold); | |||
this.ConfigItem.Name = "ConfigItem"; | |||
this.ConfigItem.Size = new System.Drawing.Size(122, 24); | |||
this.ConfigItem.Size = new System.Drawing.Size(111, 22); | |||
this.ConfigItem.Text = "Config"; | |||
this.ConfigItem.Click += new System.EventHandler(this.Config_Click); | |||
// | |||
// aboutToolStripMenuItem | |||
// | |||
this.aboutToolStripMenuItem.Name = "aboutToolStripMenuItem"; | |||
this.aboutToolStripMenuItem.Size = new System.Drawing.Size(122, 24); | |||
this.aboutToolStripMenuItem.Size = new System.Drawing.Size(111, 22); | |||
this.aboutToolStripMenuItem.Text = "About"; | |||
this.aboutToolStripMenuItem.Click += new System.EventHandler(this.aboutToolStripMenuItem_Click); | |||
// | |||
// toolStripSeparator2 | |||
// | |||
this.toolStripSeparator2.Name = "toolStripSeparator2"; | |||
this.toolStripSeparator2.Size = new System.Drawing.Size(119, 6); | |||
this.toolStripSeparator2.Size = new System.Drawing.Size(108, 6); | |||
// | |||
// QuitItem | |||
// | |||
this.QuitItem.Name = "QuitItem"; | |||
this.QuitItem.Size = new System.Drawing.Size(122, 24); | |||
this.QuitItem.Size = new System.Drawing.Size(111, 22); | |||
this.QuitItem.Text = "Quit"; | |||
this.QuitItem.Click += new System.EventHandler(this.Quit_Click); | |||
// | |||
@@ -90,9 +90,9 @@ namespace shadowsocks_csharp | |||
{ | |||
MessageBox.Show("there is format problem"); | |||
} | |||
catch (Exception) | |||
catch (Exception ex) | |||
{ | |||
MessageBox.Show("there is some problem with parameters"); | |||
MessageBox.Show(ex.ToString()); | |||
} | |||
} | |||
@@ -62,7 +62,7 @@ namespace shadowsocks_csharp | |||
// Create the state object. | |||
Handler handler = new Handler(); | |||
handler.connection = conn; | |||
if (encryptor.method == Encryptor.TYPE_TABLE) { | |||
if (encryptor.method == "table") { | |||
handler.encryptor = encryptor; | |||
} else { | |||
handler.encryptor = new Encryptor(config.method, config.password); | |||
@@ -128,11 +128,12 @@ namespace shadowsocks_csharp | |||
public void Close() | |||
{ | |||
connection.Close(); | |||
connection.Shutdown(SocketShutdown.Send); | |||
if (remote != null) | |||
{ | |||
remote.Close(); | |||
remote.Shutdown(SocketShutdown.Send); | |||
} | |||
encryptor.Dispose(); | |||
} | |||
private void connectCallback(IAsyncResult ar) | |||
@@ -264,8 +265,8 @@ namespace shadowsocks_csharp | |||
if (bytesRead > 0) | |||
{ | |||
encryptor.Decrypt(remoteBuffer, bytesRead); | |||
connection.BeginSend(remoteBuffer, 0, bytesRead, 0, new AsyncCallback(pipeConnectionSendCallback), null); | |||
byte[] buf = encryptor.Decrypt(remoteBuffer, bytesRead); | |||
connection.BeginSend(buf, 0, buf.Length, 0, new AsyncCallback(pipeConnectionSendCallback), null); | |||
} | |||
else | |||
{ | |||
@@ -289,8 +290,8 @@ namespace shadowsocks_csharp | |||
if (bytesRead > 0) | |||
{ | |||
encryptor.Encrypt(connetionBuffer, bytesRead); | |||
remote.BeginSend(connetionBuffer, 0, bytesRead, 0, new AsyncCallback(pipeRemoteSendCallback), null); | |||
byte[] buf = encryptor.Encrypt(connetionBuffer, bytesRead); | |||
remote.BeginSend(buf, 0, buf.Length, 0, new AsyncCallback(pipeRemoteSendCallback), null); | |||
} | |||
else | |||
{ | |||
@@ -56,7 +56,28 @@ | |||
<WarningLevel>4</WarningLevel> | |||
<Prefer32Bit>false</Prefer32Bit> | |||
</PropertyGroup> | |||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'"> | |||
<DebugSymbols>true</DebugSymbols> | |||
<OutputPath>bin\x86\Debug\</OutputPath> | |||
<DefineConstants>TRACE;DEBUG;SIMPLE_JSON_NO_LINQ_EXPRESSION</DefineConstants> | |||
<DebugType>full</DebugType> | |||
<PlatformTarget>x86</PlatformTarget> | |||
<ErrorReport>prompt</ErrorReport> | |||
<CodeAnalysisRuleSet>ManagedMinimumRules.ruleset</CodeAnalysisRuleSet> | |||
</PropertyGroup> | |||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'"> | |||
<OutputPath>bin\x86\Release\</OutputPath> | |||
<DefineConstants>TRACE;SIMPLE_JSON_NO_LINQ_EXPRESSION</DefineConstants> | |||
<Optimize>true</Optimize> | |||
<DebugType>pdbonly</DebugType> | |||
<PlatformTarget>x86</PlatformTarget> | |||
<ErrorReport>prompt</ErrorReport> | |||
<CodeAnalysisRuleSet>ManagedMinimumRules.ruleset</CodeAnalysisRuleSet> | |||
</PropertyGroup> | |||
<ItemGroup> | |||
<Reference Include="ManagedOpenSsl"> | |||
<HintPath>..\openssl\openssl-net-0.5\ManagedOpenSsl.dll</HintPath> | |||
</Reference> | |||
<Reference Include="System" /> | |||
<Reference Include="System.Drawing" /> | |||
<Reference Include="System.Windows.Forms" /> | |||