diff --git a/shadowsocks-csharp/Controller/Service/TCPRelay.cs b/shadowsocks-csharp/Controller/Service/TCPRelay.cs index f4b67586..fe626dac 100644 --- a/shadowsocks-csharp/Controller/Service/TCPRelay.cs +++ b/shadowsocks-csharp/Controller/Service/TCPRelay.cs @@ -339,7 +339,7 @@ namespace Shadowsocks.Controller if (bytesRead >= 5) { _command = _connetionRecvBuffer[1]; - switch(_command) + switch (_command) { case CMD_CONNECT: @@ -467,7 +467,7 @@ namespace Shadowsocks.Controller break; } - Logger.Debug($"connect to {dstAddr}:{dstPort}"); + Logger.Debug($"connect to {dstAddr}:{dstPort}"); _destEndPoint = SocketUtil.GetEndPoint(dstAddr, dstPort); @@ -820,7 +820,8 @@ namespace Shadowsocks.Controller { try { - decryptor.Decrypt(_remoteRecvBuffer, bytesRead, _remoteSendBuffer, out bytesToSend); + bytesToSend = decryptor.Decrypt(_remoteSendBuffer, _remoteRecvBuffer.AsSpan(0, bytesRead)); + // decryptor.Decrypt(_remoteRecvBuffer, bytesRead, _remoteSendBuffer, out bytesToSend); } catch (CryptoErrorException) { @@ -893,7 +894,8 @@ namespace Shadowsocks.Controller { try { - encryptor.Encrypt(_connetionRecvBuffer, length, _connetionSendBuffer, out bytesToSend); + bytesToSend = encryptor.Encrypt(_connetionRecvBuffer.AsSpan(0, length), _connetionSendBuffer); + // encryptor.Encrypt(_connetionRecvBuffer, length, _connetionSendBuffer, out bytesToSend); } catch (CryptoErrorException) { diff --git a/shadowsocks-csharp/Controller/Service/UDPRelay.cs b/shadowsocks-csharp/Controller/Service/UDPRelay.cs index 568e1f75..42a647d9 100644 --- a/shadowsocks-csharp/Controller/Service/UDPRelay.cs +++ b/shadowsocks-csharp/Controller/Service/UDPRelay.cs @@ -96,11 +96,11 @@ namespace Shadowsocks.Controller public void Send(byte[] data, int length) { IEncryptor encryptor = EncryptorFactory.GetEncryptor(_server.method, _server.password); - byte[] dataIn = new byte[length - 3]; - Array.Copy(data, 3, dataIn, 0, length - 3); + // byte[] dataIn = new byte[length - 3]; + // Array.Copy(data, 3, dataIn, 0, length - 3); byte[] dataOut = new byte[65536]; // enough space for AEAD ciphers - int outlen; - encryptor.EncryptUDP(dataIn, length - 3, dataOut, out outlen); + // encryptor.EncryptUDP(dataIn, length - 3, dataOut, out outlen); + int outlen = encryptor.EncryptUDP(data.AsSpan(3), dataOut); logger.Debug(_localEndPoint, _remoteEndPoint, outlen, "UDP Relay"); _remote?.SendTo(dataOut, outlen, SocketFlags.None, _remoteEndPoint); } @@ -124,8 +124,8 @@ namespace Shadowsocks.Controller int outlen; IEncryptor encryptor = EncryptorFactory.GetEncryptor(_server.method, _server.password); - encryptor.DecryptUDP(_buffer, bytesRead, dataOut, out outlen); - + // encryptor.DecryptUDP(_buffer, bytesRead, dataOut, out outlen); + outlen = encryptor.DecryptUDP(dataOut, _buffer.AsSpan(0, bytesRead)); byte[] sendBuf = new byte[outlen + 3]; Array.Copy(dataOut, 0, sendBuf, 3, outlen); diff --git a/shadowsocks-csharp/Encryption/AEAD/AEADEncryptor.cs b/shadowsocks-csharp/Encryption/AEAD/AEADEncryptor.cs index 4698dcd4..af9a50de 100644 --- a/shadowsocks-csharp/Encryption/AEAD/AEADEncryptor.cs +++ b/shadowsocks-csharp/Encryption/AEAD/AEADEncryptor.cs @@ -57,6 +57,8 @@ namespace Shadowsocks.Encryption.AEAD InitKey(password); // 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(); @@ -99,9 +101,10 @@ namespace Shadowsocks.Encryption.AEAD { this.salt = new byte[saltLen]; Array.Copy(salt, this.salt, saltLen); - logger.Dump("Salt", salt, saltLen); DeriveSessionKey(salt, masterKey, sessionKey); + logger.Dump($"salt {instanceId}", salt, saltLen); + logger.Dump($"sessionkey {instanceId}", sessionKey, keyLen); } public abstract int CipherEncrypt(ReadOnlySpan plain, Span cipher); @@ -109,85 +112,6 @@ namespace Shadowsocks.Encryption.AEAD #region TCP - public override void Encrypt(byte[] buf, int length, byte[] outbuf, out int outlength) - { - // push data - buf.CopyTo(sharedBuffer, bufPtr); - Span tmp = sharedBuffer.AsSpan(0, length + bufPtr); - - outlength = 0; - logger.Debug("---Start Encryption"); - if (!saltReady) - { - saltReady = true; - // Generate salt - byte[] saltBytes = RNG.GetBytes(saltLen); - InitCipher(saltBytes, true, false); - Array.Copy(saltBytes, 0, outbuf, 0, saltLen); - outlength = saltLen; - logger.Debug($"_encryptSaltSent outlength {outlength}"); - } - - if (!tcpRequestSent) - { - tcpRequestSent = true; - // The first TCP request - byte[] encAddrBufBytes = new byte[AddressBufferLength + tagLen * 2 + ChunkLengthBytes]; - - // read addr byte to encrypt - byte[] addrBytes = tmp.Slice(0, AddressBufferLength).ToArray(); - tmp = tmp.Slice(AddressBufferLength); - - int encAddrBufLength = ChunkEncrypt(addrBytes, encAddrBufBytes); - - Array.Copy(encAddrBufBytes, 0, outbuf, outlength, encAddrBufLength); - outlength += encAddrBufLength; - logger.Debug($"_tcpRequestSent outlength {outlength}"); - } - - // handle other chunks - while (true) - { - // calculate next chunk size - int bufSize = tmp.Length; - if (bufSize <= 0) - { - return; - } - - int chunklength = (int)Math.Min(bufSize, ChunkLengthMask); - // read next chunk - byte[] chunkBytes = tmp.Slice(0, chunklength).ToArray(); - tmp = tmp.Slice(chunklength); - - byte[] encChunkBytes = new byte[chunklength + tagLen * 2 + ChunkLengthBytes]; - int encChunkLength = ChunkEncrypt(chunkBytes, encChunkBytes); - - Buffer.BlockCopy(encChunkBytes, 0, outbuf, outlength, encChunkLength); - outlength += encChunkLength; - logger.Debug("chunks enc outlength " + outlength); - // check if we have enough space for outbuf - // if not, keep buf for next run, at this condition, buffer is not empty - if (outlength + TCPHandler.ChunkOverheadSize > TCPHandler.BufferSize) - { - logger.Debug("enc outbuf almost full, giving up"); - - // write rest data to head of shared buffer - tmp.CopyTo(sharedBuffer); - bufPtr = tmp.Length; - - return; - } - // check if buffer empty - bufSize = tmp.Length; - if (bufSize <= 0) - { - logger.Debug("No more data to encrypt, leaving"); - return; - } - } - } - public override int Encrypt(ReadOnlySpan plain, Span cipher) { // push data @@ -253,86 +177,6 @@ namespace Shadowsocks.Encryption.AEAD } } - public override void Decrypt(byte[] buf, int length, byte[] outbuf, out int outlength) - { - outlength = 0; - // drop all into buffer - buf.CopyTo(sharedBuffer, bufPtr); - Span tmp = buf.AsSpan(0, length + bufPtr); - int bufSize = tmp.Length; - - logger.Debug("---Start Decryption"); - if (!saltReady) - { - // check if we get the leading salt - if (bufSize <= saltLen) - { - // need more, write back cache - tmp.CopyTo(sharedBuffer); - bufPtr = tmp.Length; - return; - } - saltReady = true; - - // buffer.Get(saltLen); - byte[] salt = tmp.Slice(0, saltLen).ToArray(); - tmp = tmp.Slice(saltLen); - - InitCipher(salt, false, false); - logger.Debug("get salt len " + saltLen); - } - - // handle chunks - while (true) - { - bufSize = tmp.Length; - // check if we have any data - if (bufSize <= 0) - { - logger.Debug("No data in _decCircularBuffer"); - return; - } - - // first get chunk length - if (bufSize <= ChunkLengthBytes + tagLen) - { - // so we only have chunk length and its tag? - // wait more - tmp.CopyTo(sharedBuffer); - bufPtr = tmp.Length; - return; - } - - int len = ChunkDecrypt(outbuf.AsSpan(outlength), tmp); - if (len <= 0) - { - tmp.CopyTo(sharedBuffer); - bufPtr = tmp.Length; - return; - } - - tmp = tmp.Slice(ChunkLengthBytes + tagLen + len + tagLen); - // output to outbuf - outlength += len; - - logger.Debug("aead dec outlength " + outlength); - if (outlength + 100 > TCPHandler.BufferSize) - { - logger.Debug("dec outbuf almost full, giving up"); - tmp.CopyTo(sharedBuffer); - bufPtr = tmp.Length; - return; - } - bufSize = tmp.Length; - // check if we already done all of them - if (bufSize <= 0) - { - logger.Debug("No data in _decCircularBuffer, already all done"); - return; - } - } - } - public override int Decrypt(Span plain, ReadOnlySpan cipher) { int outlength = 0; @@ -416,16 +260,6 @@ namespace Shadowsocks.Encryption.AEAD #endregion #region UDP - public override void EncryptUDP(byte[] buf, int length, byte[] outbuf, out int outlength) - { - // Generate salt - RNG.GetSpan(outbuf.AsSpan(0, saltLen)); - InitCipher(outbuf, true, true); - outlength = saltLen + CipherEncrypt( - buf.AsSpan(0, length), - outbuf.AsSpan(saltLen, length + tagLen)); - } - public override int EncryptUDP(ReadOnlySpan plain, Span cipher) { RNG.GetSpan(cipher.Slice(0, saltLen)); @@ -433,12 +267,6 @@ namespace Shadowsocks.Encryption.AEAD return saltLen + CipherEncrypt(plain, cipher.Slice(saltLen)); } - public override void DecryptUDP(byte[] buf, int length, byte[] outbuf, out int outlength) - { - InitCipher(buf, false, true); - outlength = CipherDecrypt(outbuf, buf.AsSpan(saltLen, length - saltLen)); - } - public override int DecryptUDP(Span plain, ReadOnlySpan cipher) { InitCipher(cipher.Slice(0, saltLen).ToArray(), false, true); diff --git a/shadowsocks-csharp/Encryption/EncryptorBase.cs b/shadowsocks-csharp/Encryption/EncryptorBase.cs index 32d79847..cbda4b32 100644 --- a/shadowsocks-csharp/Encryption/EncryptorBase.cs +++ b/shadowsocks-csharp/Encryption/EncryptorBase.cs @@ -33,14 +33,6 @@ namespace Shadowsocks.Encryption protected string Method; protected string Password; - public abstract void Encrypt(byte[] buf, int length, byte[] outbuf, out int outlength); - - public abstract void Decrypt(byte[] buf, int length, byte[] outbuf, out int outlength); - - public abstract void EncryptUDP(byte[] buf, int length, byte[] outbuf, out int outlength); - - public abstract void DecryptUDP(byte[] buf, int length, byte[] outbuf, out int outlength); - public override string ToString() { return $"{instanceId}({Method},{Password})"; diff --git a/shadowsocks-csharp/Encryption/IEncryptor.cs b/shadowsocks-csharp/Encryption/IEncryptor.cs index 76efa1bf..060d57a7 100644 --- a/shadowsocks-csharp/Encryption/IEncryptor.cs +++ b/shadowsocks-csharp/Encryption/IEncryptor.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; namespace Shadowsocks.Encryption { @@ -7,10 +6,6 @@ namespace Shadowsocks.Encryption { /* length == -1 means not used */ int AddressBufferLength { set; get; } - void Encrypt(byte[] buf, int length, byte[] outbuf, out int outlength); - void Decrypt(byte[] buf, int length, byte[] outbuf, out int outlength); - void EncryptUDP(byte[] buf, int length, byte[] outbuf, out int outlength); - void DecryptUDP(byte[] buf, int length, byte[] outbuf, out int outlength); int Encrypt(ReadOnlySpan plain, Span cipher); int Decrypt(Span plain, ReadOnlySpan cipher); int EncryptUDP(ReadOnlySpan plain, Span cipher); diff --git a/shadowsocks-csharp/Encryption/Stream/StreamEncryptor.cs b/shadowsocks-csharp/Encryption/Stream/StreamEncryptor.cs index 9399480c..87dceb38 100644 --- a/shadowsocks-csharp/Encryption/Stream/StreamEncryptor.cs +++ b/shadowsocks-csharp/Encryption/Stream/StreamEncryptor.cs @@ -1,7 +1,6 @@ using NLog; using System; using System.Collections.Generic; -using System.Runtime.CompilerServices; using System.Text; namespace Shadowsocks.Encryption.Stream @@ -89,34 +88,6 @@ namespace Shadowsocks.Encryption.Stream protected abstract int CipherDecrypt(Span plain, ReadOnlySpan cipher); #region TCP - [MethodImpl(MethodImplOptions.Synchronized)] - public override void Encrypt(byte[] buf, int length, byte[] outbuf, out int outlength) - { - int cipherOffset = 0; - Span tmp = buf.AsSpan(0, length); - logger.Trace($"{instanceId} encrypt TCP, generate iv: {!ivReady}"); - if (!ivReady) - { - // Generate IV - byte[] ivBytes = RNG.GetBytes(ivLen); - initCipher(ivBytes, true); - - Array.Copy(ivBytes, 0, outbuf, 0, ivLen); - cipherOffset = ivLen; - ivReady = true; - } - int size = tmp.Length; - - byte[] cipher = new byte[size]; - CipherEncrypt(tmp, cipher); - - logger.DumpBase64($"plain {instanceId}", tmp.ToArray(), size); - logger.DumpBase64($"cipher {instanceId}", cipher, cipher.Length); - logger.Dump($"iv {instanceId}", iv, ivLen); - Buffer.BlockCopy(cipher, 0, outbuf, cipherOffset, size); - outlength = size + cipherOffset; - } - public override int Encrypt(ReadOnlySpan plain, Span cipher) { int cipherOffset = 0; @@ -134,55 +105,12 @@ namespace Shadowsocks.Encryption.Stream int clen = CipherEncrypt(plain, cipher); logger.DumpBase64($"plain {instanceId}", plain); - logger.DumpBase64($"cipher {instanceId}", cipher); + logger.DumpBase64($"cipher {instanceId}", cipher.Slice(0, clen)); logger.Dump($"iv {instanceId}", iv, ivLen); return clen + cipherOffset; } private int recieveCtr = 0; - [MethodImpl(MethodImplOptions.Synchronized)] - public override void Decrypt(byte[] buf, int length, byte[] outbuf, out int outlength) - { - Span tmp = buf.AsSpan(0, length); - logger.Trace($"{instanceId} decrypt TCP, read iv: {!ivReady}"); - - // is first packet, need read iv - if (!ivReady) - { - // push to buffer in case of not enough data - tmp.CopyTo(sharedBuffer.AsSpan(recieveCtr)); - recieveCtr += tmp.Length; - - // not enough data for read iv, return 0 byte data - if (recieveCtr <= ivLen) - { - outlength = 0; - return; - } - // start decryption - ivReady = true; - if (ivLen > 0) - { - // read iv - byte[] iv = sharedBuffer.AsSpan(0, ivLen).ToArray(); - initCipher(iv, false); - } - else - { - initCipher(Array.Empty(), false); - } - - tmp = sharedBuffer.AsSpan(ivLen, recieveCtr - ivLen); - } - - // read all data from buffer - CipherDecrypt(outbuf, tmp); - logger.DumpBase64($"cipher {instanceId}", tmp.ToArray(), tmp.Length); - logger.DumpBase64($"plain {instanceId}", outbuf, tmp.Length); - logger.Dump($"iv {instanceId}", iv, ivLen); - outlength = tmp.Length; - } - public override int Decrypt(Span plain, ReadOnlySpan cipher) { Span tmp;// = cipher; @@ -220,7 +148,7 @@ namespace Shadowsocks.Encryption.Stream // read all data from buffer int len = CipherDecrypt(plain, cipher.Slice(cipherOffset)); logger.DumpBase64($"cipher {instanceId}", cipher.Slice(cipherOffset)); - logger.DumpBase64($"plain {instanceId}", plain); + logger.DumpBase64($"plain {instanceId}", plain.Slice(0, len)); logger.Dump($"iv {instanceId}", iv, ivLen); return len; } @@ -228,20 +156,6 @@ namespace Shadowsocks.Encryption.Stream #endregion #region UDP - [MethodImpl(MethodImplOptions.Synchronized)] - public override void EncryptUDP(byte[] buf, int length, byte[] outbuf, out int outlength) - { - // Generate IV - RNG.GetBytes(outbuf, ivLen); - initCipher(outbuf, true); - lock (sharedBuffer) - { - CipherEncrypt(buf, sharedBuffer); - outlength = length + ivLen; - Buffer.BlockCopy(sharedBuffer, 0, outbuf, ivLen, length); - } - } - public override int EncryptUDP(ReadOnlySpan plain, Span cipher) { byte[] iv = RNG.GetBytes(ivLen); @@ -250,20 +164,6 @@ namespace Shadowsocks.Encryption.Stream return ivLen + CipherEncrypt(plain, cipher.Slice(ivLen)); } - [MethodImpl(MethodImplOptions.Synchronized)] - public override void DecryptUDP(byte[] buf, int length, byte[] outbuf, out int outlength) - { - // Get IV from first pos - initCipher(buf, false); - outlength = length - ivLen; - lock (sharedBuffer) - { - // C# could be multi-threaded - Buffer.BlockCopy(buf, ivLen, sharedBuffer, 0, length - ivLen); - CipherDecrypt(outbuf, sharedBuffer); - } - } - public override int DecryptUDP(Span plain, ReadOnlySpan cipher) { initCipher(cipher.Slice(0, ivLen).ToArray(), false);