@@ -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<string, EncryptorInfo> _ciphers = new Dictionary<string, EncryptorInfo> | |||
{ | |||
{"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<string, EncryptorInfo> 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); | |||
} | |||
} | |||
} |
@@ -5,8 +5,13 @@ | |||
<package id="Costura.Fody" version="3.3.3" targetFramework="net472" /> | |||
<package id="Fody" version="4.2.1" targetFramework="net472" developmentDependency="true" /> | |||
<package id="GlobalHotKey" version="1.1.0" targetFramework="net472" /> | |||
<package id="NaCl.Core" version="1.2.0" targetFramework="net472" /> | |||
<package id="Newtonsoft.Json" version="12.0.2" targetFramework="net472" /> | |||
<package id="NLog" version="4.6.8" targetFramework="net472" /> | |||
<package id="StringEx.CS" version="0.3.1" targetFramework="net472" developmentDependency="true" /> | |||
<package id="System.Buffers" version="4.4.0" targetFramework="net472" /> | |||
<package id="System.Memory" version="4.5.2" targetFramework="net472" /> | |||
<package id="System.Numerics.Vectors" version="4.4.0" targetFramework="net472" /> | |||
<package id="System.Runtime.CompilerServices.Unsafe" version="4.5.2" targetFramework="net472" /> | |||
<package id="ZXing.Net" version="0.16.5" targetFramework="net472" /> | |||
</packages> |
@@ -66,6 +66,8 @@ | |||
</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="StringEx.CS" Version="0.3.1"> | |||
@@ -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<Thread> threads = new List<Thread>(); | |||
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<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); | |||
} | |||
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 | |||