#nullable enable using CryptoBase; using CryptoBase.Abstractions.SymmetricCryptos; using CryptoBase.Digests.MD5; using System; using System.Collections.Generic; using System.Runtime.CompilerServices; namespace Shadowsocks.Net.Crypto.Stream { public class StreamCryptoBaseCrypto : StreamCrypto { private IStreamCrypto? _crypto; public StreamCryptoBaseCrypto(string method, string password) : base(method, password) { } protected override void InitCipher(byte[] iv, bool isEncrypt) { base.InitCipher(iv, isEncrypt); _crypto?.Dispose(); if (cipherFamily == CipherFamily.Rc4Md5) { Span temp = stackalloc byte[keyLen + ivLen]; var realKey = new byte[MD5Length]; key.CopyTo(temp); iv.CopyTo(temp.Slice(keyLen)); MD5Utils.Fast440(temp, realKey); _crypto = StreamCryptoCreate.Rc4(realKey); return; } _crypto = cipherFamily switch { CipherFamily.AesCfb => StreamCryptoCreate.AesCfb(isEncrypt, key, iv), CipherFamily.Chacha20 => StreamCryptoCreate.ChaCha20(key, iv), CipherFamily.Rc4 => StreamCryptoCreate.Rc4(key), _ => throw new NotSupportedException() }; } protected override int CipherEncrypt(ReadOnlySpan plain, Span cipher) { return CipherUpdate(plain, cipher); } protected override int CipherDecrypt(Span plain, ReadOnlySpan cipher) { return CipherUpdate(cipher, plain); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private int CipherUpdate(ReadOnlySpan input, Span output) { _crypto!.Update(input, output); return input.Length; } #region Cipher Info private static readonly Dictionary _ciphers = new() { { "aes-128-cfb", new CipherInfo("aes-128-cfb", 16, 16, CipherFamily.AesCfb, CipherStandardState.Unstable) }, { "aes-192-cfb", new CipherInfo("aes-192-cfb", 24, 16, CipherFamily.AesCfb, CipherStandardState.Unstable) }, { "aes-256-cfb", new CipherInfo("aes-256-cfb", 32, 16, CipherFamily.AesCfb, CipherStandardState.Unstable) }, { "chacha20-ietf", new CipherInfo("chacha20-ietf", 32, 12, CipherFamily.Chacha20) }, { "rc4", new CipherInfo("rc4", 16, 0, CipherFamily.Rc4) }, { "rc4-md5", new CipherInfo("rc4-md5", 16, 16, CipherFamily.Rc4Md5) }, }; public static Dictionary SupportedCiphers() { return _ciphers; } protected override Dictionary GetCiphers() { return _ciphers; } #endregion public override void Dispose() { _crypto?.Dispose(); } } }