Browse Source

Merge pull request #12 from canbingzt/master

refactoring encryptor
tags/2.3
clowwindy 10 years ago
parent
commit
d598d3e177
8 changed files with 422 additions and 9 deletions
  1. +29
    -0
      shadowsocks-csharp/Encrypt/EncryptorBase.cs
  2. +21
    -0
      shadowsocks-csharp/Encrypt/EncryptorFactory.cs
  3. +12
    -0
      shadowsocks-csharp/Encrypt/IEncryptor.cs
  4. +156
    -0
      shadowsocks-csharp/Encrypt/OpensslEncryptor.cs
  5. +81
    -0
      shadowsocks-csharp/Encrypt/RC4Encryptor.cs
  6. +96
    -0
      shadowsocks-csharp/Encrypt/TableEncryptor.cs
  7. +20
    -9
      shadowsocks-csharp/Local.cs
  8. +7
    -0
      shadowsocks-csharp/shadowsocks-csharp.csproj

+ 29
- 0
shadowsocks-csharp/Encrypt/EncryptorBase.cs View File

@@ -0,0 +1,29 @@
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);
}
}

+ 21
- 0
shadowsocks-csharp/Encrypt/EncryptorFactory.cs View File

@@ -0,0 +1,21 @@

namespace shadowsocks_csharp.Encrypt
{
public static class EncryptorFactory
{
public static IEncryptor GetEncryptor(string method, string password)
{
if (string.IsNullOrEmpty(method) || method.ToLowerInvariant() == "table")
{
return new TableEncryptor(method, password);
}

if (method.ToLowerInvariant() == "rc4")
{
return new Rc4Encryptor(method, password);
}

return new OpensslEncryptor(method, password);
}
}
}

+ 12
- 0
shadowsocks-csharp/Encrypt/IEncryptor.cs View File

@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace shadowsocks_csharp.Encrypt
{
public interface IEncryptor
{
byte[] Encrypt(byte[] buf, int length);
byte[] Decrypt(byte[] buf, int length);
}
}

+ 156
- 0
shadowsocks-csharp/Encrypt/OpensslEncryptor.cs View File

@@ -0,0 +1,156 @@
using OpenSSL.Core;
using OpenSSL.Crypto;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;

namespace shadowsocks_csharp.Encrypt
{
public class OpensslEncryptor
: EncryptorBase, IDisposable
{
public OpensslEncryptor(string method, string password)
: base(method, password)
{
InitKey(Method, Password);
}

public override byte[] Encrypt(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];
Buffer.BlockCopy(iv, 0, result, 0, ivLen);
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];
Buffer.BlockCopy(cipherText, 0, result, 0, outLen);
return result;
}
}

public override byte[] Decrypt(byte[] buf, int length)
{
if (_decryptCtx == IntPtr.Zero)
{
int ivLen = _cipher.IVLength;
byte[] iv = new byte[ivLen];
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];
Buffer.BlockCopy(buf, ivLen, subset, 0, length - ivLen);
Native.EVP_CipherUpdate(_decryptCtx, cipherText, out outLen, subset, length - ivLen);
byte[] result = new byte[outLen];
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];
Buffer.BlockCopy(cipherText, 0, result, 0, outLen);
return result;
}
}

private static readonly Dictionary<string, byte[]> CachedKeys = new Dictionary<string, byte[]>();
private static readonly Dictionary<string, Cipher> CachedCiphers = new Dictionary<string, Cipher>();
private byte[] _key;
private Cipher _cipher;
private IntPtr _encryptCtx;
private IntPtr _decryptCtx;

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 = 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 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, _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, _cipher.Handle, IntPtr.Zero, _key, iv, enc));
}

#region IDisposable
private bool _disposed;

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

~OpensslEncryptor()
{
Dispose(false);
}

protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{

}

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

_disposed = true;
}
}
#endregion
}
}

+ 81
- 0
shadowsocks-csharp/Encrypt/RC4Encryptor.cs View File

@@ -0,0 +1,81 @@

namespace shadowsocks_csharp.Encrypt
{
public class Rc4Encryptor
: EncryptorBase
{
public Rc4Encryptor(string method, string password)
: base(method, password)
{
byte[] hash = GetPasswordHash();
_encryptTable = EncryptInitalize(hash);
_decryptTable = EncryptInitalize(hash);
}

public override byte[] Encrypt(byte[] buf, int length)
{
return EncryptOutput(enc_ctx, _encryptTable, buf, length);
}

public override byte[] Decrypt(byte[] buf, int length)
{
return EncryptOutput(dec_ctx, _decryptTable, buf, length);
}

private readonly byte[] _encryptTable = new byte[256];
private readonly byte[] _decryptTable = new byte[256];

private Context enc_ctx = new Context();
private Context dec_ctx = new Context();

private byte[] EncryptOutput(Context ctx, byte[] s, byte[] data, int length)
{
byte[] result = new byte[length];
for (int n = 0; n < length; n++)
{
byte b = data[n];

ctx.Index1 = (ctx.Index1 + 1) & 255;
ctx.Index2 = (ctx.Index2 + s[ctx.Index1]) & 255;

Swap(s, ctx.Index1, ctx.Index2);

result[n] = (byte)(b ^ s[(s[ctx.Index1] + s[ctx.Index2]) & 255]);
}
return result;
}

private byte[] EncryptInitalize(byte[] key)
{
var s = new byte[256];

for (int i = 0; i < 256; i++)
{
s[i] = (byte)i;
}

for (int i = 0, j = 0; i < 256; i++)
{
j = (j + key[i % key.Length] + s[i]) & 255;

Swap(s, i, j);
}

return s;
}

private static void Swap(byte[] s, int i, int j)
{
byte c = s[i];

s[i] = s[j];
s[j] = c;
}

class Context
{
public int Index1;
public int Index2;
}
}
}

+ 96
- 0
shadowsocks-csharp/Encrypt/TableEncryptor.cs View File

@@ -0,0 +1,96 @@
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;
}
}
}

+ 20
- 9
shadowsocks-csharp/Local.cs View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Net;
using shadowsocks_csharp.Encrypt;
namespace shadowsocks_csharp
{
@@ -11,12 +12,12 @@ namespace shadowsocks_csharp
class Local
{
private Config config;
private Encryptor encryptor;
//private Encryptor encryptor;
Socket listener;
public Local(Config config)
{
this.config = config;
this.encryptor = new Encryptor(config.method, config.password);
//this.encryptor = new Encryptor(config.method, config.password);
}
public void Start()
@@ -53,6 +54,11 @@ namespace shadowsocks_csharp
// Get the socket that handles the client request.
Socket listener = (Socket)ar.AsyncState;
if (!listener.Connected)
{
return;
}
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
@@ -62,11 +68,15 @@ namespace shadowsocks_csharp
// Create the state object.
Handler handler = new Handler();
handler.connection = conn;
if (encryptor.method == "table") {
handler.encryptor = encryptor;
} else {
handler.encryptor = new Encryptor(config.method, config.password);
}
//if (encryptor.method == "table")
//{
// handler.encryptor = encryptor;
//}
//else
//{
// handler.encryptor = new Encryptor(config.method, config.password);
//}
handler.encryptor = EncryptorFactory.GetEncryptor(config.method, config.password);
handler.config = config;
handler.Start();
@@ -83,7 +93,8 @@ namespace shadowsocks_csharp
class Handler
{
public Encryptor encryptor;
//public Encryptor encryptor;
public IEncryptor encryptor;
public Config config;
// Client socket.
public Socket remote;
@@ -140,7 +151,7 @@ namespace shadowsocks_csharp
Console.WriteLine(e.ToString());
}
}
encryptor.Dispose();
//encryptor.Dispose();
}
private void connectCallback(IAsyncResult ar)


+ 7
- 0
shadowsocks-csharp/shadowsocks-csharp.csproj View File

@@ -46,6 +46,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
<UseVSHostingProcess>true</UseVSHostingProcess>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
@@ -83,6 +84,12 @@
<Reference Include="System.Windows.Forms" />
</ItemGroup>
<ItemGroup>
<Compile Include="Encrypt\EncryptorBase.cs" />
<Compile Include="Encrypt\EncryptorFactory.cs" />
<Compile Include="Encrypt\OpensslEncryptor.cs" />
<Compile Include="Encrypt\Rc4Encryptor.cs" />
<Compile Include="Encrypt\TableEncryptor.cs" />
<Compile Include="Encrypt\IEncryptor.cs" />
<Compile Include="RC4.cs" />
<Compile Include="Config.cs" />
<Compile Include="Encryptor.cs" />


Loading…
Cancel
Save