From 0d5ad751adf42d5053ddcee0f5673b9c83c8fb86 Mon Sep 17 00:00:00 2001 From: Student Main Date: Fri, 27 Mar 2020 22:19:40 +0800 Subject: [PATCH] improve Logger.Dump, few rename --- .../Controller/LoggerExtension.cs | 39 ++++++++---- .../Stream/StreamAesBouncyCastleEncryptor.cs | 2 - .../Stream/StreamChachaNaClEncryptor.cs | 3 +- .../Encryption/Stream/StreamEncryptor.cs | 62 +++++++++---------- .../Stream/StreamRc4NativeEncryptor.cs | 2 +- .../Stream/StreamTableNativeEncryptor.cs | 41 ++++++------ 6 files changed, 81 insertions(+), 68 deletions(-) diff --git a/shadowsocks-csharp/Controller/LoggerExtension.cs b/shadowsocks-csharp/Controller/LoggerExtension.cs index bd9b5925..eb6ee840 100644 --- a/shadowsocks-csharp/Controller/LoggerExtension.cs +++ b/shadowsocks-csharp/Controller/LoggerExtension.cs @@ -11,20 +11,35 @@ namespace NLog { public static class LoggerExtension { - public static void Dump(this Logger logger, string tag, byte[] arr, int length) + // for key, iv, etc... + public static void Dump(this Logger logger, string tag, byte[] arr, int length = -1) { - if (logger.IsTraceEnabled) - { - var sb = new StringBuilder($"{Environment.NewLine}{tag}: "); - for (int i = 0; i < length - 1; i++) - { - sb.Append($"0x{arr[i]:X2}, "); - } - sb.Append($"0x{arr[length - 1]:X2}"); - sb.Append(Environment.NewLine); - logger.Trace(sb.ToString()); - } + if (length == -1) length = arr.Length; + + if (!logger.IsTraceEnabled) return; + string hex = BitConverter.ToString(arr.AsSpan().Slice(0, length).ToArray()).Replace("-", ""); + string content = $@" +{tag}: +{hex} + +"; + logger.Trace(content); } + // for cipher and plain text, so we can use openssl to test + public static void DumpBase64(this Logger logger, string tag, byte[] arr, int length = -1) + { + if (length == -1) length = arr.Length; + + if (!logger.IsTraceEnabled) return; + string hex =Convert.ToBase64String(arr.AsSpan().Slice(0, length).ToArray()); + string content = $@" +{tag}: +{hex} + +"; + logger.Trace(content); + } + public static void Debug(this Logger logger, EndPoint local, EndPoint remote, int len, string header = null, string tailer = null) { diff --git a/shadowsocks-csharp/Encryption/Stream/StreamAesBouncyCastleEncryptor.cs b/shadowsocks-csharp/Encryption/Stream/StreamAesBouncyCastleEncryptor.cs index 5500f2f9..a247f548 100644 --- a/shadowsocks-csharp/Encryption/Stream/StreamAesBouncyCastleEncryptor.cs +++ b/shadowsocks-csharp/Encryption/Stream/StreamAesBouncyCastleEncryptor.cs @@ -45,13 +45,11 @@ namespace Shadowsocks.Encryption.Stream private void CipherUpdate(Span i, Span o) { - // c.Reset(); var ob = new byte[o.Length]; int blklen = c.ProcessBytes(i.ToArray(), 0, i.Length, ob, 0); int restlen = i.Length - blklen; if (restlen != 0) { - // may be problem, c is block cipher? c.DoFinal(ob, blklen); } ob.CopyTo(o); diff --git a/shadowsocks-csharp/Encryption/Stream/StreamChachaNaClEncryptor.cs b/shadowsocks-csharp/Encryption/Stream/StreamChachaNaClEncryptor.cs index fc419d3e..4833b621 100644 --- a/shadowsocks-csharp/Encryption/Stream/StreamChachaNaClEncryptor.cs +++ b/shadowsocks-csharp/Encryption/Stream/StreamChachaNaClEncryptor.cs @@ -1,13 +1,12 @@ using System; using System.Collections.Generic; -using System.Text; using NaCl.Core; namespace Shadowsocks.Encryption.Stream { public class StreamChachaNaClEncryptor : StreamEncryptor { - ChaCha20 c; + readonly ChaCha20 c; public StreamChachaNaClEncryptor(string method, string password) : base(method, password) { c = new ChaCha20(key, 0); diff --git a/shadowsocks-csharp/Encryption/Stream/StreamEncryptor.cs b/shadowsocks-csharp/Encryption/Stream/StreamEncryptor.cs index 1a993ee7..d8429a2f 100644 --- a/shadowsocks-csharp/Encryption/Stream/StreamEncryptor.cs +++ b/shadowsocks-csharp/Encryption/Stream/StreamEncryptor.cs @@ -10,49 +10,40 @@ namespace Shadowsocks.Encryption.Stream { public abstract class StreamEncryptor : EncryptorBase { - private static Logger logger = LogManager.GetCurrentClassLogger(); + private static readonly Logger logger = LogManager.GetCurrentClassLogger(); // for UDP only - protected static byte[] _udpTmpBuf = new byte[65536]; + protected static byte[] udpBuffer = new byte[65536]; // every connection should create its own buffer - private ByteCircularBuffer buffer = new ByteCircularBuffer(TCPHandler.BufferSize * 2); - - protected Dictionary ciphers; - + private readonly ByteCircularBuffer buffer = new ByteCircularBuffer(TCPHandler.BufferSize * 2); // Is first packet protected bool ivReady; - protected string _method; - protected CipherFamily _cipher; + protected CipherFamily cipherFamily; protected CipherInfo CipherInfo; // long-time master key - protected static byte[] key = null; - protected byte[] iv; + protected static byte[] key = Array.Empty(); + protected byte[] iv = Array.Empty(); protected int keyLen; protected int ivLen; public StreamEncryptor(string method, string password) : base(method, password) { - InitEncryptorInfo(method); - InitKey(password); - } - - protected abstract Dictionary getCiphers(); - - private void InitEncryptorInfo(string method) - { - method = method.ToLower(); - _method = method; - ciphers = getCiphers(); - CipherInfo = ciphers[_method]; - _cipher = CipherInfo.Type; + CipherInfo = getCiphers()[method.ToLower()]; + cipherFamily = CipherInfo.Type; var parameter = (StreamCipherParameter)CipherInfo.CipherParameter; keyLen = parameter.KeySize; ivLen = parameter.IvSize; + + InitKey(password); + + logger.Dump($"key {instanceId}", key, keyLen); } + protected abstract Dictionary getCiphers(); + private void InitKey(string password) { byte[] passbuf = Encoding.UTF8.GetBytes(password); @@ -65,7 +56,7 @@ namespace Shadowsocks.Encryption.Stream { byte[] result = new byte[password.Length + MD5_LEN]; int i = 0; - byte[] md5sum = null; + byte[] md5sum = Array.Empty(); while (i < keylen) { if (i == 0) @@ -85,6 +76,7 @@ namespace Shadowsocks.Encryption.Stream protected virtual void initCipher(byte[] iv, bool isEncrypt) { + if (ivLen == 0) return; this.iv = new byte[ivLen]; Array.Copy(iv, this.iv, ivLen); } @@ -103,6 +95,7 @@ namespace Shadowsocks.Encryption.Stream int cipherOffset = 0; Debug.Assert(buffer != null, "_encCircularBuffer != null"); buffer.Put(buf, 0, length); + logger.Trace($"{instanceId} encrypt TCP, generate iv: {!ivReady}"); if (!ivReady) { // Generate IV @@ -117,7 +110,9 @@ namespace Shadowsocks.Encryption.Stream byte[] plain = buffer.Get(size); byte[] cipher = new byte[size]; cipherUpdate(true, size, plain, cipher); - + logger.DumpBase64($"plain {instanceId}", plain, size); + logger.DumpBase64($"cipher {instanceId}", cipher, cipher.Length); + logger.Dump($"iv {instanceId}", iv, ivLen); Buffer.BlockCopy(cipher, 0, outbuf, cipherOffset, size); outlength = size + cipherOffset; } @@ -126,6 +121,7 @@ namespace Shadowsocks.Encryption.Stream { Debug.Assert(buffer != null, "_circularBuffer != null"); buffer.Put(buf, 0, length); + logger.Trace($"{instanceId} decrypt TCP, read iv: {!ivReady}"); if (!ivReady) { if (buffer.Size <= ivLen) @@ -145,6 +141,10 @@ namespace Shadowsocks.Encryption.Stream } byte[] cipher = buffer.ToArray(); cipherUpdate(false, cipher.Length, cipher, outbuf); + logger.DumpBase64($"cipher {instanceId}", cipher, cipher.Length); + logger.DumpBase64($"plain {instanceId}", outbuf, cipher.Length); + logger.Dump($"iv {instanceId}", iv, ivLen); + // move pointer only buffer.Skip(buffer.Size); outlength = cipher.Length; @@ -160,11 +160,11 @@ namespace Shadowsocks.Encryption.Stream // Generate IV RNG.GetBytes(outbuf, ivLen); initCipher(outbuf, true); - lock (_udpTmpBuf) + lock (udpBuffer) { - cipherUpdate(true, length, buf, _udpTmpBuf); + cipherUpdate(true, length, buf, udpBuffer); outlength = length + ivLen; - Buffer.BlockCopy(_udpTmpBuf, 0, outbuf, ivLen, length); + Buffer.BlockCopy(udpBuffer, 0, outbuf, ivLen, length); } } @@ -173,11 +173,11 @@ namespace Shadowsocks.Encryption.Stream // Get IV from first pos initCipher(buf, false); outlength = length - ivLen; - lock (_udpTmpBuf) + lock (udpBuffer) { // C# could be multi-threaded - Buffer.BlockCopy(buf, ivLen, _udpTmpBuf, 0, length - ivLen); - cipherUpdate(false, length - ivLen, _udpTmpBuf, outbuf); + Buffer.BlockCopy(buf, ivLen, udpBuffer, 0, length - ivLen); + cipherUpdate(false, length - ivLen, udpBuffer, outbuf); } } diff --git a/shadowsocks-csharp/Encryption/Stream/StreamRc4NativeEncryptor.cs b/shadowsocks-csharp/Encryption/Stream/StreamRc4NativeEncryptor.cs index 6ed35812..302d5fe7 100644 --- a/shadowsocks-csharp/Encryption/Stream/StreamRc4NativeEncryptor.cs +++ b/shadowsocks-csharp/Encryption/Stream/StreamRc4NativeEncryptor.cs @@ -14,7 +14,7 @@ namespace Shadowsocks.Encryption.Stream protected override void initCipher(byte[] iv, bool isEncrypt) { base.initCipher(iv, isEncrypt); - if (_cipher == CipherFamily.Rc4Md5) + if (cipherFamily == CipherFamily.Rc4Md5) { byte[] temp = new byte[keyLen + ivLen]; Array.Copy(key, 0, temp, 0, keyLen); diff --git a/shadowsocks-csharp/Encryption/Stream/StreamTableNativeEncryptor.cs b/shadowsocks-csharp/Encryption/Stream/StreamTableNativeEncryptor.cs index 67fdafff..7f1a6494 100644 --- a/shadowsocks-csharp/Encryption/Stream/StreamTableNativeEncryptor.cs +++ b/shadowsocks-csharp/Encryption/Stream/StreamTableNativeEncryptor.cs @@ -8,7 +8,8 @@ namespace Shadowsocks.Encryption.Stream { public class StreamTableNativeEncryptor : StreamEncryptor { - string _password; + // table mode use special way to generate key + readonly string _password; public StreamTableNativeEncryptor(string method, string password) : base(method, password) { @@ -17,28 +18,27 @@ namespace Shadowsocks.Encryption.Stream protected override void initCipher(byte[] iv, bool isEncrypt) { - base.initCipher(iv, isEncrypt); - if (_cipher == CipherFamily.Table) + // another cipher is plain, needn't a table + if (cipherFamily != CipherFamily.Table) return; + ulong a = BitConverter.ToUInt64(CryptoUtils.MD5(Encoding.UTF8.GetBytes(_password)), 0); + for (int i = 0; i < 256; i++) { - ulong a = BitConverter.ToUInt64(CryptoUtils.MD5(Encoding.UTF8.GetBytes(_password)), 0); - for (int i = 0; i < 256; i++) - { - _encryptTable[i] = (byte)i; - } - for (int i = 1; i < 1024; i++) - { - _encryptTable = MergeSort(_encryptTable, a, i); - } - for (int i = 0; i < 256; i++) - { - _decryptTable[_encryptTable[i]] = (byte)i; - } + _encryptTable[i] = (byte)i; + } + // copy array 1024 times? excuse me? + for (int i = 1; i < 1024; i++) + { + _encryptTable = MergeSort(_encryptTable, a, i); + } + for (int i = 0; i < 256; i++) + { + _decryptTable[_encryptTable[i]] = (byte)i; } } protected override void cipherUpdate(bool isEncrypt, int length, byte[] buf, byte[] outbuf) { - if (_cipher == CipherFamily.Table) + if (cipherFamily == CipherFamily.Table) { var table = isEncrypt ? _encryptTable : _decryptTable; for (int i = 0; i < length; i++) @@ -46,7 +46,7 @@ namespace Shadowsocks.Encryption.Stream outbuf[i] = table[buf[i]]; } } - else if (_cipher == CipherFamily.Plain) + else if (cipherFamily == CipherFamily.Plain) { Array.Copy(buf, outbuf, length); } @@ -54,7 +54,7 @@ namespace Shadowsocks.Encryption.Stream protected override int CipherDecrypt(Span plain, Span cipher) { - if (_cipher == CipherFamily.Plain) + if (cipherFamily == CipherFamily.Plain) { cipher.CopyTo(plain); return cipher.Length; @@ -69,7 +69,7 @@ namespace Shadowsocks.Encryption.Stream protected override int CipherEncrypt(Span plain, Span cipher) { - if (_cipher == CipherFamily.Plain) + if (cipherFamily == CipherFamily.Plain) { plain.CopyTo(cipher); return plain.Length; @@ -132,6 +132,7 @@ namespace Shadowsocks.Encryption.Stream int leftptr = 0; int rightptr = 0; + // why a new array? byte[] sorted = new byte[array.Length]; for (int k = 0; k < array.Length; k++) {