Browse Source

aead use span based CipherEncrypt/CipherDecrypt

pull/2865/head
Student Main 5 years ago
parent
commit
f8d1de8414
3 changed files with 29 additions and 163 deletions
  1. +3
    -43
      shadowsocks-csharp/Encryption/AEAD/AEADAesGcmNativeEncryptor.cs
  2. +24
    -94
      shadowsocks-csharp/Encryption/AEAD/AEADEncryptor.cs
  3. +2
    -26
      shadowsocks-csharp/Encryption/AEAD/AEADNaClEncryptor.cs

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

@@ -32,48 +32,6 @@ namespace Shadowsocks.Encryption.AEAD
}
#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<byte> plainMem = new Span<byte>(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<byte> d = new Span<byte>(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<byte> plain, Span<byte> cipher)
{
using var aes = new AesGcm(sessionKey);
@@ -85,7 +43,9 @@ namespace Shadowsocks.Encryption.AEAD
{
int clen = cipher.Length - tagLen;
using var aes = new AesGcm(sessionKey);
aes.Decrypt(nonce.AsSpan(), plain, cipher.Slice(0, clen), cipher.Slice(clen));
var ciphertxt = cipher.Slice(0, clen);
var tag = cipher.Slice(clen);
aes.Decrypt(nonce.AsSpan(), ciphertxt, tag, plain.Slice(0, clen));
return clen;
}
}

+ 24
- 94
shadowsocks-csharp/Encryption/AEAD/AEADEncryptor.cs View File

@@ -18,9 +18,6 @@ namespace Shadowsocks.Encryption.AEAD
private const string Info = "ss-subkey";
private static readonly byte[] InfoBytes = Encoding.ASCII.GetBytes(Info);
// for UDP only
protected static byte[] _udpTmpBuf = new byte[65536];
// every connection should create its own buffer
private ByteCircularBuffer buffer = new ByteCircularBuffer(MaxInputSize * 2);
@@ -29,19 +26,16 @@ namespace Shadowsocks.Encryption.AEAD
protected Dictionary<string, CipherInfo> ciphers;
protected string _method;
protected CipherFamily _cipher;
protected CipherFamily cipherFamily;
protected CipherInfo CipherInfo;
protected static byte[] masterKey = null;
protected byte[] sessionKey;
protected static byte[] masterKey = Array.Empty<byte>();
protected byte[] sessionKey = Array.Empty<byte>();
protected int keyLen;
protected int saltLen;
protected int tagLen;
protected int nonceLen;
protected byte[] salt;
protected object _nonceIncrementLock = new object();
protected byte[] nonce;
// Is first packet
@@ -53,29 +47,21 @@ namespace Shadowsocks.Encryption.AEAD
public AEADEncryptor(string method, string password)
: base(method, password)
{
InitEncryptorInfo(method);
InitKey(password);
// Initialize all-zero nonce for each connection
nonce = new byte[nonceLen];
nonce = new byte[nonceLen];
}
protected abstract Dictionary<string, CipherInfo> getCiphers();
protected void InitEncryptorInfo(string method)
{
method = method.ToLower();
_method = method;
ciphers = getCiphers();
CipherInfo = ciphers[_method];
_cipher = CipherInfo.Type;
CipherInfo = getCiphers()[method.ToLower()];
cipherFamily = CipherInfo.Type;
var parameter = (AEADCipherParameter)CipherInfo.CipherParameter;
keyLen = parameter.KeySize;
saltLen = parameter.SaltSize;
tagLen = parameter.TagSize;
nonceLen = parameter.NonceSize;
InitKey(password);
// Initialize all-zero nonce for each connection
nonce = new byte[nonceLen];
}
protected abstract Dictionary<string, CipherInfo> getCiphers();
protected void InitKey(string password)
{
byte[] passbuf = Encoding.UTF8.GetBytes(password);
@@ -84,7 +70,7 @@ namespace Shadowsocks.Encryption.AEAD
if (masterKey.Length != keyLen) Array.Resize(ref masterKey, keyLen);
DeriveKey(passbuf, masterKey, keyLen);
// init session key
if (sessionKey == null) sessionKey = new byte[keyLen];
sessionKey = new byte[keyLen];
}
public void DeriveKey(byte[] password, byte[] key, int keylen)
@@ -111,50 +97,9 @@ namespace Shadowsocks.Encryption.AEAD
DeriveSessionKey(salt, masterKey, sessionKey);
}
/// <summary>
///
/// </summary>
/// <param name="plaintext">Input, plain text</param>
/// <param name="plen">plaintext.Length</param>
/// <param name="ciphertext">Output, allocated by caller, tag space included,
/// length = plaintext.Length + tagLen, [enc][tag] order</param>
/// <param name="clen">Should be same as ciphertext.Length</param>
public abstract void cipherEncrypt(byte[] plaintext, uint plen, byte[] ciphertext, ref uint clen);
public abstract int CipherEncrypt(Span<byte> plain, Span<byte> cipher);
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)
{
var mc = cipher.AsMemory();
var clen = mc.Length - tagLen;
var c = mc.Slice(0, clen);
var t = mc.Slice(clen);
return (c, t);
}
public (byte[], byte[]) GetCipherTextAndTag(byte[] cipher)
{
var (c, t) = GetCipherTextAndTagMem(cipher);
return (c.ToArray(), t.ToArray());
}
/// <summary>
///
/// </summary>
/// <param name="ciphertext">Cipher text in [enc][tag] order</param>
/// <param name="clen">ciphertext.Length</param>
/// <param name="plaintext">Output plain text may with additional data allocated by caller</param>
/// <param name="plen">Output, should be used plain text length</param>
public abstract void cipherDecrypt(byte[] ciphertext, uint clen, byte[] plaintext, ref uint plen);
#region TCP
public override void Encrypt(byte[] buf, int length, byte[] outbuf, out int outlength)
@@ -266,7 +211,8 @@ namespace Shadowsocks.Encryption.AEAD
byte[] encLenBytes = buffer.Peek(ChunkLengthBytes + tagLen);
// try to dec chunk len
byte[] decChunkLenBytes = CipherDecrypt2(encLenBytes);
byte[] decChunkLenBytes = new byte[ChunkLengthBytes];
CipherDecrypt(decChunkLenBytes, encLenBytes);
ushort chunkLen = (ushort)IPAddress.NetworkToHostOrder((short)BitConverter.ToUInt16(decChunkLenBytes, 0));
if (chunkLen > ChunkLengthMask)
{
@@ -287,15 +233,17 @@ namespace Shadowsocks.Encryption.AEAD
// drop chunk len and its tag from buffer
buffer.Skip(ChunkLengthBytes + tagLen);
byte[] encChunkBytes = buffer.Get(chunkLen + tagLen);
byte[] decChunkBytes = CipherDecrypt2(encChunkBytes);
// byte[] decChunkBytes = CipherDecrypt2(encChunkBytes);
int len = CipherDecrypt(outbuf.AsSpan().Slice(outlength), encChunkBytes);
IncrementNonce();
#endregion
// output to outbuf
decChunkBytes.CopyTo(outbuf, outlength);
// decChunkBytes.CopyTo(outbuf, outlength);
// Buffer.BlockCopy(decChunkBytes, 0, outbuf, outlength, (int)decChunkLen);
outlength += decChunkBytes.Length;
outlength += len;
logger.Debug("aead dec outlength " + outlength);
if (outlength + 100 > TCPHandler.BufferSize)
{
@@ -326,36 +274,18 @@ namespace Shadowsocks.Encryption.AEAD
public override void EncryptUDP(byte[] buf, int length, byte[] outbuf, out int outlength)
{
// Generate salt
//RNG.GetBytes(outbuf, saltLen);
RNG.GetSpan(outbuf.AsSpan(0, saltLen));
InitCipher(outbuf, true, true);
//uint olen = 0;
lock (_udpTmpBuf)
{
//cipherEncrypt(buf, (uint)length, _udpTmpBuf, ref olen);
var plain = buf.AsSpan(0, length).ToArray(); // mmp
var cipher = CipherEncrypt2(plain);
//Debug.Assert(olen == length + tagLen);
Buffer.BlockCopy(cipher, 0, outbuf, saltLen, length + tagLen);
//Buffer.BlockCopy(_udpTmpBuf, 0, outbuf, saltLen, (int)olen);
outlength = saltLen + cipher.Length;
}
outlength = saltLen + CipherEncrypt(
buf.AsSpan(0, length),
outbuf.AsSpan(saltLen, length + tagLen));
}
public override void DecryptUDP(byte[] buf, int length, byte[] outbuf, out int outlength)
{
InitCipher(buf, false, true);
//uint olen = 0;
lock (_udpTmpBuf)
{
// copy remaining data to first pos
Buffer.BlockCopy(buf, saltLen, buf, 0, length - saltLen);
byte[] b = buf.AsSpan(0, length - saltLen).ToArray();
byte[] o = CipherDecrypt2(b);
//cipherDecrypt(buf, (uint)(length - saltLen), _udpTmpBuf, ref olen);
Buffer.BlockCopy(o, 0, outbuf, 0, o.Length);
outlength = o.Length;
}
outlength = CipherDecrypt(outbuf, buf.AsSpan(saltLen, length - saltLen));
}
#endregion


+ 2
- 26
shadowsocks-csharp/Encryption/AEAD/AEADNaClEncryptor.cs View File

@@ -37,7 +37,7 @@ namespace Shadowsocks.Encryption.AEAD
public override void InitCipher(byte[] salt, bool isEncrypt, bool isUdp)
{
base.InitCipher(salt, isEncrypt, isUdp);
switch (_cipher)
switch (cipherFamily)
{
default:
case CipherFamily.Chacha20Poly1305:
@@ -48,31 +48,7 @@ namespace Shadowsocks.Encryption.AEAD
break;
}
}

public override void cipherDecrypt(byte[] ciphertext, uint clen, byte[] plaintext, ref uint plen)
{
var pt = enc.Decrypt(ciphertext, null, nonce);
pt.CopyTo(plaintext, 0);
plen = (uint)pt.Length;
}

public override void cipherEncrypt(byte[] plaintext, uint plen, byte[] ciphertext, ref uint clen)
{
var ct = enc.Encrypt(plaintext, null, nonce);
ct.CopyTo(ciphertext, 0);
clen = (uint)ct.Length;
}

public override byte[] CipherEncrypt2(byte[] plain)
{
return enc.Encrypt(plain, null, nonce);
}

public override byte[] CipherDecrypt2(byte[] cipher)
{
return enc.Decrypt(cipher, null, nonce);
}

public override int CipherEncrypt(Span<byte> plain, Span<byte> cipher)
{
var ct = enc.Encrypt(plain, null, nonce);


Loading…
Cancel
Save