From 288b013fa26b09ef330c32aece4dd019bfeb4011 Mon Sep 17 00:00:00 2001 From: Student Main Date: Sun, 22 Mar 2020 16:39:14 +0800 Subject: [PATCH] span based aead ChunkEncrypt, remove bouncycastle aead aes --- .../AEAD/AEADAesGcmNativeEncryptor.cs | 2 +- .../AEAD/AEADBouncyCastleEncryptor.cs | 103 ------------------ .../Encryption/AEAD/AEADEncryptor.cs | 59 ++++------ test/CryptographyTest.cs | 8 -- 4 files changed, 20 insertions(+), 152 deletions(-) delete mode 100644 shadowsocks-csharp/Encryption/AEAD/AEADBouncyCastleEncryptor.cs diff --git a/shadowsocks-csharp/Encryption/AEAD/AEADAesGcmNativeEncryptor.cs b/shadowsocks-csharp/Encryption/AEAD/AEADAesGcmNativeEncryptor.cs index d46b9887..44177e3f 100644 --- a/shadowsocks-csharp/Encryption/AEAD/AEADAesGcmNativeEncryptor.cs +++ b/shadowsocks-csharp/Encryption/AEAD/AEADAesGcmNativeEncryptor.cs @@ -77,7 +77,7 @@ namespace Shadowsocks.Encryption.AEAD 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)); + aes.Encrypt(nonce.AsSpan(), plain, cipher.Slice(0, plain.Length), cipher.Slice(plain.Length, tagLen)); return plain.Length + tagLen; } diff --git a/shadowsocks-csharp/Encryption/AEAD/AEADBouncyCastleEncryptor.cs b/shadowsocks-csharp/Encryption/AEAD/AEADBouncyCastleEncryptor.cs deleted file mode 100644 index c2dd81e9..00000000 --- a/shadowsocks-csharp/Encryption/AEAD/AEADBouncyCastleEncryptor.cs +++ /dev/null @@ -1,103 +0,0 @@ -using Org.BouncyCastle.Crypto.Engines; -using Org.BouncyCastle.Crypto.Modes; -using Org.BouncyCastle.Crypto.Parameters; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Shadowsocks.Encryption.AEAD -{ - public class AEADBouncyCastleEncryptor : AEADEncryptor - { - public AEADBouncyCastleEncryptor(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 InitCipher(byte[] salt, bool isEncrypt, bool isUdp) - { - base.InitCipher(salt, isEncrypt, isUdp); - - DeriveSessionKey(salt, masterKey, sessionKey); - } - - public override void cipherDecrypt(byte[] ciphertext, uint clen, byte[] plaintext, ref uint plen) - { - var cipher = new GcmBlockCipher(new AesEngine()); - AeadParameters parameters = new AeadParameters(new KeyParameter(sessionKey), tagLen * 8, nonce); - - cipher.Init(false, parameters); - var len = cipher.ProcessBytes(ciphertext, 0, ciphertext.Length, plaintext, 0); - cipher.DoFinal(plaintext, len); - } - - public override void cipherEncrypt(byte[] plaintext, uint plen, byte[] ciphertext, ref uint clen) - { - var cipher = new GcmBlockCipher(new AesEngine()); - AeadParameters parameters = new AeadParameters(new KeyParameter(sessionKey), tagLen * 8, nonce); - - cipher.Init(true, parameters); - var ciphertextBC = new byte[cipher.GetOutputSize((int)plen)]; - var len = cipher.ProcessBytes(plaintext, 0, (int)plen, ciphertextBC, 0); - cipher.DoFinal(ciphertextBC, len); - clen = (uint)(ciphertextBC.Length); - Array.Copy(ciphertextBC, 0, ciphertext, 0, clen); - } - - public override byte[] CipherDecrypt2(byte[] cipher) - { - var aes = new GcmBlockCipher(new AesEngine()); - AeadParameters parameters = new AeadParameters(new KeyParameter(sessionKey), tagLen * 8, nonce); - - aes.Init(false, parameters); - byte[] plain = new byte[aes.GetOutputSize(cipher.Length)]; - var len = aes.ProcessBytes(cipher, 0, cipher.Length, plain, 0); - aes.DoFinal(plain, len); - - return plain; - } - - public override byte[] CipherEncrypt2(byte[] plain) - { - var aes = new GcmBlockCipher(new AesEngine()); - AeadParameters parameters = new AeadParameters(new KeyParameter(sessionKey), tagLen * 8, nonce); - - aes.Init(true, parameters); - var cipher = new byte[aes.GetOutputSize(plain.Length)]; - - var len = aes.ProcessBytes(plain, 0, plain.Length, cipher, 0); - aes.DoFinal(cipher, len); - return cipher; - } - - public override int CipherEncrypt(Span plain, Span cipher) - { - throw new NotImplementedException(); - } - - public override int CipherDecrypt(Span plain, Span cipher) - { - throw new NotImplementedException(); - } - } -} diff --git a/shadowsocks-csharp/Encryption/AEAD/AEADEncryptor.cs b/shadowsocks-csharp/Encryption/AEAD/AEADEncryptor.cs index 370592de..bafe5c5f 100644 --- a/shadowsocks-csharp/Encryption/AEAD/AEADEncryptor.cs +++ b/shadowsocks-csharp/Encryption/AEAD/AEADEncryptor.cs @@ -98,12 +98,9 @@ namespace Shadowsocks.Encryption.AEAD CryptoUtils.HKDF(keyLen, masterKey, salt, InfoBytes).CopyTo(sessionKey, 0); } - protected void IncrementNonce(bool isEncrypt) + protected void IncrementNonce() { - lock (_nonceIncrementLock) - { - CryptoUtils.SodiumIncrement(isEncrypt ? nonce : nonce); - } + CryptoUtils.SodiumIncrement(nonce); } public virtual void InitCipher(byte[] salt, bool isEncrypt, bool isUdp) @@ -129,8 +126,10 @@ namespace Shadowsocks.Encryption.AEAD public abstract int CipherDecrypt(Span plain, Span cipher); // plain -> cipher + tag + [Obsolete] public abstract byte[] CipherEncrypt2(byte[] plain); // cipher + tag -> plain + [Obsolete] public abstract byte[] CipherDecrypt2(byte[] cipher); public (Memory, Memory) GetCipherTextAndTagMem(byte[] cipher) @@ -181,10 +180,10 @@ namespace Shadowsocks.Encryption.AEAD { tcpRequestSent = true; // The first TCP request - int encAddrBufLength; byte[] encAddrBufBytes = new byte[AddressBufferLength + tagLen * 2 + CHUNK_LEN_BYTES]; byte[] addrBytes = buffer.Get(AddressBufferLength); - ChunkEncrypt(addrBytes, AddressBufferLength, encAddrBufBytes, out encAddrBufLength); + int encAddrBufLength = ChunkEncrypt(addrBytes, encAddrBufBytes); + // ChunkEncrypt(addrBytes, AddressBufferLength, encAddrBufBytes, out encAddrBufLength); Debug.Assert(encAddrBufLength == AddressBufferLength + tagLen * 2 + CHUNK_LEN_BYTES); Array.Copy(encAddrBufBytes, 0, outbuf, outlength, encAddrBufLength); outlength += encAddrBufLength; @@ -198,9 +197,9 @@ namespace Shadowsocks.Encryption.AEAD if (bufSize <= 0) return; var chunklength = (int)Math.Min(bufSize, CHUNK_LEN_MASK); byte[] chunkBytes = buffer.Get(chunklength); - int encChunkLength; byte[] encChunkBytes = new byte[chunklength + tagLen * 2 + CHUNK_LEN_BYTES]; - ChunkEncrypt(chunkBytes, chunklength, encChunkBytes, out encChunkLength); + int encChunkLength = ChunkEncrypt(chunkBytes, encChunkBytes); + // ChunkEncrypt(chunkBytes, chunklength, encChunkBytes, out encChunkLength); Debug.Assert(encChunkLength == chunklength + tagLen * 2 + CHUNK_LEN_BYTES); Buffer.BlockCopy(encChunkBytes, 0, outbuf, outlength, encChunkLength); outlength += encChunkLength; @@ -266,15 +265,9 @@ namespace Shadowsocks.Encryption.AEAD #region Chunk Decryption byte[] encLenBytes = buffer.Peek(CHUNK_LEN_BYTES + tagLen); - //uint decChunkLenLength = 0; - //byte[] decChunkLenBytes = new byte[CHUNK_LEN_BYTES]; - // try to dec chunk len - //cipherDecrypt(encLenBytes, CHUNK_LEN_BYTES + (uint)tagLen, decChunkLenBytes, ref decChunkLenLength); - + // try to dec chunk len byte[] decChunkLenBytes = CipherDecrypt2(encLenBytes); - // Debug.Assert(decChunkLenLength == CHUNK_LEN_BYTES); - // finally we get the real chunk len ushort chunkLen = (ushort)IPAddress.NetworkToHostOrder((short)BitConverter.ToUInt16(decChunkLenBytes, 0)); if (chunkLen > CHUNK_LEN_MASK) { @@ -289,18 +282,14 @@ namespace Shadowsocks.Encryption.AEAD logger.Debug("No more data to decrypt one chunk"); return; } - IncrementNonce(false); + IncrementNonce(); // we have enough data to decrypt one chunk // drop chunk len and its tag from buffer buffer.Skip(CHUNK_LEN_BYTES + tagLen); byte[] encChunkBytes = buffer.Get(chunkLen + tagLen); - //byte[] decChunkBytes = new byte[chunkLen]; - //uint decChunkLen = 0; - //cipherDecrypt(encChunkBytes, chunkLen + (uint)tagLen, decChunkBytes, ref decChunkLen); byte[] decChunkBytes = CipherDecrypt2(encChunkBytes); - //Debug.Assert(decChunkLen == chunkLen); - IncrementNonce(false); + IncrementNonce(); #endregion @@ -372,31 +361,21 @@ namespace Shadowsocks.Encryption.AEAD #endregion - // we know the plaintext length before encryption, so we can do it in one operation - // plain -> [len][data] - private void ChunkEncrypt(byte[] plaintext, int plainLen, byte[] ciphertext, out int cipherLen) + private int ChunkEncrypt(Span plain, Span cipher) { - if (plainLen > CHUNK_LEN_MASK) + if (plain.Length > CHUNK_LEN_MASK) { logger.Error("enc chunk too big"); throw new CryptoErrorException(); } - // encrypt len - // always 2 byte - byte[] lenbuf = BitConverter.GetBytes((ushort)IPAddress.HostToNetworkOrder((short)plainLen)); - - byte[] encLenBytes = CipherEncrypt2(lenbuf); - IncrementNonce(true); - - // encrypt corresponding data - byte[] encBytes = CipherEncrypt2(plaintext); - IncrementNonce(true); + byte[] lenbuf = BitConverter.GetBytes((ushort)IPAddress.HostToNetworkOrder((short)plain.Length)); + int cipherLenSize = CipherEncrypt(lenbuf, cipher); + IncrementNonce(); + int cipherDataSize = CipherEncrypt(plain, cipher.Slice(cipherLenSize)); + IncrementNonce(); - // construct outbuf - encLenBytes.CopyTo(ciphertext, 0); - encBytes.CopyTo(ciphertext, encLenBytes.Length); - cipherLen = encLenBytes.Length + encBytes.Length; + return cipherLenSize + cipherDataSize; } } } \ No newline at end of file diff --git a/test/CryptographyTest.cs b/test/CryptographyTest.cs index ed194f3a..3294ab09 100644 --- a/test/CryptographyTest.cs +++ b/test/CryptographyTest.cs @@ -110,14 +110,6 @@ namespace Shadowsocks.Test Assert.IsFalse(encryptionFailed); } - [TestMethod] - public void TestBouncyCastleAEADEncryption() - { - TestEncryptionMethod(typeof(AEADBouncyCastleEncryptor), "aes-128-gcm"); - TestEncryptionMethod(typeof(AEADBouncyCastleEncryptor), "aes-192-gcm"); - TestEncryptionMethod(typeof(AEADBouncyCastleEncryptor), "aes-256-gcm"); - } - [TestMethod] public void TestAesGcmNativeAEADEncryption() {