@@ -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() | |||
@@ -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<string, EncryptorInfo> _ciphers = new Dictionary<string, EncryptorInfo> | |||
private static readonly Dictionary<string, CipherInfo> _ciphers = new Dictionary<string, CipherInfo> | |||
{ | |||
{"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<string, EncryptorInfo> getCiphers() | |||
protected override Dictionary<string, CipherInfo> getCiphers() | |||
{ | |||
return _ciphers; | |||
} | |||
@@ -102,13 +101,9 @@ namespace Shadowsocks.Encryption.AEAD | |||
return d.ToArray(); | |||
} | |||
public static List<string> SupportedCiphers() | |||
{ | |||
return new List<string>(_ciphers.Keys); | |||
} | |||
public override void Dispose() | |||
public static Dictionary<string, CipherInfo> SupportedCiphers() | |||
{ | |||
return _ciphers; | |||
} | |||
} | |||
} |
@@ -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<string, EncryptorInfo> _ciphers = new Dictionary<string, EncryptorInfo> | |||
private static readonly Dictionary<string, CipherInfo> _ciphers = new Dictionary<string, CipherInfo> | |||
{ | |||
{"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<string, EncryptorInfo> getCiphers() | |||
protected override Dictionary<string, CipherInfo> getCiphers() | |||
{ | |||
return _ciphers; | |||
} | |||
@@ -90,14 +87,10 @@ namespace Shadowsocks.Encryption.AEAD | |||
aes.DoFinal(cipher, len); | |||
return cipher; | |||
} | |||
public static List<string> SupportedCiphers() | |||
{ | |||
return new List<string>(_ciphers.Keys); | |||
} | |||
public override void Dispose() | |||
public static Dictionary<string, CipherInfo> SupportedCiphers() | |||
{ | |||
return _ciphers; | |||
} | |||
} | |||
} |
@@ -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<string, EncryptorInfo> ciphers; | |||
protected Dictionary<string, CipherInfo> 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<string, EncryptorInfo> getCiphers(); | |||
protected abstract Dictionary<string, CipherInfo> 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}"); | |||
@@ -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<string, CipherInfo> _ciphers = new Dictionary<string, CipherInfo> | |||
{ | |||
} | |||
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<string, EncryptorInfo> _ciphers = new Dictionary<string, EncryptorInfo> | |||
protected override Dictionary<string, CipherInfo> 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<string, EncryptorInfo> getCiphers() | |||
public static Dictionary<string, CipherInfo> 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) | |||
@@ -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<string, EncryptorInfo> _ciphers = new Dictionary<string, EncryptorInfo>() | |||
{ | |||
{"plain-fake-aead",new EncryptorInfo("PLAIN_AEAD",0,0,0,0,0) } | |||
}; | |||
protected override Dictionary<string, EncryptorInfo> getCiphers() | |||
{ | |||
return _ciphers; | |||
} | |||
public static IEnumerable<string> SupportedCiphers() | |||
{ | |||
return _ciphers.Keys; | |||
} | |||
public override byte[] CipherEncrypt2(byte[] plain) | |||
{ | |||
return plain; | |||
} | |||
public override byte[] CipherDecrypt2(byte[] cipher) | |||
{ | |||
return cipher; | |||
} | |||
} | |||
} |
@@ -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 | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -10,27 +10,51 @@ namespace Shadowsocks.Encryption | |||
public static class EncryptorFactory | |||
{ | |||
private static Dictionary<string, Type> _registeredEncryptors = new Dictionary<string, Type>(); | |||
private static Dictionary<string, CipherInfo> ciphers = new Dictionary<string, CipherInfo>(); | |||
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)); | |||
} | |||
} | |||
} | |||
@@ -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); | |||
@@ -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<string, EncryptorInfo> ciphers; | |||
protected Dictionary<string, CipherInfo> 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<string, EncryptorInfo> getCiphers(); | |||
protected abstract Dictionary<string, CipherInfo> 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) | |||
@@ -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<string, EncryptorInfo> _ciphers = new Dictionary<string, EncryptorInfo> | |||
private static readonly Dictionary<string, CipherInfo> _ciphers = new Dictionary<string, CipherInfo> | |||
{ | |||
// 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<string> SupportedCiphers() | |||
public static Dictionary<string, CipherInfo> SupportedCiphers() | |||
{ | |||
return _ciphers.Keys; | |||
return _ciphers; | |||
} | |||
protected override Dictionary<string, EncryptorInfo> getCiphers() | |||
protected override Dictionary<string, CipherInfo> getCiphers() | |||
{ | |||
return _ciphers; | |||
} | |||
@@ -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<string, EncryptorInfo> _ciphers = new Dictionary<string, EncryptorInfo> | |||
private static readonly Dictionary<string, CipherInfo> _ciphers = new Dictionary<string, CipherInfo> | |||
{ | |||
{"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<string> SupportedCiphers() | |||
public static Dictionary<string, CipherInfo> SupportedCiphers() | |||
{ | |||
return _ciphers.Keys; | |||
return _ciphers; | |||
} | |||
protected override Dictionary<string, EncryptorInfo> getCiphers() | |||
protected override Dictionary<string, CipherInfo> getCiphers() | |||
{ | |||
return _ciphers; | |||
} | |||
@@ -11,7 +11,12 @@ | |||
<Version>4.1.9.2</Version> | |||
<AssemblyName>Shadowsocks</AssemblyName> | |||
<ApplicationIcon>shadowsocks.ico</ApplicationIcon> | |||
<StartupObject /> | |||
<StartupObject>Shadowsocks.Program</StartupObject> | |||
<Nullable>enable</Nullable> | |||
</PropertyGroup> | |||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> | |||
<DefineConstants>TRACE</DefineConstants> | |||
</PropertyGroup> | |||
<ItemGroup> | |||
@@ -58,26 +63,24 @@ | |||
</ItemGroup> | |||
<ItemGroup> | |||
<PackageReference Include="BouncyCastle.NetCore" Version="1.8.5" /> | |||
<PackageReference Include="Caseless.Fody" Version="1.9.0" /> | |||
<!--PackageReference Include="Caseless.Fody" Version="1.9.0" /> | |||
<PackageReference Include="Costura.Fody" Version="4.1.0" /> | |||
<PackageReference Include="Fody" Version="6.1.1"> | |||
<PrivateAssets>all</PrivateAssets> | |||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> | |||
</PackageReference> | |||
</PackageReference--> | |||
<PackageReference Include="Microsoft.VisualBasic" Version="10.3.0" /> | |||
<PackageReference Include="NaCl.Core" Version="1.2.0" /> | |||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> | |||
<PackageReference Include="NLog" Version="4.6.8" /> | |||
<PackageReference Include="ZXing.Net" Version="0.16.5" /> | |||
<PackageReference Include="StringEx.CS" Version="0.3.1"> | |||
<PrivateAssets>all</PrivateAssets> | |||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> | |||
</PackageReference> | |||
<PackageReference Include="System.Data.SqlClient" Version="4.8.1" /> | |||
<PackageReference Include="System.Management" Version="4.7.0" /> | |||
<PackageReference Include="ZXing.Net" Version="0.16.5" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
@@ -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<Thread> threads = new List<Thread>(); | |||
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); | |||
} | |||
} | |||
} |