186 lines
5.8 KiB
C#
Executable File
186 lines
5.8 KiB
C#
Executable File
using System;
|
|
using System.Collections.Generic;
|
|
using System.Runtime.InteropServices;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
using System.Threading;
|
|
|
|
namespace Shadowsocks.Encryption
|
|
{
|
|
public class PolarSSLEncryptor
|
|
: IVEncryptor, IDisposable
|
|
{
|
|
const int CIPHER_AES = 1;
|
|
const int CIPHER_RC4 = 2;
|
|
|
|
private IntPtr _encryptCtx = IntPtr.Zero;
|
|
private IntPtr _decryptCtx = IntPtr.Zero;
|
|
|
|
public PolarSSLEncryptor(string method, string password)
|
|
: base(method, password)
|
|
{
|
|
InitKey(method, password);
|
|
}
|
|
|
|
private static Dictionary<string, int[]> _ciphers = new Dictionary<string, int[]> {
|
|
{"aes-128-cfb", new int[]{16, 16, CIPHER_AES, PolarSSL.AES_CTX_SIZE}},
|
|
{"aes-192-cfb", new int[]{24, 16, CIPHER_AES, PolarSSL.AES_CTX_SIZE}},
|
|
{"aes-256-cfb", new int[]{32, 16, CIPHER_AES, PolarSSL.AES_CTX_SIZE}},
|
|
{"rc4", new int[]{16, 0, CIPHER_RC4, PolarSSL.ARC4_CTX_SIZE}},
|
|
{"rc4-md5", new int[]{16, 16, CIPHER_RC4, PolarSSL.ARC4_CTX_SIZE}},
|
|
};
|
|
|
|
public static List<string> SupportedCiphers()
|
|
{
|
|
return new List<string>(_ciphers.Keys);
|
|
}
|
|
|
|
protected override Dictionary<string, int[]> getCiphers()
|
|
{
|
|
return _ciphers;
|
|
}
|
|
|
|
protected override void initCipher(byte[] iv, bool isCipher)
|
|
{
|
|
base.initCipher(iv, isCipher);
|
|
|
|
IntPtr ctx;
|
|
ctx = Marshal.AllocHGlobal(_cipherInfo[3]);
|
|
if (isCipher)
|
|
{
|
|
_encryptCtx = ctx;
|
|
}
|
|
else
|
|
{
|
|
_decryptCtx = ctx;
|
|
}
|
|
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);
|
|
}
|
|
else if (_cipher == CIPHER_RC4)
|
|
{
|
|
PolarSSL.arc4_init(ctx);
|
|
// PolarSSL RC4 takes key length by byte
|
|
PolarSSL.arc4_setup(ctx, realkey, keyLen);
|
|
}
|
|
}
|
|
|
|
protected override void cipherUpdate(bool isCipher, int length, byte[] buf, byte[] outbuf)
|
|
{
|
|
// C# could be multi-threaded
|
|
if (_disposed)
|
|
{
|
|
throw new ObjectDisposedException(this.ToString());
|
|
}
|
|
byte[] iv;
|
|
int ivOffset;
|
|
IntPtr ctx;
|
|
if (isCipher)
|
|
{
|
|
iv = _encryptIV;
|
|
ivOffset = _encryptIVOffset;
|
|
ctx = _encryptCtx;
|
|
}
|
|
else
|
|
{
|
|
iv = _decryptIV;
|
|
ivOffset = _decryptIVOffset;
|
|
ctx = _decryptCtx;
|
|
}
|
|
switch (_cipher)
|
|
{
|
|
case CIPHER_AES:
|
|
PolarSSL.aes_crypt_cfb128(ctx, isCipher ? PolarSSL.AES_ENCRYPT : PolarSSL.AES_DECRYPT, length, ref ivOffset, iv, buf, outbuf);
|
|
if (isCipher)
|
|
{
|
|
_encryptIVOffset = ivOffset;
|
|
}
|
|
else
|
|
{
|
|
_decryptIVOffset = ivOffset;
|
|
}
|
|
break;
|
|
case CIPHER_RC4:
|
|
PolarSSL.arc4_crypt(ctx, length, buf, outbuf);
|
|
break;
|
|
}
|
|
}
|
|
|
|
#region IDisposable
|
|
private bool _disposed;
|
|
|
|
public override void Dispose()
|
|
{
|
|
Dispose(true);
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
~PolarSSLEncryptor()
|
|
{
|
|
Dispose(false);
|
|
}
|
|
|
|
protected virtual void Dispose(bool disposing)
|
|
{
|
|
lock (this)
|
|
{
|
|
if (_disposed)
|
|
{
|
|
return;
|
|
}
|
|
_disposed = true;
|
|
}
|
|
|
|
if (disposing)
|
|
{
|
|
if (_encryptCtx != IntPtr.Zero)
|
|
{
|
|
switch (_cipher)
|
|
{
|
|
case CIPHER_AES:
|
|
PolarSSL.aes_free(_encryptCtx);
|
|
break;
|
|
case CIPHER_RC4:
|
|
PolarSSL.arc4_free(_encryptCtx);
|
|
break;
|
|
}
|
|
Marshal.FreeHGlobal(_encryptCtx);
|
|
_encryptCtx = IntPtr.Zero;
|
|
}
|
|
if (_decryptCtx != IntPtr.Zero)
|
|
{
|
|
switch (_cipher)
|
|
{
|
|
case CIPHER_AES:
|
|
PolarSSL.aes_free(_decryptCtx);
|
|
break;
|
|
case CIPHER_RC4:
|
|
PolarSSL.arc4_free(_decryptCtx);
|
|
break;
|
|
}
|
|
Marshal.FreeHGlobal(_decryptCtx);
|
|
_decryptCtx = IntPtr.Zero;
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
}
|
|
}
|