diff --git a/shadowsocks-csharp/Encryption/AEAD/AEADNaClEncryptor.cs b/shadowsocks-csharp/Encryption/AEAD/AEADNaClEncryptor.cs new file mode 100644 index 00000000..dc58bffb --- /dev/null +++ b/shadowsocks-csharp/Encryption/AEAD/AEADNaClEncryptor.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using NaCl.Core; +using NaCl.Core.Base; + +namespace Shadowsocks.Encryption.AEAD +{ + public class AEADNaClEncryptor : AEADEncryptor + { + + SnufflePoly1305 enc; + SnufflePoly1305 dec; + public AEADNaClEncryptor(string method, string password) : base(method, password) + { + + } + + public override void InitCipher(byte[] salt, bool isEncrypt, bool isUdp) + { + base.InitCipher(salt, isEncrypt, isUdp); + DeriveSessionKey(isEncrypt ? encryptSalt : decryptSalt, + _Masterkey, sessionKey); + + SnufflePoly1305 tmp; + switch (_cipher) + { + default: + case CipherChaCha20Poly1305: + tmp = new ChaCha20Poly1305(sessionKey); + break; + case CipherXChaCha20Poly1305: + tmp = new XChaCha20Poly1305(sessionKey); + break; + } + if (isEncrypt) enc = tmp; + else dec = tmp; + } + + public override void cipherDecrypt(byte[] ciphertext, uint clen, byte[] plaintext, ref uint plen) + { + var pt = dec.Decrypt(ciphertext, null, decNonce); + pt.CopyTo(plaintext, 0); + plen = (uint)pt.Length; + } + + public override void cipherEncrypt(byte[] plaintext, uint plen, byte[] ciphertext, ref uint clen) + { + var ct = enc.Encrypt(plaintext, null, encNonce); + ct.CopyTo(ciphertext, 0); + clen = (uint)ct.Length; + } + + public override void Dispose() + { + } + + const int CipherChaCha20Poly1305 = 1; + const int CipherXChaCha20Poly1305 = 2; + + private static readonly Dictionary _ciphers = new Dictionary + { + {"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)}, + }; + + protected override Dictionary getCiphers() + { + return _ciphers; + } + + public override byte[] CipherEncrypt2(byte[] plain) + { + return enc.Encrypt(plain, null, encNonce); + } + + public override byte[] CipherDecrypt2(byte[] cipher) + { + return dec.Decrypt(cipher, null, decNonce); + } + } +} diff --git a/shadowsocks-csharp/packages.config b/shadowsocks-csharp/packages.config index 97b73835..f10f1e05 100644 --- a/shadowsocks-csharp/packages.config +++ b/shadowsocks-csharp/packages.config @@ -5,8 +5,13 @@ + + + + + \ No newline at end of file diff --git a/shadowsocks-csharp/shadowsocks-csharp.csproj b/shadowsocks-csharp/shadowsocks-csharp.csproj index 2926983a..2b42076e 100644 --- a/shadowsocks-csharp/shadowsocks-csharp.csproj +++ b/shadowsocks-csharp/shadowsocks-csharp.csproj @@ -66,6 +66,8 @@ + + diff --git a/test/CryptographyTest.cs b/test/CryptographyTest.cs index 4e9dc046..dce5360d 100644 --- a/test/CryptographyTest.cs +++ b/test/CryptographyTest.cs @@ -82,17 +82,39 @@ namespace Shadowsocks.Test Assert.IsFalse(encryptionFailed); } + 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!"); + 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); + } + } + catch + { + encryptionFailed = true; + throw; + } + } + [TestMethod] - public void TestNativeEncryption() + public void TesNaClAEADEncryption() { encryptionFailed = false; // run it once before the multi-threading test to initialize global tables - RunSingleNativeEncryptionThread(); + RunSingleNaClAEADEncryptionThread(); List threads = new List(); for (int i = 0; i < 10; i++) { - Thread t = new Thread(new ThreadStart(RunSingleNativeEncryptionThread)); - threads.Add(t); + Thread t = new Thread(new ThreadStart(RunSingleNaClAEADEncryptionThread)); threads.Add(t); t.Start(); } foreach (Thread t in threads) @@ -103,17 +125,20 @@ namespace Shadowsocks.Test Assert.IsFalse(encryptionFailed); } - private void RunSingleNativeEncryptionThread() + private void RunSingleNaClAEADEncryptionThread() { 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); + 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 @@ -123,20 +148,38 @@ namespace Shadowsocks.Test } } - private void RunSingleBouncyCastleAEADEncryptionThread() + [TestMethod] + public void TestNativeEncryption() + { + 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); + } + + private void RunSingleNativeEncryptionThread() { 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!"); - encryptor.AddrBufLength = 1 + 4 + 2;// ADDR_ATYP_LEN + 4 + ADDR_PORT_LEN; - decryptor = new Encryption.AEAD.AEADAesGcmNativeEncryptor("aes-256-gcm", "barfoo!"); - decryptor.AddrBufLength = 1 + 4 + 2;// ADDR_ATYP_LEN + 4 + ADDR_PORT_LEN; - RunEncryptionRound(encryptor, decryptor); + IEncryptor encryptorN; + IEncryptor decryptorN; + encryptorN = new StreamRc4NativeEncryptor("rc4-md5", "barfoo!"); + decryptorN = new StreamRc4NativeEncryptor("rc4-md5", "barfoo!"); + RunEncryptionRound(encryptorN, decryptorN); } } catch