Browse Source

span based aead ChunkEncrypt, remove bouncycastle aead aes

pull/2865/head
Student Main 5 years ago
parent
commit
288b013fa2
4 changed files with 20 additions and 152 deletions
  1. +1
    -1
      shadowsocks-csharp/Encryption/AEAD/AEADAesGcmNativeEncryptor.cs
  2. +0
    -103
      shadowsocks-csharp/Encryption/AEAD/AEADBouncyCastleEncryptor.cs
  3. +19
    -40
      shadowsocks-csharp/Encryption/AEAD/AEADEncryptor.cs
  4. +0
    -8
      test/CryptographyTest.cs

+ 1
- 1
shadowsocks-csharp/Encryption/AEAD/AEADAesGcmNativeEncryptor.cs View File

@@ -77,7 +77,7 @@ namespace Shadowsocks.Encryption.AEAD
public override int CipherEncrypt(Span<byte> plain, Span<byte> 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;
}



+ 0
- 103
shadowsocks-csharp/Encryption/AEAD/AEADBouncyCastleEncryptor.cs View File

@@ -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<string, CipherInfo> _ciphers = new Dictionary<string, CipherInfo>
{
{"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<string, CipherInfo> getCiphers()
{
return _ciphers;
}
public static Dictionary<string, CipherInfo> 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<byte> plain, Span<byte> cipher)
{
throw new NotImplementedException();
}
public override int CipherDecrypt(Span<byte> plain, Span<byte> cipher)
{
throw new NotImplementedException();
}
}
}

+ 19
- 40
shadowsocks-csharp/Encryption/AEAD/AEADEncryptor.cs View File

@@ -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<byte> plain, Span<byte> cipher);
// plain -> cipher + tag
[Obsolete]
public abstract byte[] CipherEncrypt2(byte[] plain);
// cipher + tag -> plain
[Obsolete]
public abstract byte[] CipherDecrypt2(byte[] cipher);
public (Memory<byte>, Memory<byte>) 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<byte> plain, Span<byte> 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;
}
}
}

+ 0
- 8
test/CryptographyTest.cs View File

@@ -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()
{


Loading…
Cancel
Save