diff --git a/shadowsocks-csharp/Controller/Service/TCPRelay.cs b/shadowsocks-csharp/Controller/Service/TCPRelay.cs index a10e397c..beb5c716 100644 --- a/shadowsocks-csharp/Controller/Service/TCPRelay.cs +++ b/shadowsocks-csharp/Controller/Service/TCPRelay.cs @@ -224,8 +224,8 @@ namespace Shadowsocks.Controller /* prepare address buffer length for AEAD */ Logger.Debug($"_addrBufLength={_addrBufLength}"); - encryptor.AddrBufLength = _addrBufLength; - decryptor.AddrBufLength = _addrBufLength; + encryptor.AddressBufferLength = _addrBufLength; + decryptor.AddressBufferLength = _addrBufLength; } public void Start(byte[] firstPacket, int length) @@ -275,15 +275,6 @@ namespace Shadowsocks.Controller Logger.LogUsefulException(e); } } - - lock (_encryptionLock) - { - lock (_decryptionLock) - { - encryptor?.Dispose(); - decryptor?.Dispose(); - } - } } private void HandshakeReceive() diff --git a/shadowsocks-csharp/Encryption/AEAD/AEADAesGcmNativeEncryptor.cs b/shadowsocks-csharp/Encryption/AEAD/AEADAesGcmNativeEncryptor.cs index 69ff86c4..dc6da1c7 100644 --- a/shadowsocks-csharp/Encryption/AEAD/AEADAesGcmNativeEncryptor.cs +++ b/shadowsocks-csharp/Encryption/AEAD/AEADAesGcmNativeEncryptor.cs @@ -13,16 +13,15 @@ namespace Shadowsocks.Encryption.AEAD public AEADAesGcmNativeEncryptor(string method, string password) : base(method, password) { } - static int CIPHER_AES = 1; // dummy - private static readonly Dictionary _ciphers = new Dictionary + private static readonly Dictionary _ciphers = new Dictionary { - {"aes-128-gcm", new EncryptorInfo("AES-128-GCM", 16, 16, 12, 16, CIPHER_AES)}, - {"aes-192-gcm", new EncryptorInfo("AES-192-GCM", 24, 24, 12, 16, CIPHER_AES)}, - {"aes-256-gcm", new EncryptorInfo("AES-256-GCM", 32, 32, 12, 16, CIPHER_AES)}, + {"aes-128-gcm", new CipherInfo("AES-128-GCM", 16, 16, 12, 16, CipherFamily.AesGcm)}, + {"aes-192-gcm", new CipherInfo("AES-192-GCM", 24, 24, 12, 16, CipherFamily.AesGcm)}, + {"aes-256-gcm", new CipherInfo("AES-256-GCM", 32, 32, 12, 16, CipherFamily.AesGcm)}, }; - protected override Dictionary getCiphers() + protected override Dictionary getCiphers() { return _ciphers; } @@ -102,13 +101,9 @@ namespace Shadowsocks.Encryption.AEAD return d.ToArray(); } - public static List SupportedCiphers() - { - return new List(_ciphers.Keys); - } - - public override void Dispose() + public static Dictionary SupportedCiphers() { + return _ciphers; } } } \ No newline at end of file diff --git a/shadowsocks-csharp/Encryption/AEAD/AEADBouncyCastleEncryptor.cs b/shadowsocks-csharp/Encryption/AEAD/AEADBouncyCastleEncryptor.cs index 0ee375df..0bebb026 100644 --- a/shadowsocks-csharp/Encryption/AEAD/AEADBouncyCastleEncryptor.cs +++ b/shadowsocks-csharp/Encryption/AEAD/AEADBouncyCastleEncryptor.cs @@ -11,22 +11,19 @@ namespace Shadowsocks.Encryption.AEAD { public class AEADBouncyCastleEncryptor : AEADEncryptor { - static int CIPHER_AES = 1; // dummy - - public AEADBouncyCastleEncryptor(string method, string password) - : base(method, password) + public AEADBouncyCastleEncryptor(string method, string password) : base(method, password) { } - private static readonly Dictionary _ciphers = new Dictionary + private static readonly Dictionary _ciphers = new Dictionary { - {"aes-128-gcm", new EncryptorInfo("AES-128-GCM", 16, 16, 12, 16, CIPHER_AES)}, - {"aes-192-gcm", new EncryptorInfo("AES-192-GCM", 24, 24, 12, 16, CIPHER_AES)}, - {"aes-256-gcm", new EncryptorInfo("AES-256-GCM", 32, 32, 12, 16, CIPHER_AES)}, + {"aes-128-gcm", new CipherInfo("aes-128-gcm", 16, 16, 12, 16, CipherFamily.AesGcm)}, + {"aes-192-gcm", new CipherInfo("aes-192-gcm", 24, 24, 12, 16, CipherFamily.AesGcm)}, + {"aes-256-gcm", new CipherInfo("aes-256-gcm", 32, 32, 12, 16, CipherFamily.AesGcm)}, }; - protected override Dictionary getCiphers() + protected override Dictionary getCiphers() { return _ciphers; } @@ -90,14 +87,10 @@ namespace Shadowsocks.Encryption.AEAD aes.DoFinal(cipher, len); return cipher; } - - public static List SupportedCiphers() - { - return new List(_ciphers.Keys); - } - public override void Dispose() + public static Dictionary SupportedCiphers() { + return _ciphers; } } } diff --git a/shadowsocks-csharp/Encryption/AEAD/AEADEncryptor.cs b/shadowsocks-csharp/Encryption/AEAD/AEADEncryptor.cs index 52f7030c..daa3ff07 100644 --- a/shadowsocks-csharp/Encryption/AEAD/AEADEncryptor.cs +++ b/shadowsocks-csharp/Encryption/AEAD/AEADEncryptor.cs @@ -11,8 +11,7 @@ using Shadowsocks.Encryption.Stream; namespace Shadowsocks.Encryption.AEAD { - public abstract class AEADEncryptor - : EncryptorBase + public abstract class AEADEncryptor : EncryptorBase { private static Logger logger = LogManager.GetCurrentClassLogger(); // We are using the same saltLen and keyLen @@ -29,13 +28,13 @@ namespace Shadowsocks.Encryption.AEAD public const int CHUNK_LEN_BYTES = 2; public const uint CHUNK_LEN_MASK = 0x3FFFu; - protected Dictionary ciphers; + protected Dictionary ciphers; protected string _method; - protected int _cipher; + protected CipherFamily _cipher; // internal name in the crypto library protected string _innerLibName; - protected EncryptorInfo CipherInfo; + protected CipherInfo CipherInfo; protected static byte[] _Masterkey = null; protected byte[] sessionKey; protected int keyLen; @@ -67,7 +66,7 @@ namespace Shadowsocks.Encryption.AEAD decNonce = new byte[nonceLen]; } - protected abstract Dictionary getCiphers(); + protected abstract Dictionary getCiphers(); protected void InitEncryptorInfo(string method) { @@ -75,16 +74,12 @@ namespace Shadowsocks.Encryption.AEAD _method = method; ciphers = getCiphers(); CipherInfo = ciphers[_method]; - _innerLibName = CipherInfo.InnerLibName; _cipher = CipherInfo.Type; - if (_cipher == 0) - { - throw new System.Exception("method not found"); - } - keyLen = CipherInfo.KeySize; - saltLen = CipherInfo.SaltSize; - tagLen = CipherInfo.TagSize; - nonceLen = CipherInfo.NonceSize; + var parameter = (AEADCipherParameter)CipherInfo.CipherParameter; + keyLen = parameter.KeySize; + saltLen = parameter.SaltSize; + tagLen = parameter.TagSize; + nonceLen = parameter.NonceSize; } protected void InitKey(string password) @@ -196,10 +191,10 @@ namespace Shadowsocks.Encryption.AEAD _tcpRequestSent = true; // The first TCP request int encAddrBufLength; - byte[] encAddrBufBytes = new byte[AddrBufLength + tagLen * 2 + CHUNK_LEN_BYTES]; - byte[] addrBytes = _encCircularBuffer.Get(AddrBufLength); - ChunkEncrypt(addrBytes, AddrBufLength, encAddrBufBytes, out encAddrBufLength); - Debug.Assert(encAddrBufLength == AddrBufLength + tagLen * 2 + CHUNK_LEN_BYTES); + byte[] encAddrBufBytes = new byte[AddressBufferLength + tagLen * 2 + CHUNK_LEN_BYTES]; + byte[] addrBytes = _encCircularBuffer.Get(AddressBufferLength); + ChunkEncrypt(addrBytes, AddressBufferLength, encAddrBufBytes, out encAddrBufLength); + Debug.Assert(encAddrBufLength == AddressBufferLength + tagLen * 2 + CHUNK_LEN_BYTES); Array.Copy(encAddrBufBytes, 0, outbuf, outlength, encAddrBufLength); outlength += encAddrBufLength; logger.Debug($"_tcpRequestSent outlength {outlength}"); diff --git a/shadowsocks-csharp/Encryption/AEAD/AEADNaClEncryptor.cs b/shadowsocks-csharp/Encryption/AEAD/AEADNaClEncryptor.cs index dc58bffb..3f0ec5c7 100644 --- a/shadowsocks-csharp/Encryption/AEAD/AEADNaClEncryptor.cs +++ b/shadowsocks-csharp/Encryption/AEAD/AEADNaClEncryptor.cs @@ -15,7 +15,6 @@ namespace Shadowsocks.Encryption.AEAD SnufflePoly1305 dec; public AEADNaClEncryptor(string method, string password) : base(method, password) { - } public override void InitCipher(byte[] salt, bool isEncrypt, bool isUdp) @@ -28,10 +27,10 @@ namespace Shadowsocks.Encryption.AEAD switch (_cipher) { default: - case CipherChaCha20Poly1305: + case CipherFamily.Chacha20Poly1305: tmp = new ChaCha20Poly1305(sessionKey); break; - case CipherXChaCha20Poly1305: + case CipherFamily.XChacha20Poly1305: tmp = new XChaCha20Poly1305(sessionKey); break; } @@ -53,28 +52,25 @@ namespace Shadowsocks.Encryption.AEAD clen = (uint)ct.Length; } - public override void Dispose() + private static readonly Dictionary _ciphers = new Dictionary { - } - - const int CipherChaCha20Poly1305 = 1; - const int CipherXChaCha20Poly1305 = 2; + {"chacha20-ietf-poly1305", new CipherInfo("chacha20-ietf-poly1305",32, 32, 12, 16, CipherFamily.Chacha20Poly1305)}, + {"xchacha20-ietf-poly1305", new CipherInfo("xchacha20-ietf-poly1305",32, 32, 24, 16, CipherFamily.XChacha20Poly1305)}, + }; - private static readonly Dictionary _ciphers = new Dictionary + protected override Dictionary getCiphers() { - {"chacha20-ietf-poly1305", new EncryptorInfo(32, 32, 12, 16, 1)}, - {"xchacha20-ietf-poly1305", new EncryptorInfo(32, 32, 24, 16, 2)}, - //{"aes-256-gcm", new EncryptorInfo(32, 32, 12, 16, CIPHER_AES256GCM)}, - }; + return _ciphers; + } - protected override Dictionary getCiphers() + public static Dictionary SupportedCiphers() { return _ciphers; } public override byte[] CipherEncrypt2(byte[] plain) { - return enc.Encrypt(plain, null, encNonce); + return enc.Encrypt(plain, null, encNonce); } public override byte[] CipherDecrypt2(byte[] cipher) diff --git a/shadowsocks-csharp/Encryption/AEAD/AEADNativeEncryptor.cs b/shadowsocks-csharp/Encryption/AEAD/AEADNativeEncryptor.cs deleted file mode 100644 index 1ce37496..00000000 --- a/shadowsocks-csharp/Encryption/AEAD/AEADNativeEncryptor.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Shadowsocks.Encryption.AEAD -{ - public class AEADNativeEncryptor : AEADEncryptor - { - public AEADNativeEncryptor(string method, string password) - : base(method, password) - { - } - - public override void cipherDecrypt(byte[] ciphertext, uint clen, byte[] plaintext, ref uint plen) - { - Array.Copy(ciphertext, plaintext, 0); - plen = clen; - - } - - public override void cipherEncrypt(byte[] plaintext, uint plen, byte[] ciphertext, ref uint clen) - { - Array.Copy(plaintext, ciphertext, 0); - clen = plen; - } - - public override void Dispose() - { - return; - } - - private static Dictionary _ciphers = new Dictionary() - { - {"plain-fake-aead",new EncryptorInfo("PLAIN_AEAD",0,0,0,0,0) } - }; - - protected override Dictionary getCiphers() - { - return _ciphers; - } - - public static IEnumerable SupportedCiphers() - { - return _ciphers.Keys; - } - - public override byte[] CipherEncrypt2(byte[] plain) - { - return plain; - } - - public override byte[] CipherDecrypt2(byte[] cipher) - { - return cipher; - } - } -} diff --git a/shadowsocks-csharp/Encryption/CipherInfo.cs b/shadowsocks-csharp/Encryption/CipherInfo.cs new file mode 100644 index 00000000..149e3950 --- /dev/null +++ b/shadowsocks-csharp/Encryption/CipherInfo.cs @@ -0,0 +1,85 @@ +using System; + +namespace Shadowsocks.Encryption +{ + public enum CipherFamily + { + Plain, + Table, + + AesGcm, + + AesCfb, + AesCtr, + + Chacha20, + Chacha20Poly1305, + XChacha20Poly1305, + + Rc4, + Rc4Md5, + } + + public enum CipherStandardState + { + InUse, + Deprecated, + Hidden, + } + + public class CipherParameter + { + public int KeySize; + } + public class StreamCipherParameter : CipherParameter + { + public int IvSize; + } + + public class AEADCipherParameter : CipherParameter + { + public int SaltSize; + public int TagSize; + public int NonceSize; + } + + public class CipherInfo + { + public string Name; + public CipherFamily Type; + public CipherParameter CipherParameter; + + public CipherStandardState StandardState = CipherStandardState.InUse; + + #region Stream ciphers + public CipherInfo(string name, int keySize, int ivSize, CipherFamily type) + { + Type = type; + Name = name; + StandardState = CipherStandardState.Hidden; + CipherParameter = new StreamCipherParameter + { + KeySize = keySize, + IvSize = ivSize, + }; + } + + #endregion + + #region AEAD ciphers + public CipherInfo(string name, int keySize, int saltSize, int nonceSize, int tagSize, CipherFamily type) + { + Type = type; + Name = name; + + CipherParameter = new AEADCipherParameter + { + KeySize = keySize, + SaltSize = saltSize, + NonceSize = nonceSize, + TagSize = tagSize, + }; + } + #endregion + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/Encryption/EncryptorBase.cs b/shadowsocks-csharp/Encryption/EncryptorBase.cs index ab69f1ec..7f358a5c 100644 --- a/shadowsocks-csharp/Encryption/EncryptorBase.cs +++ b/shadowsocks-csharp/Encryption/EncryptorBase.cs @@ -1,65 +1,6 @@ namespace Shadowsocks.Encryption { - public class EncryptorInfo - { - public int KeySize; - public int IvSize; - public int SaltSize; - public int TagSize; - public int NonceSize; - public int Type; - public string InnerLibName; - - // For those who make use of internal crypto method name - // e.g. mbed TLS - - #region Stream ciphers - - public EncryptorInfo(string innerLibName, int keySize, int ivSize, int type) - { - this.KeySize = keySize; - this.IvSize = ivSize; - this.Type = type; - this.InnerLibName = innerLibName; - } - - public EncryptorInfo(int keySize, int ivSize, int type) - { - this.KeySize = keySize; - this.IvSize = ivSize; - this.Type = type; - this.InnerLibName = string.Empty; - } - - #endregion - - #region AEAD ciphers - - public EncryptorInfo(string innerLibName, int keySize, int saltSize, int nonceSize, int tagSize, int type) - { - this.KeySize = keySize; - this.SaltSize = saltSize; - this.NonceSize = nonceSize; - this.TagSize = tagSize; - this.Type = type; - this.InnerLibName = innerLibName; - } - - public EncryptorInfo(int keySize, int saltSize, int nonceSize, int tagSize, int type) - { - this.KeySize = keySize; - this.SaltSize = saltSize; - this.NonceSize = nonceSize; - this.TagSize = tagSize; - this.Type = type; - this.InnerLibName = string.Empty; - } - - #endregion - } - - public abstract class EncryptorBase - : IEncryptor + public abstract class EncryptorBase : IEncryptor { public const int MAX_INPUT_SIZE = 32768; @@ -81,7 +22,7 @@ protected string Method; protected string Password; - + 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); @@ -90,8 +31,6 @@ public abstract void DecryptUDP(byte[] buf, int length, byte[] outbuf, out int outlength); - public abstract void Dispose(); - - public int AddrBufLength { get; set; } = - 1; + public int AddressBufferLength { get; set; } = -1; } } \ No newline at end of file diff --git a/shadowsocks-csharp/Encryption/EncryptorFactory.cs b/shadowsocks-csharp/Encryption/EncryptorFactory.cs index 14bad7ee..ce6dbc28 100644 --- a/shadowsocks-csharp/Encryption/EncryptorFactory.cs +++ b/shadowsocks-csharp/Encryption/EncryptorFactory.cs @@ -10,27 +10,51 @@ namespace Shadowsocks.Encryption public static class EncryptorFactory { private static Dictionary _registeredEncryptors = new Dictionary(); - + private static Dictionary ciphers = new Dictionary(); private static readonly Type[] ConstructorTypes = { typeof(string), typeof(string) }; static EncryptorFactory() { - foreach (string method in StreamTableNativeEncryptor.SupportedCiphers()) + foreach (var method in StreamTableNativeEncryptor.SupportedCiphers()) { - if (!_registeredEncryptors.ContainsKey(method)) - _registeredEncryptors.Add(method, typeof(StreamTableNativeEncryptor)); + if (!_registeredEncryptors.ContainsKey(method.Key)) + { + ciphers.Add(method.Key, method.Value); + _registeredEncryptors.Add(method.Key, typeof(StreamTableNativeEncryptor)); + } } - - foreach (string method in AEADNativeEncryptor.SupportedCiphers()) + foreach (var method in StreamRc4NativeEncryptor.SupportedCiphers()) { - if (!_registeredEncryptors.ContainsKey(method)) - _registeredEncryptors.Add(method, typeof(AEADNativeEncryptor)); + if (!_registeredEncryptors.ContainsKey(method.Key)) + { + ciphers.Add(method.Key, method.Value); + _registeredEncryptors.Add(method.Key, typeof(StreamRc4NativeEncryptor)); + } } - foreach (string method in AEADBouncyCastleEncryptor.SupportedCiphers()) + foreach (var method in AEADAesGcmNativeEncryptor.SupportedCiphers()) + { + if (!_registeredEncryptors.ContainsKey(method.Key)) + { + ciphers.Add(method.Key, method.Value); + _registeredEncryptors.Add(method.Key, typeof(AEADAesGcmNativeEncryptor)); + } + } + foreach (var method in AEADNaClEncryptor.SupportedCiphers()) + { + if (!_registeredEncryptors.ContainsKey(method.Key)) + { + ciphers.Add(method.Key, method.Value); + _registeredEncryptors.Add(method.Key, typeof(AEADNaClEncryptor)); + } + } + foreach (var method in StreamRc4NativeEncryptor.SupportedCiphers()) { - if (!_registeredEncryptors.ContainsKey(method)) - _registeredEncryptors.Add(method, typeof(AEADBouncyCastleEncryptor)); + if (!_registeredEncryptors.ContainsKey(method.Key)) + { + ciphers.Add(method.Key, method.Value); + _registeredEncryptors.Add(method.Key, typeof(StreamRc4NativeEncryptor)); + } } } diff --git a/shadowsocks-csharp/Encryption/IEncryptor.cs b/shadowsocks-csharp/Encryption/IEncryptor.cs index d238083c..00600a21 100644 --- a/shadowsocks-csharp/Encryption/IEncryptor.cs +++ b/shadowsocks-csharp/Encryption/IEncryptor.cs @@ -1,11 +1,12 @@ using System; +using System.Collections.Generic; namespace Shadowsocks.Encryption { - public interface IEncryptor : IDisposable + public interface IEncryptor { /* length == -1 means not used */ - int AddrBufLength { set; get; } + int AddressBufferLength { set; get; } void Encrypt(byte[] buf, int length, byte[] outbuf, out int outlength); void Decrypt(byte[] buf, int length, byte[] outbuf, out int outlength); void EncryptUDP(byte[] buf, int length, byte[] outbuf, out int outlength); diff --git a/shadowsocks-csharp/Encryption/Stream/StreamEncryptor.cs b/shadowsocks-csharp/Encryption/Stream/StreamEncryptor.cs index 6c27b9a3..ee854812 100644 --- a/shadowsocks-csharp/Encryption/Stream/StreamEncryptor.cs +++ b/shadowsocks-csharp/Encryption/Stream/StreamEncryptor.cs @@ -7,8 +7,7 @@ using Shadowsocks.Controller; namespace Shadowsocks.Encryption.Stream { - public abstract class StreamEncryptor - : EncryptorBase + public abstract class StreamEncryptor : EncryptorBase { // for UDP only protected static byte[] _udpTmpBuf = new byte[65536]; @@ -17,7 +16,7 @@ namespace Shadowsocks.Encryption.Stream private ByteCircularBuffer _encCircularBuffer = new ByteCircularBuffer(TCPHandler.BufferSize * 2); private ByteCircularBuffer _decCircularBuffer = new ByteCircularBuffer(TCPHandler.BufferSize * 2); - protected Dictionary ciphers; + protected Dictionary ciphers; protected byte[] _encryptIV; protected byte[] _decryptIV; @@ -27,10 +26,10 @@ namespace Shadowsocks.Encryption.Stream protected bool _encryptIVSent; protected string _method; - protected int _cipher; + protected CipherFamily _cipher; // internal name in the crypto library protected string _innerLibName; - protected EncryptorInfo CipherInfo; + protected CipherInfo CipherInfo; // long-time master key protected static byte[] _key = null; protected int keyLen; @@ -43,7 +42,7 @@ namespace Shadowsocks.Encryption.Stream InitKey(password); } - protected abstract Dictionary getCiphers(); + protected abstract Dictionary getCiphers(); private void InitEncryptorInfo(string method) { @@ -51,14 +50,10 @@ namespace Shadowsocks.Encryption.Stream _method = method; ciphers = getCiphers(); CipherInfo = ciphers[_method]; - _innerLibName = CipherInfo.InnerLibName; _cipher = CipherInfo.Type; - if (_cipher == 0) - { - throw new System.Exception("method not found"); - } - keyLen = CipherInfo.KeySize; - ivLen = CipherInfo.IvSize; + var parameter = (StreamCipherParameter)CipherInfo.CipherParameter; + keyLen = parameter.KeySize; + ivLen = parameter.IvSize; } private void InitKey(string password) diff --git a/shadowsocks-csharp/Encryption/Stream/StreamRc4NativeEncryptor.cs b/shadowsocks-csharp/Encryption/Stream/StreamRc4NativeEncryptor.cs index 4655aba4..fd0f8081 100644 --- a/shadowsocks-csharp/Encryption/Stream/StreamRc4NativeEncryptor.cs +++ b/shadowsocks-csharp/Encryption/Stream/StreamRc4NativeEncryptor.cs @@ -8,27 +8,16 @@ namespace Shadowsocks.Encryption.Stream { public class StreamRc4NativeEncryptor : StreamEncryptor { - const int Rc4 = 0; - const int Rc4Md5 = 1; - - string _password; - - byte[] realkey; - byte[] sbox; + byte[] realkey = new byte[256]; + byte[] sbox = new byte[256]; public StreamRc4NativeEncryptor(string method, string password) : base(method, password) { - _password = password; - } - - public override void Dispose() - { - return; } protected override void initCipher(byte[] iv, bool isEncrypt) { base.initCipher(iv, isEncrypt); - if (_cipher == Rc4Md5) + if (_cipher == CipherFamily.Rc4Md5) { byte[] temp = new byte[keyLen + ivLen]; Array.Copy(_key, 0, temp, 0, keyLen); @@ -54,19 +43,19 @@ namespace Shadowsocks.Encryption.Stream Array.Copy(t, outbuf, length); } - private static readonly Dictionary _ciphers = new Dictionary + private static readonly Dictionary _ciphers = new Dictionary { // original RC4 doesn't use IV - { "rc4", new EncryptorInfo("RC4", 16, 0, Rc4) }, - { "rc4-md5", new EncryptorInfo("RC4", 16, 16, Rc4Md5) }, + { "rc4", new CipherInfo("rc4", 16, 0, CipherFamily.Rc4) }, + { "rc4-md5", new CipherInfo("rc4-md5", 16, 16, CipherFamily.Rc4Md5) }, }; - public static IEnumerable SupportedCiphers() + public static Dictionary SupportedCiphers() { - return _ciphers.Keys; + return _ciphers; } - protected override Dictionary getCiphers() + protected override Dictionary getCiphers() { return _ciphers; } diff --git a/shadowsocks-csharp/Encryption/Stream/StreamTableNativeEncryptor.cs b/shadowsocks-csharp/Encryption/Stream/StreamTableNativeEncryptor.cs index 1771cf29..097257cf 100644 --- a/shadowsocks-csharp/Encryption/Stream/StreamTableNativeEncryptor.cs +++ b/shadowsocks-csharp/Encryption/Stream/StreamTableNativeEncryptor.cs @@ -8,9 +8,6 @@ namespace Shadowsocks.Encryption.Stream { public class StreamTableNativeEncryptor : StreamEncryptor { - const int Plain = 0; - const int Table = 1; - string _password; public StreamTableNativeEncryptor(string method, string password) : base(method, password) @@ -18,15 +15,10 @@ namespace Shadowsocks.Encryption.Stream _password = password; } - public override void Dispose() - { - return; - } - protected override void initCipher(byte[] iv, bool isEncrypt) { base.initCipher(iv, isEncrypt); - if (_cipher == Table) + if (_cipher == CipherFamily.Table) { ulong a = BitConverter.ToUInt64(CryptoUtils.MD5(Encoding.UTF8.GetBytes(_password)), 0); for (int i = 0; i < 256; i++) @@ -46,7 +38,7 @@ namespace Shadowsocks.Encryption.Stream protected override void cipherUpdate(bool isEncrypt, int length, byte[] buf, byte[] outbuf) { - if (_cipher == Table) + if (_cipher == CipherFamily.Table) { var table = isEncrypt ? _encryptTable : _decryptTable; for (int i = 0; i < length; i++) @@ -54,24 +46,24 @@ namespace Shadowsocks.Encryption.Stream outbuf[i] = table[buf[i]]; } } - else if (_cipher == Plain) + else if (_cipher == CipherFamily.Plain) { Array.Copy(buf, outbuf, length); } } - private static readonly Dictionary _ciphers = new Dictionary + private static readonly Dictionary _ciphers = new Dictionary { - {"plain", new EncryptorInfo("PLAIN", 0, 0, Plain) }, - {"table", new EncryptorInfo("TABLE", 0, 0, Table) }, + {"plain", new CipherInfo("plain", 0, 0, CipherFamily.Plain) }, + {"table", new CipherInfo("table", 0, 0, CipherFamily.Table) }, }; - public static IEnumerable SupportedCiphers() + public static Dictionary SupportedCiphers() { - return _ciphers.Keys; + return _ciphers; } - protected override Dictionary getCiphers() + protected override Dictionary getCiphers() { return _ciphers; } diff --git a/shadowsocks-csharp/shadowsocks-csharp.csproj b/shadowsocks-csharp/shadowsocks-csharp.csproj index 2b42076e..2d843e44 100644 --- a/shadowsocks-csharp/shadowsocks-csharp.csproj +++ b/shadowsocks-csharp/shadowsocks-csharp.csproj @@ -11,7 +11,12 @@ 4.1.9.2 Shadowsocks shadowsocks.ico - + Shadowsocks.Program + enable + + + + TRACE @@ -58,26 +63,24 @@ - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - diff --git a/test/CryptographyTest.cs b/test/CryptographyTest.cs index 6b85a82d..189449cf 100644 --- a/test/CryptographyTest.cs +++ b/test/CryptographyTest.cs @@ -11,7 +11,7 @@ namespace Shadowsocks.Test [TestClass] public class CryptographyTest { - + Random random = new Random(); [TestMethod] public void TestMD5() { @@ -19,7 +19,6 @@ namespace Shadowsocks.Test { System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] bytes = new byte[len]; - var random = new Random(); random.NextBytes(bytes); string md5str = Convert.ToBase64String(md5.ComputeHash(bytes)); string md5str2 = Convert.ToBase64String(CryptoUtils.MD5(bytes)); @@ -33,12 +32,12 @@ namespace Shadowsocks.Test byte[] plain = new byte[16384]; byte[] cipher = new byte[plain.Length + 100];// AEAD with IPv4 address type needs +100 byte[] plain2 = new byte[plain.Length + 16]; - int outLen = 0; - int outLen2 = 0; - var random = new Random(); + + //random = new Random(); + random.NextBytes(plain); - encryptor.Encrypt(plain, plain.Length, cipher, out outLen); - decryptor.Decrypt(cipher, outLen, plain2, out outLen2); + encryptor.Encrypt(plain, plain.Length, cipher, out int outLen); + decryptor.Decrypt(cipher, outLen, plain2, out int outLen2); Assert.AreEqual(plain.Length, outLen2); for (int j = 0; j < plain.Length; j++) { @@ -66,15 +65,16 @@ namespace Shadowsocks.Test { var ector = enc.GetConstructor(new Type[] { typeof(string), typeof(string) }); var dctor = dec.GetConstructor(new Type[] { typeof(string), typeof(string) }); - try { - for (int i = 0; i < 100; i++) + IEncryptor encryptor = (IEncryptor)ector.Invoke(new object[] { method, password }); + IEncryptor decryptor = (IEncryptor)dctor.Invoke(new object[] { method, password }); + encryptor.AddressBufferLength = 1 + 4 + 2;// ADDR_ATYP_LEN + 4 + ADDR_PORT_LEN; + decryptor.AddressBufferLength = 1 + 4 + 2;// ADDR_ATYP_LEN + 4 + ADDR_PORT_LEN; + + + for (int i = 0; i < 16; i++) { - IEncryptor encryptor = (IEncryptor)ector.Invoke(new object[] { method, password }); - IEncryptor decryptor = (IEncryptor)dctor.Invoke(new object[] { method, password }); - encryptor.AddrBufLength = 1 + 4 + 2;// ADDR_ATYP_LEN + 4 + ADDR_PORT_LEN; - decryptor.AddrBufLength = 1 + 4 + 2;// ADDR_ATYP_LEN + 4 + ADDR_PORT_LEN; RunEncryptionRound(encryptor, decryptor); } } @@ -98,7 +98,7 @@ namespace Shadowsocks.Test // run it once before the multi-threading test to initialize global tables RunSingleEncryptionThread(enc, dec, method); List threads = new List(); - for (int i = 0; i < 10; i++) + for (int i = 0; i < 8; i++) { Thread t = new Thread(new ThreadStart(() => RunSingleEncryptionThread(enc, dec, method))); threads.Add(t); t.Start(); @@ -114,20 +114,41 @@ namespace Shadowsocks.Test [TestMethod] public void TestBouncyCastleAEADEncryption() { + TestEncryptionMethod(typeof(AEADBouncyCastleEncryptor), "aes-128-gcm"); + TestEncryptionMethod(typeof(AEADBouncyCastleEncryptor), "aes-192-gcm"); TestEncryptionMethod(typeof(AEADBouncyCastleEncryptor), "aes-256-gcm"); } + [TestMethod] + public void TestAesGcmNativeAEADEncryption() + { + TestEncryptionMethod(typeof(AEADAesGcmNativeEncryptor), "aes-128-gcm"); + TestEncryptionMethod(typeof(AEADAesGcmNativeEncryptor), "aes-192-gcm"); + TestEncryptionMethod(typeof(AEADAesGcmNativeEncryptor), "aes-256-gcm"); + } + [TestMethod] public void TestNaClAEADEncryption() { TestEncryptionMethod(typeof(AEADNaClEncryptor), "chacha20-ietf-poly1305"); + TestEncryptionMethod(typeof(AEADNaClEncryptor), "xchacha20-ietf-poly1305"); } [TestMethod] public void TestNativeEncryption() { - //TestEncryptionMethod(typeof(StreamTableNativeEncryptor), "table"); + TestEncryptionMethod(typeof(StreamTableNativeEncryptor), "plain"); + TestEncryptionMethod(typeof(StreamRc4NativeEncryptor), "rc4"); TestEncryptionMethod(typeof(StreamRc4NativeEncryptor), "rc4-md5"); } + + [TestMethod] + public void TestNativeTableEncryption() + { + // Too slow, run once to save CPU + var enc = new StreamTableNativeEncryptor("table", "barfoo!"); + var dec = new StreamTableNativeEncryptor("table", "barfoo!"); + RunEncryptionRound(enc, dec); + } } } \ No newline at end of file