diff --git a/shadowsocks-csharp/Encryption/Stream/StreamEncryptor.cs b/shadowsocks-csharp/Encryption/Stream/StreamEncryptor.cs index 6dd736be..6c27b9a3 100644 --- a/shadowsocks-csharp/Encryption/Stream/StreamEncryptor.cs +++ b/shadowsocks-csharp/Encryption/Stream/StreamEncryptor.cs @@ -53,7 +53,8 @@ namespace Shadowsocks.Encryption.Stream CipherInfo = ciphers[_method]; _innerLibName = CipherInfo.InnerLibName; _cipher = CipherInfo.Type; - if (_cipher == 0) { + if (_cipher == 0) + { throw new System.Exception("method not found"); } keyLen = CipherInfo.KeySize; @@ -73,10 +74,14 @@ namespace Shadowsocks.Encryption.Stream byte[] result = new byte[password.Length + MD5_LEN]; int i = 0; byte[] md5sum = null; - while (i < keylen) { - if (i == 0) { + while (i < keylen) + { + if (i == 0) + { md5sum = CryptoUtils.MD5(password); - } else { + } + else + { Array.Copy(md5sum, 0, result, 0, MD5_LEN); Array.Copy(password, 0, result, MD5_LEN, password.Length); md5sum = CryptoUtils.MD5(result); @@ -88,10 +93,13 @@ namespace Shadowsocks.Encryption.Stream protected virtual void initCipher(byte[] iv, bool isEncrypt) { - if (isEncrypt) { + if (isEncrypt) + { _encryptIV = new byte[ivLen]; Array.Copy(iv, _encryptIV, ivLen); - } else { + } + else + { _decryptIV = new byte[ivLen]; Array.Copy(iv, _decryptIV, ivLen); } @@ -108,12 +116,13 @@ namespace Shadowsocks.Encryption.Stream int cipherOffset = 0; Debug.Assert(_encCircularBuffer != null, "_encCircularBuffer != null"); _encCircularBuffer.Put(buf, 0, length); - if (! _encryptIVSent) { + if (!_encryptIVSent) + { // Generate IV byte[] ivBytes = new byte[ivLen]; randBytes(ivBytes, ivLen); initCipher(ivBytes, true); - + Array.Copy(ivBytes, 0, outbuf, 0, ivLen); cipherOffset = ivLen; _encryptIVSent = true; @@ -130,16 +139,22 @@ namespace Shadowsocks.Encryption.Stream { Debug.Assert(_decCircularBuffer != null, "_circularBuffer != null"); _decCircularBuffer.Put(buf, 0, length); - if (! _decryptIVReceived) { - if (_decCircularBuffer.Size <= ivLen) { + if (!_decryptIVReceived) + { + if (_decCircularBuffer.Size <= ivLen) + { // we need more data outlength = 0; return; } // start decryption _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(), false); } byte[] cipher = _decCircularBuffer.ToArray(); cipherUpdate(false, cipher.Length, cipher, outbuf); @@ -158,7 +173,8 @@ namespace Shadowsocks.Encryption.Stream // Generate IV randBytes(outbuf, ivLen); initCipher(outbuf, true); - lock (_udpTmpBuf) { + lock (_udpTmpBuf) + { cipherUpdate(true, length, buf, _udpTmpBuf); outlength = length + ivLen; Buffer.BlockCopy(_udpTmpBuf, 0, outbuf, ivLen, length); @@ -170,7 +186,8 @@ namespace Shadowsocks.Encryption.Stream // Get IV from first pos initCipher(buf, false); outlength = length - ivLen; - lock (_udpTmpBuf) { + lock (_udpTmpBuf) + { // C# could be multi-threaded Buffer.BlockCopy(buf, ivLen, _udpTmpBuf, 0, length - ivLen); cipherUpdate(false, length - ivLen, _udpTmpBuf, outbuf); diff --git a/test/CryptographyTest.cs b/test/CryptographyTest.cs index dce5360d..6b85a82d 100644 --- a/test/CryptographyTest.cs +++ b/test/CryptographyTest.cs @@ -1,6 +1,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Shadowsocks.Encryption; using Shadowsocks.Encryption.Stream; +using Shadowsocks.Encryption.AEAD; using System; using System.Collections.Generic; 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 threads = new List(); - 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 { 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; - decryptor = new Encryption.AEAD.AEADBouncyCastleEncryptor("aes-256-gcm", "barfoo!"); decryptor.AddrBufLength = 1 + 4 + 2;// ADDR_ATYP_LEN + 4 + ADDR_PORT_LEN; 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; + // run it once before the multi-threading test to initialize global tables - RunSingleNaClAEADEncryptionThread(); + RunSingleEncryptionThread(enc, dec, method); List threads = new List(); 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(); } foreach (Thread t in threads) @@ -125,68 +111,23 @@ namespace Shadowsocks.Test 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] - public void TestNativeEncryption() + public void TestNaClAEADEncryption() { - encryptionFailed = false; - // run it once before the multi-threading test to initialize global tables - RunSingleNativeEncryptionThread(); - List threads = new List(); - 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"); } } } \ No newline at end of file