diff --git a/shadowsocks-csharp/Encryption/EncryptorFactory.cs b/shadowsocks-csharp/Encryption/EncryptorFactory.cs index 534c66d8..1b627b38 100644 --- a/shadowsocks-csharp/Encryption/EncryptorFactory.cs +++ b/shadowsocks-csharp/Encryption/EncryptorFactory.cs @@ -41,6 +41,14 @@ namespace Shadowsocks.Encryption _registeredEncryptors.Add(method.Key, typeof(StreamAesBouncyCastleEncryptor)); } } + foreach (var method in StreamChachaNaClEncryptor.SupportedCiphers()) + { + if (!_registeredEncryptors.ContainsKey(method.Key)) + { + ciphers.Add(method.Key, method.Value); + _registeredEncryptors.Add(method.Key, typeof(StreamChachaNaClEncryptor)); + } + } foreach (var method in AEADAesGcmNativeEncryptor.SupportedCiphers()) diff --git a/shadowsocks-csharp/Encryption/Stream/StreamChachaNaClEncryptor.cs b/shadowsocks-csharp/Encryption/Stream/StreamChachaNaClEncryptor.cs new file mode 100644 index 00000000..fc419d3e --- /dev/null +++ b/shadowsocks-csharp/Encryption/Stream/StreamChachaNaClEncryptor.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Text; +using NaCl.Core; + +namespace Shadowsocks.Encryption.Stream +{ + public class StreamChachaNaClEncryptor : StreamEncryptor + { + ChaCha20 c; + public StreamChachaNaClEncryptor(string method, string password) : base(method, password) + { + c = new ChaCha20(key, 0); + } + + protected override int CipherDecrypt(Span plain, Span cipher) + { + var p = c.Decrypt(cipher, iv); + p.CopyTo(plain); + return p.Length; + } + + protected override int CipherEncrypt(Span plain, Span cipher) + { + var e = c.Encrypt(plain, iv); + e.CopyTo(cipher); + return e.Length; + } + + protected override void cipherUpdate(bool isEncrypt, int length, byte[] buf, byte[] outbuf) + { + var i = buf.AsSpan().Slice(0, length); + if (isEncrypt) + { + CipherEncrypt(i, outbuf); + } + else + { + CipherDecrypt(outbuf, i); + } + } + + #region Ciphers + private static readonly Dictionary _ciphers = new Dictionary + { + { "chacha20-ietf", new CipherInfo("chacha20-ietf", 32, 12, CipherFamily.Chacha20) }, + }; + public static Dictionary SupportedCiphers() + { + return _ciphers; + } + + protected override Dictionary getCiphers() + { + return _ciphers; + } + #endregion + } +} diff --git a/test/CryptographyTest.cs b/test/CryptographyTest.cs index ea68995c..599023d4 100644 --- a/test/CryptographyTest.cs +++ b/test/CryptographyTest.cs @@ -165,5 +165,10 @@ namespace Shadowsocks.Test { TestEncryptionMethod(typeof(StreamAesBouncyCastleEncryptor), "aes-256-cfb"); } + [TestMethod] + public void TestStreamChachaNaClEncryption() + { + TestEncryptionMethod(typeof(StreamChachaNaClEncryptor), "chacha20-ietf"); + } } } \ No newline at end of file