using System; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; namespace Shadowsocks.Encryption.Stream { public class StreamTableNativeEncryptor : StreamEncryptor { // table mode use special way to generate key readonly string _password; public StreamTableNativeEncryptor(string method, string password) : base(method, password) { _password = password; } protected override void initCipher(byte[] iv, bool isEncrypt) { // 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++) { _encryptTable[i] = (byte)i; } Span t = _encryptTable; // copy array 1024 times? excuse me? for (int i = 1; i < 1024; i++) { t = MergeSort(t, a, i); } _encryptTable = t.ToArray(); 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 (cipherFamily == CipherFamily.Table) { var table = isEncrypt ? _encryptTable : _decryptTable; for (int i = 0; i < length; i++) { outbuf[i] = table[buf[i]]; } } else if (cipherFamily == CipherFamily.Plain) { Array.Copy(buf, outbuf, length); } } protected override int CipherDecrypt(Span plain, Span cipher) { if (cipherFamily == CipherFamily.Plain) { cipher.CopyTo(plain); return cipher.Length; } for (int i = 0; i < cipher.Length; i++) { plain[i] = _decryptTable[cipher[i]]; } return cipher.Length; } protected override int CipherEncrypt(Span plain, Span cipher) { if (cipherFamily == CipherFamily.Plain) { plain.CopyTo(cipher); return plain.Length; } for (int i = 0; i < plain.Length; i++) { cipher[i] = _decryptTable[plain[i]]; } return plain.Length; } #region Cipher Info private static readonly Dictionary _ciphers = new Dictionary { {"plain", new CipherInfo("plain", 0, 0, CipherFamily.Plain) }, {"table", new CipherInfo("table", 0, 0, CipherFamily.Table) }, }; public static Dictionary SupportedCiphers() { return _ciphers; } protected override Dictionary getCiphers() { return _ciphers; } #endregion #region Table private byte[] _encryptTable = new byte[256]; private byte[] _decryptTable = new byte[256]; private byte[] _tmp = new byte[256]; [MethodImpl(MethodImplOptions.AggressiveInlining)] private static long Compare(byte x, byte y, ulong a, int i) { return (long)(a % (ulong)(x + i)) - (long)(a % (ulong)(y + i)); } byte[] buf = new byte[1024]; private Span MergeSort(Span array, ulong a, int j) { if (array.Length == 1) { return array; } int middle = array.Length / 2; Span left = MergeSort(array.Slice(0, middle), a, j);; Span right = MergeSort(array.Slice(middle), a, j); int leftptr = 0; int rightptr = 0; // why a new array? Span sorted = new byte[array.Length];// buf.AsSpan().Slice(0,array.Length); // // _tmp; for (int k = 0; k < array.Length; k++) { if (rightptr == right.Length || ((leftptr < left.Length) && (Compare(left[leftptr], right[rightptr], a, j) <= 0))) { sorted[k] = left[leftptr]; leftptr++; } else if (leftptr == left.Length || ((rightptr < right.Length) && (Compare(right[rightptr], left[leftptr], a, j)) <= 0)) { sorted[k] = right[rightptr]; rightptr++; } } return sorted; } #endregion } }