|
|
@@ -27,12 +27,12 @@ namespace Shadowsocks.Encrypt |
|
|
|
private int _cipher;
|
|
|
|
private int[] _cipherInfo;
|
|
|
|
private byte[] _key;
|
|
|
|
private byte[] _encryptCtx;
|
|
|
|
private byte[] _decryptCtx;
|
|
|
|
private IntPtr _encryptCtx = IntPtr.Zero;
|
|
|
|
private IntPtr _decryptCtx = IntPtr.Zero;
|
|
|
|
private byte[] _encryptIV;
|
|
|
|
private byte[] _decryptIV;
|
|
|
|
private int _encryptIVOffset;
|
|
|
|
private int _decryptIVOffset;
|
|
|
|
private byte[] _encryptIVOffset;
|
|
|
|
private byte[] _decryptIVOffset;
|
|
|
|
private string _method;
|
|
|
|
private int keyLen;
|
|
|
|
private int ivLen;
|
|
|
@@ -100,63 +100,65 @@ namespace Shadowsocks.Encrypt |
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void InitCipher(ref byte[] ctx, byte[] iv, bool isCipher)
|
|
|
|
private void InitCipher(ref IntPtr ctx, byte[] iv, bool isCipher)
|
|
|
|
{
|
|
|
|
ctx = new byte[_cipherInfo[3]];
|
|
|
|
lock (ctx)
|
|
|
|
ctx = Marshal.AllocHGlobal(_cipherInfo[3]);
|
|
|
|
byte[] realkey;
|
|
|
|
if (_method == "rc4-md5")
|
|
|
|
{
|
|
|
|
byte[] realkey;
|
|
|
|
if (_method == "rc4-md5")
|
|
|
|
byte[] temp = new byte[keyLen + ivLen];
|
|
|
|
realkey = new byte[keyLen];
|
|
|
|
Array.Copy(_key, 0, temp, 0, keyLen);
|
|
|
|
Array.Copy(iv, 0, temp, keyLen, ivLen);
|
|
|
|
realkey = MD5.Create().ComputeHash(temp);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
realkey = _key;
|
|
|
|
}
|
|
|
|
if (_cipher == CIPHER_AES)
|
|
|
|
{
|
|
|
|
PolarSSL.aes_init(ctx);
|
|
|
|
// PolarSSL takes key length by bit
|
|
|
|
// since we'll use CFB mode, here we both do enc, not dec
|
|
|
|
PolarSSL.aes_setkey_enc(ctx, realkey, keyLen * 8);
|
|
|
|
if (isCipher)
|
|
|
|
{
|
|
|
|
byte[] temp = new byte[keyLen + ivLen];
|
|
|
|
realkey = new byte[keyLen];
|
|
|
|
Array.Copy(_key, 0, temp, 0, keyLen);
|
|
|
|
Array.Copy(iv, 0, temp, keyLen, ivLen);
|
|
|
|
realkey = MD5.Create().ComputeHash(temp);
|
|
|
|
_encryptIV = new byte[ivLen];
|
|
|
|
_encryptIVOffset = new byte[8];
|
|
|
|
Array.Copy(iv, _encryptIV, ivLen);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
realkey = _key;
|
|
|
|
}
|
|
|
|
if (_cipher == CIPHER_AES)
|
|
|
|
{
|
|
|
|
PolarSSL.aes_init(ctx);
|
|
|
|
// PolarSSL takes key length by bit
|
|
|
|
// since we'll use CFB mode, here we both do enc, not dec
|
|
|
|
PolarSSL.aes_setkey_enc(ctx, realkey, keyLen * 8);
|
|
|
|
if (isCipher)
|
|
|
|
{
|
|
|
|
_encryptIV = new byte[ivLen];
|
|
|
|
Array.Copy(iv, _encryptIV, ivLen);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_decryptIV = new byte[ivLen];
|
|
|
|
Array.Copy(iv, _decryptIV, ivLen);
|
|
|
|
}
|
|
|
|
_decryptIV = new byte[ivLen];
|
|
|
|
_decryptIVOffset = new byte[8];
|
|
|
|
Array.Copy(iv, _decryptIV, ivLen);
|
|
|
|
}
|
|
|
|
else if (_cipher == CIPHER_BF)
|
|
|
|
}
|
|
|
|
else if (_cipher == CIPHER_BF)
|
|
|
|
{
|
|
|
|
PolarSSL.blowfish_init(ctx);
|
|
|
|
// PolarSSL takes key length by bit
|
|
|
|
PolarSSL.blowfish_setkey(ctx, realkey, keyLen * 8);
|
|
|
|
if (isCipher)
|
|
|
|
{
|
|
|
|
PolarSSL.blowfish_init(ctx);
|
|
|
|
// PolarSSL takes key length by bit
|
|
|
|
PolarSSL.blowfish_setkey(ctx, realkey, keyLen * 8);
|
|
|
|
if (isCipher)
|
|
|
|
{
|
|
|
|
_encryptIV = new byte[ivLen];
|
|
|
|
Array.Copy(iv, _encryptIV, ivLen);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_decryptIV = new byte[ivLen];
|
|
|
|
Array.Copy(iv, _decryptIV, ivLen);
|
|
|
|
}
|
|
|
|
_encryptIV = new byte[ivLen];
|
|
|
|
_encryptIVOffset = new byte[8];
|
|
|
|
Array.Copy(iv, _encryptIV, ivLen);
|
|
|
|
}
|
|
|
|
else if (_cipher == CIPHER_RC4)
|
|
|
|
else
|
|
|
|
{
|
|
|
|
PolarSSL.arc4_init(ctx);
|
|
|
|
PolarSSL.arc4_setup(ctx, realkey, keyLen);
|
|
|
|
_decryptIV = new byte[ivLen];
|
|
|
|
_decryptIVOffset = new byte[8];
|
|
|
|
Array.Copy(iv, _decryptIV, ivLen);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (_cipher == CIPHER_RC4)
|
|
|
|
{
|
|
|
|
PolarSSL.arc4_init(ctx);
|
|
|
|
// PolarSSL RC4 takes key length by byte
|
|
|
|
PolarSSL.arc4_setup(ctx, realkey, keyLen);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@@ -165,7 +167,7 @@ namespace Shadowsocks.Encrypt |
|
|
|
|
|
|
|
public override void Encrypt(byte[] buf, int length, byte[] outbuf, out int outlength)
|
|
|
|
{
|
|
|
|
if (_encryptCtx == null)
|
|
|
|
if (_encryptCtx == IntPtr.Zero)
|
|
|
|
{
|
|
|
|
randBytes(outbuf, ivLen);
|
|
|
|
InitCipher(ref _encryptCtx, outbuf, true);
|
|
|
@@ -173,34 +175,6 @@ namespace Shadowsocks.Encrypt |
|
|
|
lock (tempbuf)
|
|
|
|
{
|
|
|
|
// C# could be multi-threaded
|
|
|
|
lock (_encryptCtx)
|
|
|
|
{
|
|
|
|
if (_disposed)
|
|
|
|
{
|
|
|
|
throw new ObjectDisposedException(this.ToString());
|
|
|
|
}
|
|
|
|
switch (_cipher)
|
|
|
|
{
|
|
|
|
case CIPHER_AES:
|
|
|
|
PolarSSL.aes_crypt_cfb128(_encryptCtx, PolarSSL.AES_ENCRYPT, length, ref _encryptIVOffset, _encryptIV, buf, tempbuf);
|
|
|
|
break;
|
|
|
|
case CIPHER_BF:
|
|
|
|
PolarSSL.blowfish_crypt_cfb64(_encryptCtx, PolarSSL.BLOWFISH_ENCRYPT, length, ref _encryptIVOffset, _encryptIV, buf, tempbuf);
|
|
|
|
break;
|
|
|
|
case CIPHER_RC4:
|
|
|
|
PolarSSL.arc4_crypt(_encryptCtx, length, buf, tempbuf);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
outlength = length + ivLen;
|
|
|
|
Buffer.BlockCopy(tempbuf, 0, outbuf, ivLen, length);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
outlength = length;
|
|
|
|
lock (_encryptCtx)
|
|
|
|
{
|
|
|
|
if (_disposed)
|
|
|
|
{
|
|
|
|
throw new ObjectDisposedException(this.ToString());
|
|
|
@@ -208,22 +182,45 @@ namespace Shadowsocks.Encrypt |
|
|
|
switch (_cipher)
|
|
|
|
{
|
|
|
|
case CIPHER_AES:
|
|
|
|
PolarSSL.aes_crypt_cfb128(_encryptCtx, PolarSSL.AES_ENCRYPT, length, ref _encryptIVOffset, _encryptIV, buf, outbuf);
|
|
|
|
PolarSSL.aes_crypt_cfb128(_encryptCtx, PolarSSL.AES_ENCRYPT, length, _encryptIVOffset, _encryptIV, buf, tempbuf);
|
|
|
|
break;
|
|
|
|
case CIPHER_BF:
|
|
|
|
PolarSSL.blowfish_crypt_cfb64(_encryptCtx, PolarSSL.BLOWFISH_ENCRYPT, length, ref _encryptIVOffset, _encryptIV, buf, outbuf);
|
|
|
|
PolarSSL.blowfish_crypt_cfb64(_encryptCtx, PolarSSL.BLOWFISH_ENCRYPT, length, _encryptIVOffset, _encryptIV, buf, tempbuf);
|
|
|
|
break;
|
|
|
|
case CIPHER_RC4:
|
|
|
|
PolarSSL.arc4_crypt(_encryptCtx, length, buf, outbuf);
|
|
|
|
PolarSSL.arc4_crypt(_encryptCtx, length, buf, tempbuf);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
outlength = length + ivLen;
|
|
|
|
Buffer.BlockCopy(tempbuf, 0, outbuf, ivLen, length);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
outlength = length;
|
|
|
|
if (_disposed)
|
|
|
|
{
|
|
|
|
throw new ObjectDisposedException(this.ToString());
|
|
|
|
}
|
|
|
|
switch (_cipher)
|
|
|
|
{
|
|
|
|
case CIPHER_AES:
|
|
|
|
PolarSSL.aes_crypt_cfb128(_encryptCtx, PolarSSL.AES_ENCRYPT, length, _encryptIVOffset, _encryptIV, buf, outbuf);
|
|
|
|
break;
|
|
|
|
case CIPHER_BF:
|
|
|
|
PolarSSL.blowfish_crypt_cfb64(_encryptCtx, PolarSSL.BLOWFISH_ENCRYPT, length, _encryptIVOffset, _encryptIV, buf, outbuf);
|
|
|
|
break;
|
|
|
|
case CIPHER_RC4:
|
|
|
|
PolarSSL.arc4_crypt(_encryptCtx, length, buf, outbuf);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public override void Decrypt(byte[] buf, int length, byte[] outbuf, out int outlength)
|
|
|
|
{
|
|
|
|
if (_decryptCtx == null)
|
|
|
|
if (_decryptCtx == IntPtr.Zero)
|
|
|
|
{
|
|
|
|
InitCipher(ref _decryptCtx, buf, false);
|
|
|
|
outlength = length - ivLen;
|
|
|
@@ -231,32 +228,6 @@ namespace Shadowsocks.Encrypt |
|
|
|
{
|
|
|
|
// C# could be multi-threaded
|
|
|
|
Buffer.BlockCopy(buf, ivLen, tempbuf, 0, length - ivLen);
|
|
|
|
lock (_decryptCtx)
|
|
|
|
{
|
|
|
|
if (_disposed)
|
|
|
|
{
|
|
|
|
throw new ObjectDisposedException(this.ToString());
|
|
|
|
}
|
|
|
|
switch (_cipher)
|
|
|
|
{
|
|
|
|
case CIPHER_AES:
|
|
|
|
PolarSSL.aes_crypt_cfb128(_decryptCtx, PolarSSL.AES_DECRYPT, length - ivLen, ref _decryptIVOffset, _decryptIV, tempbuf, outbuf);
|
|
|
|
break;
|
|
|
|
case CIPHER_BF:
|
|
|
|
PolarSSL.blowfish_crypt_cfb64(_decryptCtx, PolarSSL.BLOWFISH_DECRYPT, length - ivLen, ref _decryptIVOffset, _decryptIV, tempbuf, outbuf);
|
|
|
|
break;
|
|
|
|
case CIPHER_RC4:
|
|
|
|
PolarSSL.arc4_crypt(_decryptCtx, length - ivLen, tempbuf, outbuf);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
outlength = length;
|
|
|
|
lock (_decryptCtx)
|
|
|
|
{
|
|
|
|
if (_disposed)
|
|
|
|
{
|
|
|
|
throw new ObjectDisposedException(this.ToString());
|
|
|
@@ -264,17 +235,37 @@ namespace Shadowsocks.Encrypt |
|
|
|
switch (_cipher)
|
|
|
|
{
|
|
|
|
case CIPHER_AES:
|
|
|
|
PolarSSL.aes_crypt_cfb128(_decryptCtx, PolarSSL.AES_DECRYPT, length, ref _decryptIVOffset, _decryptIV, buf, outbuf);
|
|
|
|
PolarSSL.aes_crypt_cfb128(_decryptCtx, PolarSSL.AES_DECRYPT, length - ivLen, _decryptIVOffset, _decryptIV, tempbuf, outbuf);
|
|
|
|
break;
|
|
|
|
case CIPHER_BF:
|
|
|
|
PolarSSL.blowfish_crypt_cfb64(_decryptCtx, PolarSSL.BLOWFISH_DECRYPT, length, ref _decryptIVOffset, _decryptIV, buf, outbuf);
|
|
|
|
PolarSSL.blowfish_crypt_cfb64(_decryptCtx, PolarSSL.BLOWFISH_DECRYPT, length - ivLen, _decryptIVOffset, _decryptIV, tempbuf, outbuf);
|
|
|
|
break;
|
|
|
|
case CIPHER_RC4:
|
|
|
|
PolarSSL.arc4_crypt(_decryptCtx, length, buf, outbuf);
|
|
|
|
PolarSSL.arc4_crypt(_decryptCtx, length - ivLen, tempbuf, outbuf);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
outlength = length;
|
|
|
|
if (_disposed)
|
|
|
|
{
|
|
|
|
throw new ObjectDisposedException(this.ToString());
|
|
|
|
}
|
|
|
|
switch (_cipher)
|
|
|
|
{
|
|
|
|
case CIPHER_AES:
|
|
|
|
PolarSSL.aes_crypt_cfb128(_decryptCtx, PolarSSL.AES_DECRYPT, length, _decryptIVOffset, _decryptIV, buf, outbuf);
|
|
|
|
break;
|
|
|
|
case CIPHER_BF:
|
|
|
|
PolarSSL.blowfish_crypt_cfb64(_decryptCtx, PolarSSL.BLOWFISH_DECRYPT, length, _decryptIVOffset, _decryptIV, buf, outbuf);
|
|
|
|
break;
|
|
|
|
case CIPHER_RC4:
|
|
|
|
PolarSSL.arc4_crypt(_decryptCtx, length, buf, outbuf);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#region IDisposable
|
|
|
@@ -304,41 +295,39 @@ namespace Shadowsocks.Encrypt |
|
|
|
|
|
|
|
if (disposing)
|
|
|
|
{
|
|
|
|
if (_encryptCtx != null)
|
|
|
|
if (_encryptCtx != IntPtr.Zero)
|
|
|
|
{
|
|
|
|
lock (_encryptCtx)
|
|
|
|
switch (_cipher)
|
|
|
|
{
|
|
|
|
switch (_cipher)
|
|
|
|
{
|
|
|
|
case CIPHER_AES:
|
|
|
|
PolarSSL.aes_free(_encryptCtx);
|
|
|
|
break;
|
|
|
|
case CIPHER_BF:
|
|
|
|
PolarSSL.blowfish_free(_encryptCtx);
|
|
|
|
break;
|
|
|
|
case CIPHER_RC4:
|
|
|
|
PolarSSL.arc4_free(_encryptCtx);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case CIPHER_AES:
|
|
|
|
PolarSSL.aes_free(_encryptCtx);
|
|
|
|
break;
|
|
|
|
case CIPHER_BF:
|
|
|
|
PolarSSL.blowfish_free(_encryptCtx);
|
|
|
|
break;
|
|
|
|
case CIPHER_RC4:
|
|
|
|
PolarSSL.arc4_free(_encryptCtx);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
Marshal.FreeHGlobal(_encryptCtx);
|
|
|
|
_encryptCtx = IntPtr.Zero;
|
|
|
|
}
|
|
|
|
if (_decryptCtx != null)
|
|
|
|
if (_decryptCtx != IntPtr.Zero)
|
|
|
|
{
|
|
|
|
lock (_decryptCtx)
|
|
|
|
switch (_cipher)
|
|
|
|
{
|
|
|
|
switch (_cipher)
|
|
|
|
{
|
|
|
|
case CIPHER_AES:
|
|
|
|
PolarSSL.aes_free(_decryptCtx);
|
|
|
|
break;
|
|
|
|
case CIPHER_BF:
|
|
|
|
PolarSSL.blowfish_free(_decryptCtx);
|
|
|
|
break;
|
|
|
|
case CIPHER_RC4:
|
|
|
|
PolarSSL.arc4_free(_decryptCtx);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case CIPHER_AES:
|
|
|
|
PolarSSL.aes_free(_decryptCtx);
|
|
|
|
break;
|
|
|
|
case CIPHER_BF:
|
|
|
|
PolarSSL.blowfish_free(_decryptCtx);
|
|
|
|
break;
|
|
|
|
case CIPHER_RC4:
|
|
|
|
PolarSSL.arc4_free(_decryptCtx);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
Marshal.FreeHGlobal(_decryptCtx);
|
|
|
|
_decryptCtx = IntPtr.Zero;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|