| @@ -53,7 +53,8 @@ namespace Shadowsocks.Encryption.Stream | |||||
| CipherInfo = ciphers[_method]; | CipherInfo = ciphers[_method]; | ||||
| _innerLibName = CipherInfo.InnerLibName; | _innerLibName = CipherInfo.InnerLibName; | ||||
| _cipher = CipherInfo.Type; | _cipher = CipherInfo.Type; | ||||
| if (_cipher == 0) { | |||||
| if (_cipher == 0) | |||||
| { | |||||
| throw new System.Exception("method not found"); | throw new System.Exception("method not found"); | ||||
| } | } | ||||
| keyLen = CipherInfo.KeySize; | keyLen = CipherInfo.KeySize; | ||||
| @@ -73,10 +74,14 @@ namespace Shadowsocks.Encryption.Stream | |||||
| byte[] result = new byte[password.Length + MD5_LEN]; | byte[] result = new byte[password.Length + MD5_LEN]; | ||||
| int i = 0; | int i = 0; | ||||
| byte[] md5sum = null; | byte[] md5sum = null; | ||||
| while (i < keylen) { | |||||
| if (i == 0) { | |||||
| while (i < keylen) | |||||
| { | |||||
| if (i == 0) | |||||
| { | |||||
| md5sum = CryptoUtils.MD5(password); | md5sum = CryptoUtils.MD5(password); | ||||
| } else { | |||||
| } | |||||
| else | |||||
| { | |||||
| Array.Copy(md5sum, 0, result, 0, MD5_LEN); | Array.Copy(md5sum, 0, result, 0, MD5_LEN); | ||||
| Array.Copy(password, 0, result, MD5_LEN, password.Length); | Array.Copy(password, 0, result, MD5_LEN, password.Length); | ||||
| md5sum = CryptoUtils.MD5(result); | md5sum = CryptoUtils.MD5(result); | ||||
| @@ -88,10 +93,13 @@ namespace Shadowsocks.Encryption.Stream | |||||
| protected virtual void initCipher(byte[] iv, bool isEncrypt) | protected virtual void initCipher(byte[] iv, bool isEncrypt) | ||||
| { | { | ||||
| if (isEncrypt) { | |||||
| if (isEncrypt) | |||||
| { | |||||
| _encryptIV = new byte[ivLen]; | _encryptIV = new byte[ivLen]; | ||||
| Array.Copy(iv, _encryptIV, ivLen); | Array.Copy(iv, _encryptIV, ivLen); | ||||
| } else { | |||||
| } | |||||
| else | |||||
| { | |||||
| _decryptIV = new byte[ivLen]; | _decryptIV = new byte[ivLen]; | ||||
| Array.Copy(iv, _decryptIV, ivLen); | Array.Copy(iv, _decryptIV, ivLen); | ||||
| } | } | ||||
| @@ -108,12 +116,13 @@ namespace Shadowsocks.Encryption.Stream | |||||
| int cipherOffset = 0; | int cipherOffset = 0; | ||||
| Debug.Assert(_encCircularBuffer != null, "_encCircularBuffer != null"); | Debug.Assert(_encCircularBuffer != null, "_encCircularBuffer != null"); | ||||
| _encCircularBuffer.Put(buf, 0, length); | _encCircularBuffer.Put(buf, 0, length); | ||||
| if (! _encryptIVSent) { | |||||
| if (!_encryptIVSent) | |||||
| { | |||||
| // Generate IV | // Generate IV | ||||
| byte[] ivBytes = new byte[ivLen]; | byte[] ivBytes = new byte[ivLen]; | ||||
| randBytes(ivBytes, ivLen); | randBytes(ivBytes, ivLen); | ||||
| initCipher(ivBytes, true); | initCipher(ivBytes, true); | ||||
| Array.Copy(ivBytes, 0, outbuf, 0, ivLen); | Array.Copy(ivBytes, 0, outbuf, 0, ivLen); | ||||
| cipherOffset = ivLen; | cipherOffset = ivLen; | ||||
| _encryptIVSent = true; | _encryptIVSent = true; | ||||
| @@ -130,16 +139,22 @@ namespace Shadowsocks.Encryption.Stream | |||||
| { | { | ||||
| Debug.Assert(_decCircularBuffer != null, "_circularBuffer != null"); | Debug.Assert(_decCircularBuffer != null, "_circularBuffer != null"); | ||||
| _decCircularBuffer.Put(buf, 0, length); | _decCircularBuffer.Put(buf, 0, length); | ||||
| if (! _decryptIVReceived) { | |||||
| if (_decCircularBuffer.Size <= ivLen) { | |||||
| if (!_decryptIVReceived) | |||||
| { | |||||
| if (_decCircularBuffer.Size <= ivLen) | |||||
| { | |||||
| // we need more data | // we need more data | ||||
| outlength = 0; | outlength = 0; | ||||
| return; | return; | ||||
| } | } | ||||
| // start decryption | // start decryption | ||||
| _decryptIVReceived = true; | _decryptIVReceived = true; | ||||
| byte[] iv = _decCircularBuffer.Get(ivLen); | |||||
| initCipher(iv, false); | |||||
| if (ivLen > 0) | |||||
| { | |||||
| byte[] iv = _decCircularBuffer.Get(ivLen); | |||||
| initCipher(iv, false); | |||||
| } | |||||
| else initCipher(Array.Empty<byte>(), false); | |||||
| } | } | ||||
| byte[] cipher = _decCircularBuffer.ToArray(); | byte[] cipher = _decCircularBuffer.ToArray(); | ||||
| cipherUpdate(false, cipher.Length, cipher, outbuf); | cipherUpdate(false, cipher.Length, cipher, outbuf); | ||||
| @@ -158,7 +173,8 @@ namespace Shadowsocks.Encryption.Stream | |||||
| // Generate IV | // Generate IV | ||||
| randBytes(outbuf, ivLen); | randBytes(outbuf, ivLen); | ||||
| initCipher(outbuf, true); | initCipher(outbuf, true); | ||||
| lock (_udpTmpBuf) { | |||||
| lock (_udpTmpBuf) | |||||
| { | |||||
| cipherUpdate(true, length, buf, _udpTmpBuf); | cipherUpdate(true, length, buf, _udpTmpBuf); | ||||
| outlength = length + ivLen; | outlength = length + ivLen; | ||||
| Buffer.BlockCopy(_udpTmpBuf, 0, outbuf, ivLen, length); | Buffer.BlockCopy(_udpTmpBuf, 0, outbuf, ivLen, length); | ||||
| @@ -170,7 +186,8 @@ namespace Shadowsocks.Encryption.Stream | |||||
| // Get IV from first pos | // Get IV from first pos | ||||
| initCipher(buf, false); | initCipher(buf, false); | ||||
| outlength = length - ivLen; | outlength = length - ivLen; | ||||
| lock (_udpTmpBuf) { | |||||
| lock (_udpTmpBuf) | |||||
| { | |||||
| // C# could be multi-threaded | // C# could be multi-threaded | ||||
| Buffer.BlockCopy(buf, ivLen, _udpTmpBuf, 0, length - ivLen); | Buffer.BlockCopy(buf, ivLen, _udpTmpBuf, 0, length - ivLen); | ||||
| cipherUpdate(false, length - ivLen, _udpTmpBuf, outbuf); | cipherUpdate(false, length - ivLen, _udpTmpBuf, outbuf); | ||||
| @@ -1,6 +1,7 @@ | |||||
| using Microsoft.VisualStudio.TestTools.UnitTesting; | using Microsoft.VisualStudio.TestTools.UnitTesting; | ||||
| using Shadowsocks.Encryption; | using Shadowsocks.Encryption; | ||||
| using Shadowsocks.Encryption.Stream; | using Shadowsocks.Encryption.Stream; | ||||
| using Shadowsocks.Encryption.AEAD; | |||||
| using System; | using System; | ||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| using System.Threading; | using System.Threading; | ||||
| @@ -59,41 +60,20 @@ namespace Shadowsocks.Test | |||||
| } | } | ||||
| } | } | ||||
| private static bool encryptionFailed = false; | |||||
| private static object locker = new object(); | |||||
| const string password = "barfoo!"; | |||||
| [TestMethod] | |||||
| public void TestBouncyCastleAEADEncryption() | |||||
| private void RunSingleEncryptionThread(Type enc, Type dec, string method) | |||||
| { | { | ||||
| encryptionFailed = false; | |||||
| // run it once before the multi-threading test to initialize global tables | |||||
| RunSingleBouncyCastleAEADEncryptionThread(); | |||||
| List<Thread> threads = new List<Thread>(); | |||||
| for (int i = 0; i < 10; i++) | |||||
| { | |||||
| Thread t = new Thread(new ThreadStart(RunSingleBouncyCastleAEADEncryptionThread)); threads.Add(t); | |||||
| t.Start(); | |||||
| } | |||||
| foreach (Thread t in threads) | |||||
| { | |||||
| t.Join(); | |||||
| } | |||||
| RNG.Close(); | |||||
| Assert.IsFalse(encryptionFailed); | |||||
| } | |||||
| var ector = enc.GetConstructor(new Type[] { typeof(string), typeof(string) }); | |||||
| var dctor = dec.GetConstructor(new Type[] { typeof(string), typeof(string) }); | |||||
| private void RunSingleBouncyCastleAEADEncryptionThread() | |||||
| { | |||||
| try | try | ||||
| { | { | ||||
| for (int i = 0; i < 100; i++) | for (int i = 0; i < 100; i++) | ||||
| { | { | ||||
| var random = new Random(); | |||||
| IEncryptor encryptor; | |||||
| IEncryptor decryptor; | |||||
| encryptor = new Encryption.AEAD.AEADBouncyCastleEncryptor("aes-256-gcm", "barfoo!"); | |||||
| 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; | encryptor.AddrBufLength = 1 + 4 + 2;// ADDR_ATYP_LEN + 4 + ADDR_PORT_LEN; | ||||
| decryptor = new Encryption.AEAD.AEADBouncyCastleEncryptor("aes-256-gcm", "barfoo!"); | |||||
| decryptor.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); | RunEncryptionRound(encryptor, decryptor); | ||||
| } | } | ||||
| @@ -105,16 +85,22 @@ namespace Shadowsocks.Test | |||||
| } | } | ||||
| } | } | ||||
| [TestMethod] | |||||
| public void TesNaClAEADEncryption() | |||||
| private static bool encryptionFailed = false; | |||||
| private void TestEncryptionMethod(Type enc, string method) | |||||
| { | |||||
| TestEncryptionMethod(enc, enc, method); | |||||
| } | |||||
| private void TestEncryptionMethod(Type enc, Type dec, string method) | |||||
| { | { | ||||
| encryptionFailed = false; | encryptionFailed = false; | ||||
| // run it once before the multi-threading test to initialize global tables | // run it once before the multi-threading test to initialize global tables | ||||
| RunSingleNaClAEADEncryptionThread(); | |||||
| RunSingleEncryptionThread(enc, dec, method); | |||||
| List<Thread> threads = new List<Thread>(); | List<Thread> threads = new List<Thread>(); | ||||
| for (int i = 0; i < 10; i++) | for (int i = 0; i < 10; i++) | ||||
| { | { | ||||
| Thread t = new Thread(new ThreadStart(RunSingleNaClAEADEncryptionThread)); threads.Add(t); | |||||
| Thread t = new Thread(new ThreadStart(() => RunSingleEncryptionThread(enc, dec, method))); threads.Add(t); | |||||
| t.Start(); | t.Start(); | ||||
| } | } | ||||
| foreach (Thread t in threads) | foreach (Thread t in threads) | ||||
| @@ -125,68 +111,23 @@ namespace Shadowsocks.Test | |||||
| Assert.IsFalse(encryptionFailed); | Assert.IsFalse(encryptionFailed); | ||||
| } | } | ||||
| private void RunSingleNaClAEADEncryptionThread() | |||||
| [TestMethod] | |||||
| public void TestBouncyCastleAEADEncryption() | |||||
| { | { | ||||
| try | |||||
| { | |||||
| for (int i = 0; i < 100; i++) | |||||
| { | |||||
| var random = new Random(); | |||||
| IEncryptor encryptor; | |||||
| IEncryptor decryptor; | |||||
| encryptor = new Encryption.AEAD.AEADNaClEncryptor("chacha20-ietf-poly1305", "barfoo!"); | |||||
| encryptor.AddrBufLength = 1 + 4 + 2;// ADDR_ATYP_LEN + 4 + ADDR_PORT_LEN; | |||||
| decryptor = new Encryption.AEAD.AEADNaClEncryptor("chacha20-ietf-poly1305", "barfoo!"); | |||||
| decryptor.AddrBufLength = 1 + 4 + 2;// ADDR_ATYP_LEN + 4 + ADDR_PORT_LEN; | |||||
| RunEncryptionRound(encryptor, decryptor); | |||||
| } | |||||
| } | |||||
| catch | |||||
| { | |||||
| encryptionFailed = true; | |||||
| throw; | |||||
| } | |||||
| TestEncryptionMethod(typeof(AEADBouncyCastleEncryptor), "aes-256-gcm"); | |||||
| } | } | ||||
| [TestMethod] | [TestMethod] | ||||
| public void TestNativeEncryption() | |||||
| public void TestNaClAEADEncryption() | |||||
| { | { | ||||
| encryptionFailed = false; | |||||
| // run it once before the multi-threading test to initialize global tables | |||||
| RunSingleNativeEncryptionThread(); | |||||
| List<Thread> threads = new List<Thread>(); | |||||
| for (int i = 0; i < 10; i++) | |||||
| { | |||||
| Thread t = new Thread(new ThreadStart(RunSingleNativeEncryptionThread)); | |||||
| threads.Add(t); | |||||
| t.Start(); | |||||
| } | |||||
| foreach (Thread t in threads) | |||||
| { | |||||
| t.Join(); | |||||
| } | |||||
| RNG.Close(); | |||||
| Assert.IsFalse(encryptionFailed); | |||||
| TestEncryptionMethod(typeof(AEADNaClEncryptor), "chacha20-ietf-poly1305"); | |||||
| } | } | ||||
| private void RunSingleNativeEncryptionThread() | |||||
| [TestMethod] | |||||
| public void TestNativeEncryption() | |||||
| { | { | ||||
| try | |||||
| { | |||||
| for (int i = 0; i < 100; i++) | |||||
| { | |||||
| IEncryptor encryptorN; | |||||
| IEncryptor decryptorN; | |||||
| encryptorN = new StreamRc4NativeEncryptor("rc4-md5", "barfoo!"); | |||||
| decryptorN = new StreamRc4NativeEncryptor("rc4-md5", "barfoo!"); | |||||
| RunEncryptionRound(encryptorN, decryptorN); | |||||
| } | |||||
| } | |||||
| catch | |||||
| { | |||||
| encryptionFailed = true; | |||||
| throw; | |||||
| } | |||||
| //TestEncryptionMethod(typeof(StreamTableNativeEncryptor), "table"); | |||||
| TestEncryptionMethod(typeof(StreamRc4NativeEncryptor), "rc4-md5"); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||