using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; namespace Shadowsocks.Encryption.AEAD { public class AEADAesGcmNativeEncryptor : AEADEncryptor { public AEADAesGcmNativeEncryptor(string method, string password) : base(method, password) { } #region Cipher Info private static readonly Dictionary _ciphers = new Dictionary { {"aes-128-gcm", new CipherInfo("aes-128-gcm", 16, 16, 12, 16, CipherFamily.AesGcm)}, {"aes-192-gcm", new CipherInfo("aes-192-gcm", 24, 24, 12, 16, CipherFamily.AesGcm)}, {"aes-256-gcm", new CipherInfo("aes-256-gcm", 32, 32, 12, 16, CipherFamily.AesGcm)}, }; protected override Dictionary getCiphers() { return _ciphers; } public static Dictionary SupportedCiphers() { return _ciphers; } #endregion public override void cipherDecrypt(byte[] ciphertext, uint clen, byte[] plaintext, ref uint plen) { using (var aes = new AesGcm(sessionKey)) { byte[] tag = new byte[tagLen]; byte[] cipherWithoutTag = new byte[clen]; Array.Copy(ciphertext, 0, cipherWithoutTag, 0, clen - tagLen); Array.Copy(ciphertext, clen - tagLen, tag, 0, tagLen); aes.Decrypt(nonce, ciphertext, cipherWithoutTag, tag); } } public override void cipherEncrypt(byte[] plaintext, uint plen, byte[] ciphertext, ref uint clen) { using (var aes = new AesGcm(sessionKey)) { byte[] tag = new byte[tagLen]; byte[] cipherWithoutTag = new byte[clen]; aes.Encrypt(nonce, plaintext, cipherWithoutTag, tag); cipherWithoutTag.CopyTo(ciphertext, 0); tag.CopyTo(ciphertext, clen); } } public override byte[] CipherDecrypt2(byte[] cipher) { var (cipherMem, tagMem) = GetCipherTextAndTagMem(cipher); Span plainMem = new Span(new byte[cipherMem.Length]); using var aes = new AesGcm(sessionKey); aes.Decrypt(nonce.AsSpan(), cipherMem.Span, tagMem.Span, plainMem); return plainMem.ToArray(); } public override byte[] CipherEncrypt2(byte[] plain) { Span d = new Span(new byte[plain.Length + tagLen]); using var aes = new AesGcm(sessionKey); aes.Encrypt(nonce.AsSpan(), plain.AsSpan(), d.Slice(0, plain.Length), d.Slice(plain.Length)); return d.ToArray(); } public override int CipherEncrypt(Span plain, Span cipher) { using var aes = new AesGcm(sessionKey); aes.Encrypt(nonce.AsSpan(), plain, cipher.Slice(0, plain.Length), cipher.Slice(plain.Length, tagLen)); return plain.Length + tagLen; } public override int CipherDecrypt(Span plain, Span cipher) { int clen = cipher.Length - tagLen; using var aes = new AesGcm(sessionKey); aes.Decrypt(nonce.AsSpan(), plain, cipher.Slice(0, clen), cipher.Slice(clen)); return clen; } } }