diff --git a/shadowsocks-csharp/Encryption/AEAD/AEADAesGcmNativeEncryptor.cs b/shadowsocks-csharp/Encryption/AEAD/AEADAesGcmNativeEncryptor.cs index 788f3544..882519d9 100644 --- a/shadowsocks-csharp/Encryption/AEAD/AEADAesGcmNativeEncryptor.cs +++ b/shadowsocks-csharp/Encryption/AEAD/AEADAesGcmNativeEncryptor.cs @@ -18,7 +18,7 @@ namespace Shadowsocks.Encryption.AEAD {"aes-256-gcm", new CipherInfo("aes-256-gcm", 32, 32, 12, 16, CipherFamily.AesGcm)}, }; - protected override Dictionary getCiphers() + protected override Dictionary GetCiphers() { return _ciphers; } @@ -32,7 +32,7 @@ namespace Shadowsocks.Encryption.AEAD public override int CipherEncrypt(ReadOnlySpan plain, Span cipher) { using AesGcm aes = new AesGcm(sessionKey); - aes.Encrypt(nonce.AsSpan(), plain, cipher.Slice(0, plain.Length), cipher.Slice(plain.Length, tagLen)); + aes.Encrypt(nonce, plain, cipher.Slice(0, plain.Length), cipher.Slice(plain.Length, tagLen)); return plain.Length + tagLen; } @@ -42,7 +42,7 @@ namespace Shadowsocks.Encryption.AEAD using AesGcm aes = new AesGcm(sessionKey); ReadOnlySpan ciphertxt = cipher.Slice(0, clen); ReadOnlySpan tag = cipher.Slice(clen); - aes.Decrypt(nonce.AsSpan(), ciphertxt, tag, plain.Slice(0, clen)); + aes.Decrypt(nonce, ciphertxt, tag, plain.Slice(0, clen)); return clen; } } diff --git a/shadowsocks-csharp/Encryption/AEAD/AEADEncryptor.cs b/shadowsocks-csharp/Encryption/AEAD/AEADEncryptor.cs index af9a50de..7e3f5fe7 100644 --- a/shadowsocks-csharp/Encryption/AEAD/AEADEncryptor.cs +++ b/shadowsocks-csharp/Encryption/AEAD/AEADEncryptor.cs @@ -5,26 +5,25 @@ using Shadowsocks.Encryption.Stream; using System; using System.Collections.Generic; using System.Net; +using System.Runtime.CompilerServices; using System.Text; namespace Shadowsocks.Encryption.AEAD { public abstract class AEADEncryptor : EncryptorBase { - private static Logger logger = LogManager.GetCurrentClassLogger(); + private static readonly Logger logger = LogManager.GetCurrentClassLogger(); // We are using the same saltLen and keyLen private const string Info = "ss-subkey"; private static readonly byte[] InfoBytes = Encoding.ASCII.GetBytes(Info); // every connection should create its own buffer - private byte[] sharedBuffer = new byte[65536]; + private readonly byte[] buffer = new byte[65536]; private int bufPtr = 0; public const int ChunkLengthBytes = 2; public const uint ChunkLengthMask = 0x3FFFu; - protected Dictionary ciphers; - protected CipherFamily cipherFamily; protected CipherInfo CipherInfo; protected static byte[] masterKey = Array.Empty(); @@ -46,7 +45,7 @@ namespace Shadowsocks.Encryption.AEAD public AEADEncryptor(string method, string password) : base(method, password) { - CipherInfo = getCiphers()[method.ToLower()]; + CipherInfo = GetCiphers()[method.ToLower()]; cipherFamily = CipherInfo.Type; AEADCipherParameter parameter = (AEADCipherParameter)CipherInfo.CipherParameter; keyLen = parameter.KeySize; @@ -55,13 +54,15 @@ namespace Shadowsocks.Encryption.AEAD nonceLen = parameter.NonceSize; InitKey(password); + + salt = new byte[saltLen]; // Initialize all-zero nonce for each connection nonce = new byte[nonceLen]; logger.Dump($"masterkey {instanceId}", masterKey, keyLen); logger.Dump($"nonce {instanceId}", nonce, keyLen); } - protected abstract Dictionary getCiphers(); + protected abstract Dictionary GetCiphers(); protected void InitKey(string password) { @@ -77,32 +78,18 @@ namespace Shadowsocks.Encryption.AEAD Array.Resize(ref masterKey, keyLen); } - DeriveKey(passbuf, masterKey, keyLen); + StreamEncryptor.LegacyDeriveKey(passbuf, masterKey, keyLen); // init session key sessionKey = new byte[keyLen]; } - public void DeriveKey(byte[] password, byte[] key, int keylen) - { - StreamEncryptor.LegacyDeriveKey(password, key, keylen); - } - - public void DeriveSessionKey(byte[] salt, byte[] masterKey, byte[] sessionKey) - { - CryptoUtils.HKDF(keyLen, masterKey, salt, InfoBytes).CopyTo(sessionKey, 0); - } - - protected void IncrementNonce() - { - CryptoUtils.SodiumIncrement(nonce); - } - - public virtual void InitCipher(byte[] salt, bool isEncrypt, bool isUdp) + public virtual void InitCipher(byte[] salt, bool isEncrypt) { this.salt = new byte[saltLen]; Array.Copy(salt, this.salt, saltLen); - DeriveSessionKey(salt, masterKey, sessionKey); + CryptoUtils.HKDF(keyLen, masterKey, salt, InfoBytes).CopyTo(sessionKey, 0); + logger.Dump($"salt {instanceId}", salt, saltLen); logger.Dump($"sessionkey {instanceId}", sessionKey, keyLen); } @@ -112,10 +99,11 @@ namespace Shadowsocks.Encryption.AEAD #region TCP + [MethodImpl(MethodImplOptions.Synchronized | MethodImplOptions.AggressiveOptimization)] public override int Encrypt(ReadOnlySpan plain, Span cipher) { // push data - Span tmp = sharedBuffer.AsSpan(0, plain.Length + bufPtr); + Span tmp = buffer.AsSpan(0, plain.Length + bufPtr); plain.CopyTo(tmp.Slice(bufPtr)); int outlength = 0; @@ -124,7 +112,7 @@ namespace Shadowsocks.Encryption.AEAD saltReady = true; // Generate salt byte[] saltBytes = RNG.GetBytes(saltLen); - InitCipher(saltBytes, true, false); + InitCipher(saltBytes, true); saltBytes.CopyTo(cipher); outlength = saltLen; } @@ -162,7 +150,7 @@ namespace Shadowsocks.Encryption.AEAD logger.Debug("enc outbuf almost full, giving up"); // write rest data to head of shared buffer - tmp.CopyTo(sharedBuffer); + tmp.CopyTo(buffer); bufPtr = tmp.Length; return outlength; @@ -177,11 +165,12 @@ namespace Shadowsocks.Encryption.AEAD } } + [MethodImpl(MethodImplOptions.Synchronized | MethodImplOptions.AggressiveOptimization)] public override int Decrypt(Span plain, ReadOnlySpan cipher) { int outlength = 0; // drop all into buffer - Span tmp = sharedBuffer.AsSpan(0, cipher.Length + bufPtr); + Span tmp = buffer.AsSpan(0, cipher.Length + bufPtr); cipher.CopyTo(tmp.Slice(bufPtr)); int bufSize = tmp.Length; @@ -192,7 +181,7 @@ namespace Shadowsocks.Encryption.AEAD if (bufSize <= saltLen) { // need more, write back cache - tmp.CopyTo(sharedBuffer); + tmp.CopyTo(buffer); bufPtr = tmp.Length; return outlength; } @@ -202,7 +191,7 @@ namespace Shadowsocks.Encryption.AEAD byte[] salt = tmp.Slice(0, saltLen).ToArray(); tmp = tmp.Slice(saltLen); - InitCipher(salt, false, false); + InitCipher(salt, false); logger.Debug("get salt len " + saltLen); } @@ -222,7 +211,7 @@ namespace Shadowsocks.Encryption.AEAD { // so we only have chunk length and its tag? // wait more - tmp.CopyTo(sharedBuffer); + tmp.CopyTo(buffer); bufPtr = tmp.Length; return outlength; } @@ -231,7 +220,7 @@ namespace Shadowsocks.Encryption.AEAD if (len <= 0) { // no chunk decrypted - tmp.CopyTo(sharedBuffer); + tmp.CopyTo(buffer); bufPtr = tmp.Length; return outlength; } @@ -243,7 +232,7 @@ namespace Shadowsocks.Encryption.AEAD if (outlength + 100 > TCPHandler.BufferSize) { logger.Debug("dec outbuf almost full, giving up"); - tmp.CopyTo(sharedBuffer); + tmp.CopyTo(buffer); bufPtr = tmp.Length; return outlength; } @@ -260,21 +249,24 @@ namespace Shadowsocks.Encryption.AEAD #endregion #region UDP + [MethodImpl(MethodImplOptions.Synchronized | MethodImplOptions.AggressiveOptimization)] public override int EncryptUDP(ReadOnlySpan plain, Span cipher) { RNG.GetSpan(cipher.Slice(0, saltLen)); - InitCipher(cipher.Slice(0, saltLen).ToArray(), true, true); + InitCipher(cipher.Slice(0, saltLen).ToArray(), true); return saltLen + CipherEncrypt(plain, cipher.Slice(saltLen)); } + [MethodImpl(MethodImplOptions.Synchronized | MethodImplOptions.AggressiveOptimization)] public override int DecryptUDP(Span plain, ReadOnlySpan cipher) { - InitCipher(cipher.Slice(0, saltLen).ToArray(), false, true); + InitCipher(cipher.Slice(0, saltLen).ToArray(), false); return CipherDecrypt(plain, cipher.Slice(saltLen)); } #endregion + [MethodImpl(MethodImplOptions.AggressiveOptimization)] private int ChunkEncrypt(ReadOnlySpan plain, Span cipher) { if (plain.Length > ChunkLengthMask) @@ -285,13 +277,14 @@ namespace Shadowsocks.Encryption.AEAD byte[] lenbuf = BitConverter.GetBytes((ushort)IPAddress.HostToNetworkOrder((short)plain.Length)); int cipherLenSize = CipherEncrypt(lenbuf, cipher); - IncrementNonce(); + CryptoUtils.SodiumIncrement(nonce); int cipherDataSize = CipherEncrypt(plain, cipher.Slice(cipherLenSize)); - IncrementNonce(); + CryptoUtils.SodiumIncrement(nonce); return cipherLenSize + cipherDataSize; } + [MethodImpl(MethodImplOptions.AggressiveOptimization)] private int ChunkDecrypt(Span plain, ReadOnlySpan cipher) { // try to dec chunk len @@ -311,11 +304,11 @@ namespace Shadowsocks.Encryption.AEAD logger.Debug("No data to decrypt one chunk"); return 0; } - IncrementNonce(); + CryptoUtils.SodiumIncrement(nonce); // we have enough data to decrypt one chunk // drop chunk len and its tag from buffer int len = CipherDecrypt(plain, cipher.Slice(ChunkLengthBytes + tagLen, chunkLength + tagLen)); - IncrementNonce(); + CryptoUtils.SodiumIncrement(nonce); return len; } } diff --git a/shadowsocks-csharp/Encryption/AEAD/AEADNaClEncryptor.cs b/shadowsocks-csharp/Encryption/AEAD/AEADNaClEncryptor.cs index 0fb2ff55..3fc18649 100644 --- a/shadowsocks-csharp/Encryption/AEAD/AEADNaClEncryptor.cs +++ b/shadowsocks-csharp/Encryption/AEAD/AEADNaClEncryptor.cs @@ -8,7 +8,7 @@ namespace Shadowsocks.Encryption.AEAD public class AEADNaClEncryptor : AEADEncryptor { - SnufflePoly1305 enc; + SnufflePoly1305? enc; public AEADNaClEncryptor(string method, string password) : base(method, password) { } @@ -20,7 +20,7 @@ namespace Shadowsocks.Encryption.AEAD {"xchacha20-ietf-poly1305", new CipherInfo("xchacha20-ietf-poly1305",32, 32, 24, 16, CipherFamily.XChacha20Poly1305)}, }; - protected override Dictionary getCiphers() + protected override Dictionary GetCiphers() { return _ciphers; } @@ -31,31 +31,26 @@ namespace Shadowsocks.Encryption.AEAD } #endregion - public override void InitCipher(byte[] salt, bool isEncrypt, bool isUdp) + public override void InitCipher(byte[] salt, bool isEncrypt) { - base.InitCipher(salt, isEncrypt, isUdp); - switch (cipherFamily) + base.InitCipher(salt, isEncrypt); + enc = cipherFamily switch { - default: - case CipherFamily.Chacha20Poly1305: - enc = new ChaCha20Poly1305(sessionKey); - break; - case CipherFamily.XChacha20Poly1305: - enc = new XChaCha20Poly1305(sessionKey); - break; - } + CipherFamily.XChacha20Poly1305 => new XChaCha20Poly1305(sessionKey), + _ => new ChaCha20Poly1305(sessionKey), + }; } public override int CipherEncrypt(ReadOnlySpan plain, Span cipher) { - byte[] ct = enc.Encrypt(plain, null, nonce); + byte[] ct = enc!.Encrypt(plain, null, nonce); ct.CopyTo(cipher); return ct.Length; } public override int CipherDecrypt(Span plain, ReadOnlySpan cipher) { - byte[] pt = enc.Decrypt(cipher, null, nonce); + byte[] pt = enc!.Decrypt(cipher, null, nonce); pt.CopyTo(plain); return pt.Length; } diff --git a/shadowsocks-csharp/Encryption/EncryptorBase.cs b/shadowsocks-csharp/Encryption/EncryptorBase.cs index cbda4b32..7effb0c2 100644 --- a/shadowsocks-csharp/Encryption/EncryptorBase.cs +++ b/shadowsocks-csharp/Encryption/EncryptorBase.cs @@ -1,4 +1,5 @@ using System; +using System.Runtime.CompilerServices; namespace Shadowsocks.Encryption { diff --git a/shadowsocks-csharp/Encryption/EncryptorFactory.cs b/shadowsocks-csharp/Encryption/EncryptorFactory.cs index be90af84..e5df88f0 100644 --- a/shadowsocks-csharp/Encryption/EncryptorFactory.cs +++ b/shadowsocks-csharp/Encryption/EncryptorFactory.cs @@ -11,8 +11,8 @@ namespace Shadowsocks.Encryption { public static string DefaultCipher = "chacha20-ietf-poly1305"; - private static Dictionary _registeredEncryptors = new Dictionary(); - private static Dictionary ciphers = new Dictionary(); + private static readonly Dictionary _registeredEncryptors = new Dictionary(); + private static readonly Dictionary ciphers = new Dictionary(); private static readonly Type[] ConstructorTypes = { typeof(string), typeof(string) }; static EncryptorFactory() @@ -33,12 +33,12 @@ namespace Shadowsocks.Encryption _registeredEncryptors.Add(method.Key, typeof(StreamRc4NativeEncryptor)); } } - foreach (var method in StreamAesBouncyCastleEncryptor.SupportedCiphers()) + foreach (var method in StreamAesCfbBouncyCastleEncryptor.SupportedCiphers()) { if (!_registeredEncryptors.ContainsKey(method.Key)) { ciphers.Add(method.Key, method.Value); - _registeredEncryptors.Add(method.Key, typeof(StreamAesBouncyCastleEncryptor)); + _registeredEncryptors.Add(method.Key, typeof(StreamAesCfbBouncyCastleEncryptor)); } } foreach (var method in StreamChachaNaClEncryptor.SupportedCiphers()) @@ -77,7 +77,7 @@ namespace Shadowsocks.Encryption } method = method.ToLowerInvariant(); - bool ok = _registeredEncryptors.TryGetValue(method, out Type t); + bool ok = _registeredEncryptors.TryGetValue(method, out Type? t); if (!ok) { t = _registeredEncryptors[DefaultCipher]; diff --git a/shadowsocks-csharp/Encryption/Stream/ExtendedCfbBlockCipher.cs b/shadowsocks-csharp/Encryption/Stream/ExtendedCfbBlockCipher.cs index 322b9c4c..fc912ebc 100644 --- a/shadowsocks-csharp/Encryption/Stream/ExtendedCfbBlockCipher.cs +++ b/shadowsocks-csharp/Encryption/Stream/ExtendedCfbBlockCipher.cs @@ -13,9 +13,9 @@ namespace Org.BouncyCastle.Crypto.Modes public class ExtendedCfbBlockCipher : IBlockCipher { - private byte[] IV; - private byte[] cfbV; - private byte[] cfbOutV; + private readonly byte[] IV; + private readonly byte[] cfbV; + private readonly byte[] cfbOutV; private bool encrypting; private readonly int blockSize; @@ -63,9 +63,8 @@ namespace Org.BouncyCastle.Crypto.Modes ICipherParameters parameters) { encrypting = forEncryption; - if (parameters is ParametersWithIV) + if (parameters is ParametersWithIV ivParam) { - ParametersWithIV ivParam = (ParametersWithIV)parameters; byte[] iv = ivParam.GetIV(); int diff = IV.Length - iv.Length; Array.Copy(iv, 0, IV, diff, iv.Length); diff --git a/shadowsocks-csharp/Encryption/Stream/StreamAesBouncyCastleEncryptor.cs b/shadowsocks-csharp/Encryption/Stream/StreamAesBouncyCastleEncryptor.cs index 6a6ea32b..b22341f3 100644 --- a/shadowsocks-csharp/Encryption/Stream/StreamAesBouncyCastleEncryptor.cs +++ b/shadowsocks-csharp/Encryption/Stream/StreamAesBouncyCastleEncryptor.cs @@ -3,23 +3,24 @@ using Org.BouncyCastle.Crypto.Modes; using Org.BouncyCastle.Crypto.Parameters; using System; using System.Collections.Generic; +using System.Runtime.CompilerServices; namespace Shadowsocks.Encryption.Stream { - public class StreamAesBouncyCastleEncryptor : StreamEncryptor + public class StreamAesCfbBouncyCastleEncryptor : StreamEncryptor { - byte[] cfbBuf = new byte[MaxInputSize + 128]; + readonly byte[] cfbBuf = new byte[MaxInputSize + 128]; int ptr = 0; readonly ExtendedCfbBlockCipher b; - public StreamAesBouncyCastleEncryptor(string method, string password) : base(method, password) + public StreamAesCfbBouncyCastleEncryptor(string method, string password) : base(method, password) { b = new ExtendedCfbBlockCipher(new AesEngine(), 128); } - protected override void initCipher(byte[] iv, bool isEncrypt) + protected override void InitCipher(byte[] iv, bool isEncrypt) { - base.initCipher(iv, isEncrypt); + base.InitCipher(iv, isEncrypt); b.Init(isEncrypt, new ParametersWithIV(new KeyParameter(key), iv)); } @@ -35,6 +36,7 @@ namespace Shadowsocks.Encryption.Stream return cipher.Length; } + [MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)] private void CipherUpdate(ReadOnlySpan i, Span o) { Span ob = new byte[o.Length + 128]; @@ -82,7 +84,7 @@ namespace Shadowsocks.Encryption.Stream return _ciphers; } - protected override Dictionary getCiphers() + protected override Dictionary GetCiphers() { return _ciphers; } diff --git a/shadowsocks-csharp/Encryption/Stream/StreamChachaNaClEncryptor.cs b/shadowsocks-csharp/Encryption/Stream/StreamChachaNaClEncryptor.cs index e8670109..aad65b10 100644 --- a/shadowsocks-csharp/Encryption/Stream/StreamChachaNaClEncryptor.cs +++ b/shadowsocks-csharp/Encryption/Stream/StreamChachaNaClEncryptor.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Runtime.CompilerServices; using NaCl.Core; namespace Shadowsocks.Encryption.Stream @@ -7,15 +8,16 @@ namespace Shadowsocks.Encryption.Stream public class StreamChachaNaClEncryptor : StreamEncryptor { const int BlockSize = 64; + // tcp is stream, which can split into chunks at unexpected position... // so we need some special handling, as we can't read all data before encrypt - + // we did it in AEADEncryptor.cs for AEAD, it can operate at block level // but we need do it ourselves in stream cipher. // when new data arrive, put it on correct offset // and update it, ignore other data, get it in correct offset... - byte[] chachaBuf = new byte[MaxInputSize + BlockSize]; + readonly byte[] chachaBuf = new byte[MaxInputSize + BlockSize]; // the 'correct offset', always in 0~BlockSize range, so input data always fit into buffer int remain = 0; // increase counter manually... @@ -34,6 +36,7 @@ namespace Shadowsocks.Encryption.Stream return CipherUpdate(plain, cipher, true); } + [MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)] private int CipherUpdate(ReadOnlySpan i, Span o, bool enc) { int len = i.Length; @@ -58,7 +61,7 @@ namespace Shadowsocks.Encryption.Stream return _ciphers; } - protected override Dictionary getCiphers() + protected override Dictionary GetCiphers() { return _ciphers; } diff --git a/shadowsocks-csharp/Encryption/Stream/StreamEncryptor.cs b/shadowsocks-csharp/Encryption/Stream/StreamEncryptor.cs index 87dceb38..eacd25e6 100644 --- a/shadowsocks-csharp/Encryption/Stream/StreamEncryptor.cs +++ b/shadowsocks-csharp/Encryption/Stream/StreamEncryptor.cs @@ -1,6 +1,7 @@ using NLog; using System; using System.Collections.Generic; +using System.Runtime.CompilerServices; using System.Text; namespace Shadowsocks.Encryption.Stream @@ -26,7 +27,7 @@ namespace Shadowsocks.Encryption.Stream public StreamEncryptor(string method, string password) : base(method, password) { - CipherInfo = getCiphers()[method.ToLower()]; + CipherInfo = GetCiphers()[method.ToLower()]; cipherFamily = CipherInfo.Type; StreamCipherParameter parameter = (StreamCipherParameter)CipherInfo.CipherParameter; keyLen = parameter.KeySize; @@ -37,7 +38,7 @@ namespace Shadowsocks.Encryption.Stream logger.Dump($"key {instanceId}", key, keyLen); } - protected abstract Dictionary getCiphers(); + protected abstract Dictionary GetCiphers(); private void InitKey(string password) { @@ -51,6 +52,7 @@ namespace Shadowsocks.Encryption.Stream LegacyDeriveKey(passbuf, key, keyLen); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void LegacyDeriveKey(byte[] password, byte[] key, int keylen) { byte[] result = new byte[password.Length + MD5Length]; @@ -73,7 +75,7 @@ namespace Shadowsocks.Encryption.Stream } } - protected virtual void initCipher(byte[] iv, bool isEncrypt) + protected virtual void InitCipher(byte[] iv, bool isEncrypt) { if (ivLen == 0) { @@ -88,6 +90,7 @@ namespace Shadowsocks.Encryption.Stream protected abstract int CipherDecrypt(Span plain, ReadOnlySpan cipher); #region TCP + [MethodImpl(MethodImplOptions.Synchronized | MethodImplOptions.AggressiveOptimization)] public override int Encrypt(ReadOnlySpan plain, Span cipher) { int cipherOffset = 0; @@ -96,7 +99,7 @@ namespace Shadowsocks.Encryption.Stream { // Generate IV byte[] ivBytes = RNG.GetBytes(ivLen); - initCipher(ivBytes, true); + InitCipher(ivBytes, true); ivBytes.CopyTo(cipher); cipherOffset = ivLen; cipher = cipher.Slice(cipherOffset); @@ -111,9 +114,9 @@ namespace Shadowsocks.Encryption.Stream } private int recieveCtr = 0; + [MethodImpl(MethodImplOptions.Synchronized | MethodImplOptions.AggressiveOptimization)] public override int Decrypt(Span plain, ReadOnlySpan cipher) { - Span tmp;// = cipher; logger.Trace($"{instanceId} decrypt TCP, read iv: {!ivReady}"); int cipherOffset = 0; @@ -135,14 +138,13 @@ namespace Shadowsocks.Encryption.Stream { // read iv byte[] iv = sharedBuffer.AsSpan(0, ivLen).ToArray(); - initCipher(iv, false); + InitCipher(iv, false); } else { - initCipher(Array.Empty(), false); + InitCipher(Array.Empty(), false); } cipherOffset += ivLen; - tmp = sharedBuffer.AsSpan(ivLen, recieveCtr - ivLen); } // read all data from buffer @@ -156,17 +158,19 @@ namespace Shadowsocks.Encryption.Stream #endregion #region UDP + [MethodImpl(MethodImplOptions.Synchronized | MethodImplOptions.AggressiveOptimization)] public override int EncryptUDP(ReadOnlySpan plain, Span cipher) { byte[] iv = RNG.GetBytes(ivLen); iv.CopyTo(cipher); - initCipher(iv, true); + InitCipher(iv, true); return ivLen + CipherEncrypt(plain, cipher.Slice(ivLen)); } + [MethodImpl(MethodImplOptions.Synchronized | MethodImplOptions.AggressiveOptimization)] public override int DecryptUDP(Span plain, ReadOnlySpan cipher) { - initCipher(cipher.Slice(0, ivLen).ToArray(), false); + InitCipher(cipher.Slice(0, ivLen).ToArray(), false); return CipherDecrypt(plain, cipher.Slice(ivLen)); } diff --git a/shadowsocks-csharp/Encryption/Stream/StreamPlainNativeEncryptor.cs b/shadowsocks-csharp/Encryption/Stream/StreamPlainNativeEncryptor.cs index 33a59dcc..3b4e1ece 100644 --- a/shadowsocks-csharp/Encryption/Stream/StreamPlainNativeEncryptor.cs +++ b/shadowsocks-csharp/Encryption/Stream/StreamPlainNativeEncryptor.cs @@ -33,7 +33,7 @@ namespace Shadowsocks.Encryption.Stream return _ciphers; } - protected override Dictionary getCiphers() + protected override Dictionary GetCiphers() { return _ciphers; } diff --git a/shadowsocks-csharp/Encryption/Stream/StreamRc4NativeEncryptor.cs b/shadowsocks-csharp/Encryption/Stream/StreamRc4NativeEncryptor.cs index 367b8080..0e2d1935 100644 --- a/shadowsocks-csharp/Encryption/Stream/StreamRc4NativeEncryptor.cs +++ b/shadowsocks-csharp/Encryption/Stream/StreamRc4NativeEncryptor.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Runtime.CompilerServices; namespace Shadowsocks.Encryption.Stream { @@ -11,9 +12,9 @@ namespace Shadowsocks.Encryption.Stream { } - protected override void initCipher(byte[] iv, bool isEncrypt) + protected override void InitCipher(byte[] iv, bool isEncrypt) { - base.initCipher(iv, isEncrypt); + base.InitCipher(iv, isEncrypt); // rc4-md5 is rc4 with md5 based session key if (cipherFamily == CipherFamily.Rc4Md5) { @@ -39,6 +40,7 @@ namespace Shadowsocks.Encryption.Stream return CipherUpdate(cipher, plain); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private int CipherUpdate(ReadOnlySpan i, Span o) { // don't know why we need third array, but it works... @@ -62,7 +64,7 @@ namespace Shadowsocks.Encryption.Stream return _ciphers; } - protected override Dictionary getCiphers() + protected override Dictionary GetCiphers() { return _ciphers; } @@ -75,7 +77,7 @@ namespace Shadowsocks.Encryption.Stream public int index2 = 0; } - private Context ctx = new Context(); + private readonly Context ctx = new Context(); private byte[] SBox(byte[] key) { @@ -96,6 +98,7 @@ namespace Shadowsocks.Encryption.Stream return s; } + [MethodImpl(MethodImplOptions.AggressiveOptimization)] private void RC4(Context ctx, Span s, Span data, int length) { for (int n = 0; n < length; n++) @@ -110,6 +113,7 @@ namespace Shadowsocks.Encryption.Stream } } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void Swap(Span s, int i, int j) { byte c = s[i]; diff --git a/test/CryptographyTest.cs b/test/CryptographyTest.cs index 13459069..57e987a9 100644 --- a/test/CryptographyTest.cs +++ b/test/CryptographyTest.cs @@ -11,7 +11,7 @@ namespace Shadowsocks.Test [TestClass] public class CryptographyTest { - Random random = new Random(); + readonly Random random = new Random(); [TestMethod] @@ -161,9 +161,9 @@ namespace Shadowsocks.Test [TestMethod] public void TestStreamAesCfbBouncyCastleEncryption() { - TestEncryptionMethod(typeof(StreamAesBouncyCastleEncryptor), "aes-128-cfb"); - TestEncryptionMethod(typeof(StreamAesBouncyCastleEncryptor), "aes-192-cfb"); - TestEncryptionMethod(typeof(StreamAesBouncyCastleEncryptor), "aes-256-cfb"); + TestEncryptionMethod(typeof(StreamAesCfbBouncyCastleEncryptor), "aes-128-cfb"); + TestEncryptionMethod(typeof(StreamAesCfbBouncyCastleEncryptor), "aes-192-cfb"); + TestEncryptionMethod(typeof(StreamAesCfbBouncyCastleEncryptor), "aes-256-cfb"); } [TestMethod] public void TestStreamChachaNaClEncryption()