Browse Source

remove excessive state in Encryptor, as we use 2 encryptor per connection.

pull/2865/head
Student Main 5 years ago
parent
commit
0497ce88ff
7 changed files with 139 additions and 154 deletions
  1. +5
    -30
      shadowsocks-csharp/Encryption/AEAD/AEADAesGcmNativeEncryptor.cs
  2. +5
    -9
      shadowsocks-csharp/Encryption/AEAD/AEADBouncyCastleEncryptor.cs
  3. +37
    -50
      shadowsocks-csharp/Encryption/AEAD/AEADEncryptor.cs
  4. +7
    -12
      shadowsocks-csharp/Encryption/AEAD/AEADNaClEncryptor.cs
  5. +29
    -40
      shadowsocks-csharp/Encryption/Stream/StreamEncryptor.cs
  6. +24
    -13
      shadowsocks-csharp/Encryption/Stream/StreamRc4NativeEncryptor.cs
  7. +32
    -0
      shadowsocks-csharp/Encryption/Stream/StreamTableNativeEncryptor.cs

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

@@ -30,8 +30,7 @@ namespace Shadowsocks.Encryption.AEAD
{
base.InitCipher(salt, isEncrypt, isUdp);

DeriveSessionKey(isEncrypt ? encryptSalt : decryptSalt,
_Masterkey, sessionKey);
DeriveSessionKey(salt, masterKey, sessionKey);
}

public override void cipherDecrypt(byte[] ciphertext, uint clen, byte[] plaintext, ref uint plen)
@@ -42,17 +41,8 @@ namespace Shadowsocks.Encryption.AEAD
byte[] cipherWithoutTag = new byte[clen];
Array.Copy(ciphertext, 0, cipherWithoutTag, 0, clen - tagLen);
Array.Copy(ciphertext, clen - tagLen, tag, 0, tagLen);
aes.Decrypt(decNonce, ciphertext, cipherWithoutTag, tag);
aes.Decrypt(nonce, ciphertext, cipherWithoutTag, tag);
}
/*var cipher = new GcmBlockCipher(new AesEngine());
AeadParameters parameters = new AeadParameters(new KeyParameter(_sessionKey), tagLen * 8, _decNonce);

cipher.Init(false, parameters);
var plaintextBC = new byte[cipher.GetOutputSize((int)clen)];
var len = cipher.ProcessBytes(ciphertext, 0, (int)clen, plaintextBC, 0);
cipher.DoFinal(plaintextBC, len);
plen = (uint)(plaintextBC.Length);
Array.Copy(plaintextBC, 0, plaintext, 0, plen);*/
}

public override void cipherEncrypt(byte[] plaintext, uint plen, byte[] ciphertext, ref uint clen)
@@ -61,21 +51,10 @@ namespace Shadowsocks.Encryption.AEAD
{
byte[] tag = new byte[tagLen];
byte[] cipherWithoutTag = new byte[clen];
aes.Encrypt(encNonce, plaintext, cipherWithoutTag, tag);
aes.Encrypt(nonce, plaintext, cipherWithoutTag, tag);
cipherWithoutTag.CopyTo(ciphertext, 0);
tag.CopyTo(ciphertext, clen);
}

/*
var cipher = new GcmBlockCipher(new AesEngine());
AeadParameters parameters = new AeadParameters(new KeyParameter(_sessionKey), tagLen * 8, _encNonce);

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)
@@ -84,19 +63,15 @@ namespace Shadowsocks.Encryption.AEAD
Span<byte> plainMem = new Span<byte>(new byte[cipherMem.Length]);

using var aes = new AesGcm(sessionKey);
aes.Decrypt(decNonce.AsSpan(), cipherMem.Span, tagMem.Span, plainMem);
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]);

//Span<byte> cipherMem = new Span<byte>(new byte[plain.Length]);
//Span<byte> tagMem = new Span<byte>(new byte[tagLen]);

using var aes = new AesGcm(sessionKey);
aes.Encrypt(encNonce.AsSpan(), plain.AsSpan(), d.Slice(0, plain.Length), d.Slice(plain.Length));
aes.Encrypt(nonce.AsSpan(), plain.AsSpan(), d.Slice(0, plain.Length), d.Slice(plain.Length));

return d.ToArray();
}


+ 5
- 9
shadowsocks-csharp/Encryption/AEAD/AEADBouncyCastleEncryptor.cs View File

@@ -32,27 +32,23 @@ namespace Shadowsocks.Encryption.AEAD
{
base.InitCipher(salt, isEncrypt, isUdp);
DeriveSessionKey(isEncrypt ? encryptSalt : decryptSalt,
_Masterkey, sessionKey);
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, decNonce);
AeadParameters parameters = new AeadParameters(new KeyParameter(sessionKey), tagLen * 8, nonce);
cipher.Init(false, parameters);
//var plaintextBC = new byte[cipher.GetOutputSize(ciphertext.Length)];
var len = cipher.ProcessBytes(ciphertext, 0, ciphertext.Length, plaintext, 0);
cipher.DoFinal(plaintext, len);
//plen = (uint)(plaintext.Length);
//Array.Copy(plaintextBC, 0, plaintext, 0, plaintext.Length);
}
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, encNonce);
AeadParameters parameters = new AeadParameters(new KeyParameter(sessionKey), tagLen * 8, nonce);
cipher.Init(true, parameters);
var ciphertextBC = new byte[cipher.GetOutputSize((int)plen)];
@@ -65,7 +61,7 @@ namespace Shadowsocks.Encryption.AEAD
public override byte[] CipherDecrypt2(byte[] cipher)
{
var aes = new GcmBlockCipher(new AesEngine());
AeadParameters parameters = new AeadParameters(new KeyParameter(sessionKey), tagLen * 8, decNonce);
AeadParameters parameters = new AeadParameters(new KeyParameter(sessionKey), tagLen * 8, nonce);
aes.Init(false, parameters);
byte[] plain = new byte[aes.GetOutputSize(cipher.Length)];
@@ -78,7 +74,7 @@ namespace Shadowsocks.Encryption.AEAD
public override byte[] CipherEncrypt2(byte[] plain)
{
var aes = new GcmBlockCipher(new AesEngine());
AeadParameters parameters = new AeadParameters(new KeyParameter(sessionKey), tagLen * 8, encNonce);
AeadParameters parameters = new AeadParameters(new KeyParameter(sessionKey), tagLen * 8, nonce);
aes.Init(true, parameters);
var cipher = new byte[aes.GetOutputSize(plain.Length)];


+ 37
- 50
shadowsocks-csharp/Encryption/AEAD/AEADEncryptor.cs View File

@@ -22,8 +22,8 @@ namespace Shadowsocks.Encryption.AEAD
protected static byte[] _udpTmpBuf = new byte[65536];
// every connection should create its own buffer
private ByteCircularBuffer _encCircularBuffer = new ByteCircularBuffer(MAX_INPUT_SIZE * 2);
private ByteCircularBuffer _decCircularBuffer = new ByteCircularBuffer(MAX_INPUT_SIZE * 2);
private ByteCircularBuffer buffer = new ByteCircularBuffer(MAX_INPUT_SIZE * 2);
// private ByteCircularBuffer buffer = new ByteCircularBuffer(MAX_INPUT_SIZE * 2);
public const int CHUNK_LEN_BYTES = 2;
public const uint CHUNK_LEN_MASK = 0x3FFFu;
@@ -32,29 +32,24 @@ namespace Shadowsocks.Encryption.AEAD
protected string _method;
protected CipherFamily _cipher;
// internal name in the crypto library
protected string _innerLibName;
protected CipherInfo CipherInfo;
protected static byte[] _Masterkey = null;
protected static byte[] masterKey = null;
protected byte[] sessionKey;
protected int keyLen;
protected int saltLen;
protected int tagLen;
protected int nonceLen;
protected byte[] encryptSalt;
protected byte[] decryptSalt;
protected byte[] salt;
protected object _nonceIncrementLock = new object();
protected byte[] encNonce;
protected byte[] decNonce;
protected byte[] nonce;
// Is first packet
protected bool _decryptSaltReceived;
protected bool _encryptSaltSent;
protected bool saltReady;
// Is first chunk(tcp request)
protected bool _tcpRequestSent;
protected bool tcpRequestSent;
public AEADEncryptor(string method, string password)
: base(method, password)
@@ -62,8 +57,8 @@ namespace Shadowsocks.Encryption.AEAD
InitEncryptorInfo(method);
InitKey(password);
// Initialize all-zero nonce for each connection
encNonce = new byte[nonceLen];
decNonce = new byte[nonceLen];
nonce = new byte[nonceLen];
nonce = new byte[nonceLen];
}
protected abstract Dictionary<string, CipherInfo> getCiphers();
@@ -86,9 +81,9 @@ namespace Shadowsocks.Encryption.AEAD
{
byte[] passbuf = Encoding.UTF8.GetBytes(password);
// init master key
if (_Masterkey == null) _Masterkey = new byte[keyLen];
if (_Masterkey.Length != keyLen) Array.Resize(ref _Masterkey, keyLen);
DeriveKey(passbuf, _Masterkey, keyLen);
if (masterKey == null) masterKey = new byte[keyLen];
if (masterKey.Length != keyLen) Array.Resize(ref masterKey, keyLen);
DeriveKey(passbuf, masterKey, keyLen);
// init session key
if (sessionKey == null) sessionKey = new byte[keyLen];
}
@@ -107,22 +102,14 @@ namespace Shadowsocks.Encryption.AEAD
{
lock (_nonceIncrementLock)
{
CryptoUtils.SodiumIncrement(isEncrypt ? encNonce : decNonce);
CryptoUtils.SodiumIncrement(isEncrypt ? nonce : nonce);
}
}
public virtual void InitCipher(byte[] salt, bool isEncrypt, bool isUdp)
{
if (isEncrypt)
{
encryptSalt = new byte[saltLen];
Array.Copy(salt, encryptSalt, saltLen);
}
else
{
decryptSalt = new byte[saltLen];
Array.Copy(salt, decryptSalt, saltLen);
}
this.salt = new byte[saltLen];
Array.Copy(salt, this.salt, saltLen);
logger.Dump("Salt", salt, saltLen);
}
@@ -169,14 +156,14 @@ namespace Shadowsocks.Encryption.AEAD
public override void Encrypt(byte[] buf, int length, byte[] outbuf, out int outlength)
{
Debug.Assert(_encCircularBuffer != null, "_encCircularBuffer != null");
Debug.Assert(buffer != null, "_encCircularBuffer != null");
_encCircularBuffer.Put(buf, 0, length);
buffer.Put(buf, 0, length);
outlength = 0;
logger.Debug("---Start Encryption");
if (!_encryptSaltSent)
if (!saltReady)
{
_encryptSaltSent = true;
saltReady = true;
// Generate salt
byte[] saltBytes = RNG.GetBytes(saltLen);
InitCipher(saltBytes, true, false);
@@ -185,13 +172,13 @@ namespace Shadowsocks.Encryption.AEAD
logger.Debug($"_encryptSaltSent outlength {outlength}");
}
if (!_tcpRequestSent)
if (!tcpRequestSent)
{
_tcpRequestSent = true;
tcpRequestSent = true;
// The first TCP request
int encAddrBufLength;
byte[] encAddrBufBytes = new byte[AddressBufferLength + tagLen * 2 + CHUNK_LEN_BYTES];
byte[] addrBytes = _encCircularBuffer.Get(AddressBufferLength);
byte[] addrBytes = buffer.Get(AddressBufferLength);
ChunkEncrypt(addrBytes, AddressBufferLength, encAddrBufBytes, out encAddrBufLength);
Debug.Assert(encAddrBufLength == AddressBufferLength + tagLen * 2 + CHUNK_LEN_BYTES);
Array.Copy(encAddrBufBytes, 0, outbuf, outlength, encAddrBufLength);
@@ -202,10 +189,10 @@ namespace Shadowsocks.Encryption.AEAD
// handle other chunks
while (true)
{
uint bufSize = (uint)_encCircularBuffer.Size;
uint bufSize = (uint)buffer.Size;
if (bufSize <= 0) return;
var chunklength = (int)Math.Min(bufSize, CHUNK_LEN_MASK);
byte[] chunkBytes = _encCircularBuffer.Get(chunklength);
byte[] chunkBytes = buffer.Get(chunklength);
int encChunkLength;
byte[] encChunkBytes = new byte[chunklength + tagLen * 2 + CHUNK_LEN_BYTES];
ChunkEncrypt(chunkBytes, chunklength, encChunkBytes, out encChunkLength);
@@ -219,7 +206,7 @@ namespace Shadowsocks.Encryption.AEAD
logger.Debug("enc outbuf almost full, giving up");
return;
}
bufSize = (uint)_encCircularBuffer.Size;
bufSize = (uint)buffer.Size;
if (bufSize <= 0)
{
logger.Debug("No more data to encrypt, leaving");
@@ -231,24 +218,24 @@ namespace Shadowsocks.Encryption.AEAD
public override void Decrypt(byte[] buf, int length, byte[] outbuf, out int outlength)
{
Debug.Assert(_decCircularBuffer != null, "_decCircularBuffer != null");
Debug.Assert(buffer != null, "_decCircularBuffer != null");
int bufSize;
outlength = 0;
// drop all into buffer
_decCircularBuffer.Put(buf, 0, length);
buffer.Put(buf, 0, length);
logger.Debug("---Start Decryption");
if (!_decryptSaltReceived)
if (!saltReady)
{
bufSize = _decCircularBuffer.Size;
bufSize = buffer.Size;
// check if we get the leading salt
if (bufSize <= saltLen)
{
// need more
return;
}
_decryptSaltReceived = true;
byte[] salt = _decCircularBuffer.Get(saltLen);
saltReady = true;
byte[] salt = buffer.Get(saltLen);
InitCipher(salt, false, false);
logger.Debug("get salt len " + saltLen);
}
@@ -256,7 +243,7 @@ namespace Shadowsocks.Encryption.AEAD
// handle chunks
while (true)
{
bufSize = _decCircularBuffer.Size;
bufSize = buffer.Size;
// check if we have any data
if (bufSize <= 0)
{
@@ -273,7 +260,7 @@ namespace Shadowsocks.Encryption.AEAD
#region Chunk Decryption
byte[] encLenBytes = _decCircularBuffer.Peek(CHUNK_LEN_BYTES + tagLen);
byte[] encLenBytes = buffer.Peek(CHUNK_LEN_BYTES + tagLen);
//uint decChunkLenLength = 0;
//byte[] decChunkLenBytes = new byte[CHUNK_LEN_BYTES];
// try to dec chunk len
@@ -291,7 +278,7 @@ namespace Shadowsocks.Encryption.AEAD
throw new CryptoErrorException();
}
logger.Debug("Get the real chunk len:" + chunkLen);
bufSize = _decCircularBuffer.Size;
bufSize = buffer.Size;
if (bufSize < CHUNK_LEN_BYTES + tagLen /* we haven't remove them */+ chunkLen + tagLen)
{
logger.Debug("No more data to decrypt one chunk");
@@ -301,8 +288,8 @@ namespace Shadowsocks.Encryption.AEAD
// we have enough data to decrypt one chunk
// drop chunk len and its tag from buffer
_decCircularBuffer.Skip(CHUNK_LEN_BYTES + tagLen);
byte[] encChunkBytes = _decCircularBuffer.Get(chunkLen + tagLen);
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);
@@ -322,7 +309,7 @@ namespace Shadowsocks.Encryption.AEAD
logger.Debug("dec outbuf almost full, giving up");
return;
}
bufSize = _decCircularBuffer.Size;
bufSize = buffer.Size;
// check if we already done all of them
if (bufSize <= 0)
{


+ 7
- 12
shadowsocks-csharp/Encryption/AEAD/AEADNaClEncryptor.cs View File

@@ -12,7 +12,6 @@ namespace Shadowsocks.Encryption.AEAD
{

SnufflePoly1305 enc;
SnufflePoly1305 dec;
public AEADNaClEncryptor(string method, string password) : base(method, password)
{
}
@@ -20,34 +19,30 @@ namespace Shadowsocks.Encryption.AEAD
public override void InitCipher(byte[] salt, bool isEncrypt, bool isUdp)
{
base.InitCipher(salt, isEncrypt, isUdp);
DeriveSessionKey(isEncrypt ? encryptSalt : decryptSalt,
_Masterkey, sessionKey);
DeriveSessionKey(salt, masterKey, sessionKey);

SnufflePoly1305 tmp;
switch (_cipher)
{
default:
case CipherFamily.Chacha20Poly1305:
tmp = new ChaCha20Poly1305(sessionKey);
enc = new ChaCha20Poly1305(sessionKey);
break;
case CipherFamily.XChacha20Poly1305:
tmp = new XChaCha20Poly1305(sessionKey);
enc = new XChaCha20Poly1305(sessionKey);
break;
}
if (isEncrypt) enc = tmp;
else dec = tmp;
}

public override void cipherDecrypt(byte[] ciphertext, uint clen, byte[] plaintext, ref uint plen)
{
var pt = dec.Decrypt(ciphertext, null, decNonce);
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, encNonce);
var ct = enc.Encrypt(plaintext, null, nonce);
ct.CopyTo(ciphertext, 0);
clen = (uint)ct.Length;
}
@@ -70,12 +65,12 @@ namespace Shadowsocks.Encryption.AEAD

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

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

+ 29
- 40
shadowsocks-csharp/Encryption/Stream/StreamEncryptor.cs View File

@@ -13,25 +13,20 @@ namespace Shadowsocks.Encryption.Stream
protected static byte[] _udpTmpBuf = new byte[65536];
// every connection should create its own buffer
private ByteCircularBuffer _encCircularBuffer = new ByteCircularBuffer(TCPHandler.BufferSize * 2);
private ByteCircularBuffer _decCircularBuffer = new ByteCircularBuffer(TCPHandler.BufferSize * 2);
private ByteCircularBuffer buffer = new ByteCircularBuffer(TCPHandler.BufferSize * 2);
protected Dictionary<string, CipherInfo> ciphers;
protected byte[] _encryptIV;
protected byte[] _decryptIV;
// Is first packet
protected bool _decryptIVReceived;
protected bool _encryptIVSent;
protected bool ivReady;
protected string _method;
protected CipherFamily _cipher;
// internal name in the crypto library
protected string _innerLibName;
protected CipherInfo CipherInfo;
// long-time master key
protected static byte[] _key = null;
protected static byte[] key = null;
protected byte[] iv;
protected int keyLen;
protected int ivLen;
@@ -59,9 +54,9 @@ namespace Shadowsocks.Encryption.Stream
private void InitKey(string password)
{
byte[] passbuf = Encoding.UTF8.GetBytes(password);
if (_key == null) _key = new byte[keyLen];
if (_key.Length != keyLen) Array.Resize(ref _key, keyLen);
LegacyDeriveKey(passbuf, _key, keyLen);
key ??= new byte[keyLen];
if (key.Length != keyLen) Array.Resize(ref key, keyLen);
LegacyDeriveKey(passbuf, key, keyLen);
}
public static void LegacyDeriveKey(byte[] password, byte[] key, int keylen)
@@ -88,42 +83,36 @@ namespace Shadowsocks.Encryption.Stream
protected virtual void initCipher(byte[] iv, bool isEncrypt)
{
if (isEncrypt)
{
_encryptIV = new byte[ivLen];
Array.Copy(iv, _encryptIV, ivLen);
}
else
{
_decryptIV = new byte[ivLen];
Array.Copy(iv, _decryptIV, ivLen);
}
this.iv = new byte[ivLen];
Array.Copy(iv, this.iv, ivLen);
}
protected abstract void cipherUpdate(bool isEncrypt, int length, byte[] buf, byte[] outbuf);
protected static void randBytes(byte[] buf, int length) { RNG.GetBytes(buf, length); }
protected abstract int CipherEncrypt(Span<byte> plain, Span<byte> cipher);
protected abstract int CipherDecrypt(Span<byte> plain, Span<byte> cipher);
//protected static void randBytes(byte[] buf, int length) { RNG.GetBytes(buf, length); }
#region TCP
public override void Encrypt(byte[] buf, int length, byte[] outbuf, out int outlength)
{
int cipherOffset = 0;
Debug.Assert(_encCircularBuffer != null, "_encCircularBuffer != null");
_encCircularBuffer.Put(buf, 0, length);
if (!_encryptIVSent)
Debug.Assert(buffer != null, "_encCircularBuffer != null");
buffer.Put(buf, 0, length);
if (!ivReady)
{
// Generate IV
byte[] ivBytes = new byte[ivLen];
randBytes(ivBytes, ivLen);
byte[] ivBytes = RNG.GetBytes(ivLen);
initCipher(ivBytes, true);
Array.Copy(ivBytes, 0, outbuf, 0, ivLen);
cipherOffset = ivLen;
_encryptIVSent = true;
ivReady = true;
}
int size = _encCircularBuffer.Size;
byte[] plain = _encCircularBuffer.Get(size);
int size = buffer.Size;
byte[] plain = buffer.Get(size);
byte[] cipher = new byte[size];
cipherUpdate(true, size, plain, cipher);
Buffer.BlockCopy(cipher, 0, outbuf, cipherOffset, size);
@@ -132,29 +121,29 @@ namespace Shadowsocks.Encryption.Stream
public override void Decrypt(byte[] buf, int length, byte[] outbuf, out int outlength)
{
Debug.Assert(_decCircularBuffer != null, "_circularBuffer != null");
_decCircularBuffer.Put(buf, 0, length);
if (!_decryptIVReceived)
Debug.Assert(buffer != null, "_circularBuffer != null");
buffer.Put(buf, 0, length);
if (!ivReady)
{
if (_decCircularBuffer.Size <= ivLen)
if (buffer.Size <= ivLen)
{
// we need more data
outlength = 0;
return;
}
// start decryption
_decryptIVReceived = true;
ivReady = true;
if (ivLen > 0)
{
byte[] iv = _decCircularBuffer.Get(ivLen);
byte[] iv = buffer.Get(ivLen);
initCipher(iv, false);
}
else initCipher(Array.Empty<byte>(), false);
}
byte[] cipher = _decCircularBuffer.ToArray();
byte[] cipher = buffer.ToArray();
cipherUpdate(false, cipher.Length, cipher, outbuf);
// move pointer only
_decCircularBuffer.Skip(_decCircularBuffer.Size);
buffer.Skip(buffer.Size);
outlength = cipher.Length;
// done the decryption
}
@@ -166,7 +155,7 @@ namespace Shadowsocks.Encryption.Stream
public override void EncryptUDP(byte[] buf, int length, byte[] outbuf, out int outlength)
{
// Generate IV
randBytes(outbuf, ivLen);
RNG.GetBytes(outbuf, ivLen);
initCipher(outbuf, true);
lock (_udpTmpBuf)
{


+ 24
- 13
shadowsocks-csharp/Encryption/Stream/StreamRc4NativeEncryptor.cs View File

@@ -1,8 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Shadowsocks.Encryption.Stream
{
@@ -20,22 +17,19 @@ namespace Shadowsocks.Encryption.Stream
if (_cipher == CipherFamily.Rc4Md5)
{
byte[] temp = new byte[keyLen + ivLen];
Array.Copy(_key, 0, temp, 0, keyLen);
Array.Copy(key, 0, temp, 0, keyLen);
Array.Copy(iv, 0, temp, keyLen, ivLen);
realkey = CryptoUtils.MD5(temp);
}
else
{
realkey = _key;
realkey = key;
}
sbox = SBox(realkey);

}

protected override void cipherUpdate(bool isEncrypt, int length, byte[] buf, byte[] outbuf)
{
var ctx = isEncrypt ? enc_ctx : dec_ctx;

byte[] t = new byte[length];
Array.Copy(buf, t, length);

@@ -43,6 +37,24 @@ namespace Shadowsocks.Encryption.Stream
Array.Copy(t, outbuf, length);
}

protected override int CipherEncrypt(Span<byte> plain, Span<byte> cipher)
{
return DoRC4(plain, cipher);
}

protected override int CipherDecrypt(Span<byte> plain, Span<byte> cipher)
{
return DoRC4(cipher, plain);
}

private int DoRC4(Span<byte> i, Span<byte> o)
{
i.CopyTo(o);
RC4(ctx, sbox, o, o.Length);
return o.Length;
}

#region Ciphers
private static readonly Dictionary<string, CipherInfo> _ciphers = new Dictionary<string, CipherInfo>
{
// original RC4 doesn't use IV
@@ -59,6 +71,7 @@ namespace Shadowsocks.Encryption.Stream
{
return _ciphers;
}
#endregion

#region RC4
class Context
@@ -67,8 +80,7 @@ namespace Shadowsocks.Encryption.Stream
public int index2 = 0;
}

private Context enc_ctx = new Context();
private Context dec_ctx = new Context();
private Context ctx = new Context();

private byte[] SBox(byte[] key)
{
@@ -89,7 +101,7 @@ namespace Shadowsocks.Encryption.Stream
return s;
}

private void RC4(Context ctx, byte[] s, byte[] data, int length)
private void RC4(Context ctx, Span<byte> s, Span<byte> data, int length)
{
for (int n = 0; n < length; n++)
{
@@ -99,12 +111,11 @@ namespace Shadowsocks.Encryption.Stream
ctx.index2 = (ctx.index2 + s[ctx.index1]) & 255;

Swap(s, ctx.index1, ctx.index2);

data[n] = (byte)(b ^ s[(s[ctx.index1] + s[ctx.index2]) & 255]);
}
}

private static void Swap(byte[] s, int i, int j)
private static void Swap(Span<byte> s, int i, int j)
{
byte c = s[i];



+ 32
- 0
shadowsocks-csharp/Encryption/Stream/StreamTableNativeEncryptor.cs View File

@@ -52,6 +52,37 @@ namespace Shadowsocks.Encryption.Stream
}
}

protected override int CipherDecrypt(Span<byte> plain, Span<byte> cipher)
{
if (_cipher == CipherFamily.Plain)
{
cipher.CopyTo(plain);
return cipher.Length;
}

for (int i = 0; i < cipher.Length; i++)
{
plain[i] = _decryptTable[cipher[i]];
}
return cipher.Length;
}

protected override int CipherEncrypt(Span<byte> plain, Span<byte> cipher)
{
if (_cipher == CipherFamily.Plain)
{
plain.CopyTo(cipher);
return plain.Length;
}

for (int i = 0; i < plain.Length; i++)
{
cipher[i] = _decryptTable[plain[i]];
}
return plain.Length;
}

#region Cipher Info
private static readonly Dictionary<string, CipherInfo> _ciphers = new Dictionary<string, CipherInfo>
{
{"plain", new CipherInfo("plain", 0, 0, CipherFamily.Plain) },
@@ -67,6 +98,7 @@ namespace Shadowsocks.Encryption.Stream
{
return _ciphers;
}
#endregion

#region Table
private byte[] _encryptTable = new byte[256];


Loading…
Cancel
Save