Browse Source

make compiler happy in encryption

pull/2865/head
Student Main 5 years ago
parent
commit
92137d28aa
12 changed files with 96 additions and 95 deletions
  1. +3
    -3
      shadowsocks-csharp/Encryption/AEAD/AEADAesGcmNativeEncryptor.cs
  2. +32
    -39
      shadowsocks-csharp/Encryption/AEAD/AEADEncryptor.cs
  3. +10
    -15
      shadowsocks-csharp/Encryption/AEAD/AEADNaClEncryptor.cs
  4. +1
    -0
      shadowsocks-csharp/Encryption/EncryptorBase.cs
  5. +5
    -5
      shadowsocks-csharp/Encryption/EncryptorFactory.cs
  6. +4
    -5
      shadowsocks-csharp/Encryption/Stream/ExtendedCfbBlockCipher.cs
  7. +8
    -6
      shadowsocks-csharp/Encryption/Stream/StreamAesBouncyCastleEncryptor.cs
  8. +6
    -3
      shadowsocks-csharp/Encryption/Stream/StreamChachaNaClEncryptor.cs
  9. +14
    -10
      shadowsocks-csharp/Encryption/Stream/StreamEncryptor.cs
  10. +1
    -1
      shadowsocks-csharp/Encryption/Stream/StreamPlainNativeEncryptor.cs
  11. +8
    -4
      shadowsocks-csharp/Encryption/Stream/StreamRc4NativeEncryptor.cs
  12. +4
    -4
      test/CryptographyTest.cs

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

@@ -18,7 +18,7 @@ namespace Shadowsocks.Encryption.AEAD
{"aes-256-gcm", new CipherInfo("aes-256-gcm", 32, 32, 12, 16, CipherFamily.AesGcm)}, {"aes-256-gcm", new CipherInfo("aes-256-gcm", 32, 32, 12, 16, CipherFamily.AesGcm)},
}; };


protected override Dictionary<string, CipherInfo> getCiphers()
protected override Dictionary<string, CipherInfo> GetCiphers()
{ {
return _ciphers; return _ciphers;
} }
@@ -32,7 +32,7 @@ namespace Shadowsocks.Encryption.AEAD
public override int CipherEncrypt(ReadOnlySpan<byte> plain, Span<byte> cipher) public override int CipherEncrypt(ReadOnlySpan<byte> plain, Span<byte> cipher)
{ {
using AesGcm aes = new AesGcm(sessionKey); using AesGcm aes = new AesGcm(sessionKey);
aes.Encrypt(nonce.AsSpan(), plain, cipher.Slice(0, plain.Length), cipher.Slice(plain.Length, tagLen));
aes.Encrypt(nonce, plain, cipher.Slice(0, plain.Length), cipher.Slice(plain.Length, tagLen));
return plain.Length + tagLen; return plain.Length + tagLen;
} }


@@ -42,7 +42,7 @@ namespace Shadowsocks.Encryption.AEAD
using AesGcm aes = new AesGcm(sessionKey); using AesGcm aes = new AesGcm(sessionKey);
ReadOnlySpan<byte> ciphertxt = cipher.Slice(0, clen); ReadOnlySpan<byte> ciphertxt = cipher.Slice(0, clen);
ReadOnlySpan<byte> tag = cipher.Slice(clen); ReadOnlySpan<byte> tag = cipher.Slice(clen);
aes.Decrypt(nonce.AsSpan(), ciphertxt, tag, plain.Slice(0, clen));
aes.Decrypt(nonce, ciphertxt, tag, plain.Slice(0, clen));
return clen; return clen;
} }
} }

+ 32
- 39
shadowsocks-csharp/Encryption/AEAD/AEADEncryptor.cs View File

@@ -5,26 +5,25 @@ using Shadowsocks.Encryption.Stream;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net; using System.Net;
using System.Runtime.CompilerServices;
using System.Text; using System.Text;
namespace Shadowsocks.Encryption.AEAD namespace Shadowsocks.Encryption.AEAD
{ {
public abstract class AEADEncryptor : EncryptorBase public abstract class AEADEncryptor : EncryptorBase
{ {
private static Logger logger = LogManager.GetCurrentClassLogger();
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
// We are using the same saltLen and keyLen // We are using the same saltLen and keyLen
private const string Info = "ss-subkey"; private const string Info = "ss-subkey";
private static readonly byte[] InfoBytes = Encoding.ASCII.GetBytes(Info); private static readonly byte[] InfoBytes = Encoding.ASCII.GetBytes(Info);
// every connection should create its own buffer // every connection should create its own buffer
private byte[] sharedBuffer = new byte[65536];
private readonly byte[] buffer = new byte[65536];
private int bufPtr = 0; private int bufPtr = 0;
public const int ChunkLengthBytes = 2; public const int ChunkLengthBytes = 2;
public const uint ChunkLengthMask = 0x3FFFu; public const uint ChunkLengthMask = 0x3FFFu;
protected Dictionary<string, CipherInfo> ciphers;
protected CipherFamily cipherFamily; protected CipherFamily cipherFamily;
protected CipherInfo CipherInfo; protected CipherInfo CipherInfo;
protected static byte[] masterKey = Array.Empty<byte>(); protected static byte[] masterKey = Array.Empty<byte>();
@@ -46,7 +45,7 @@ namespace Shadowsocks.Encryption.AEAD
public AEADEncryptor(string method, string password) public AEADEncryptor(string method, string password)
: base(method, password) : base(method, password)
{ {
CipherInfo = getCiphers()[method.ToLower()];
CipherInfo = GetCiphers()[method.ToLower()];
cipherFamily = CipherInfo.Type; cipherFamily = CipherInfo.Type;
AEADCipherParameter parameter = (AEADCipherParameter)CipherInfo.CipherParameter; AEADCipherParameter parameter = (AEADCipherParameter)CipherInfo.CipherParameter;
keyLen = parameter.KeySize; keyLen = parameter.KeySize;
@@ -55,13 +54,15 @@ namespace Shadowsocks.Encryption.AEAD
nonceLen = parameter.NonceSize; nonceLen = parameter.NonceSize;
InitKey(password); InitKey(password);
salt = new byte[saltLen];
// Initialize all-zero nonce for each connection // Initialize all-zero nonce for each connection
nonce = new byte[nonceLen]; nonce = new byte[nonceLen];
logger.Dump($"masterkey {instanceId}", masterKey, keyLen); logger.Dump($"masterkey {instanceId}", masterKey, keyLen);
logger.Dump($"nonce {instanceId}", nonce, keyLen); logger.Dump($"nonce {instanceId}", nonce, keyLen);
} }
protected abstract Dictionary<string, CipherInfo> getCiphers();
protected abstract Dictionary<string, CipherInfo> GetCiphers();
protected void InitKey(string password) protected void InitKey(string password)
{ {
@@ -77,32 +78,18 @@ namespace Shadowsocks.Encryption.AEAD
Array.Resize(ref masterKey, keyLen); Array.Resize(ref masterKey, keyLen);
} }
DeriveKey(passbuf, masterKey, keyLen);
StreamEncryptor.LegacyDeriveKey(passbuf, masterKey, keyLen);
// init session key // init session key
sessionKey = new byte[keyLen]; sessionKey = new byte[keyLen];
} }
public void DeriveKey(byte[] password, byte[] key, int keylen)
{
StreamEncryptor.LegacyDeriveKey(password, key, keylen);
}
public void DeriveSessionKey(byte[] salt, byte[] masterKey, byte[] sessionKey)
{
CryptoUtils.HKDF(keyLen, masterKey, salt, InfoBytes).CopyTo(sessionKey, 0);
}
protected void IncrementNonce()
{
CryptoUtils.SodiumIncrement(nonce);
}
public virtual void InitCipher(byte[] salt, bool isEncrypt, bool isUdp)
public virtual void InitCipher(byte[] salt, bool isEncrypt)
{ {
this.salt = new byte[saltLen]; this.salt = new byte[saltLen];
Array.Copy(salt, this.salt, saltLen); Array.Copy(salt, this.salt, saltLen);
DeriveSessionKey(salt, masterKey, sessionKey);
CryptoUtils.HKDF(keyLen, masterKey, salt, InfoBytes).CopyTo(sessionKey, 0);
logger.Dump($"salt {instanceId}", salt, saltLen); logger.Dump($"salt {instanceId}", salt, saltLen);
logger.Dump($"sessionkey {instanceId}", sessionKey, keyLen); logger.Dump($"sessionkey {instanceId}", sessionKey, keyLen);
} }
@@ -112,10 +99,11 @@ namespace Shadowsocks.Encryption.AEAD
#region TCP #region TCP
[MethodImpl(MethodImplOptions.Synchronized | MethodImplOptions.AggressiveOptimization)]
public override int Encrypt(ReadOnlySpan<byte> plain, Span<byte> cipher) public override int Encrypt(ReadOnlySpan<byte> plain, Span<byte> cipher)
{ {
// push data // push data
Span<byte> tmp = sharedBuffer.AsSpan(0, plain.Length + bufPtr);
Span<byte> tmp = buffer.AsSpan(0, plain.Length + bufPtr);
plain.CopyTo(tmp.Slice(bufPtr)); plain.CopyTo(tmp.Slice(bufPtr));
int outlength = 0; int outlength = 0;
@@ -124,7 +112,7 @@ namespace Shadowsocks.Encryption.AEAD
saltReady = true; saltReady = true;
// Generate salt // Generate salt
byte[] saltBytes = RNG.GetBytes(saltLen); byte[] saltBytes = RNG.GetBytes(saltLen);
InitCipher(saltBytes, true, false);
InitCipher(saltBytes, true);
saltBytes.CopyTo(cipher); saltBytes.CopyTo(cipher);
outlength = saltLen; outlength = saltLen;
} }
@@ -162,7 +150,7 @@ namespace Shadowsocks.Encryption.AEAD
logger.Debug("enc outbuf almost full, giving up"); logger.Debug("enc outbuf almost full, giving up");
// write rest data to head of shared buffer // write rest data to head of shared buffer
tmp.CopyTo(sharedBuffer);
tmp.CopyTo(buffer);
bufPtr = tmp.Length; bufPtr = tmp.Length;
return outlength; return outlength;
@@ -177,11 +165,12 @@ namespace Shadowsocks.Encryption.AEAD
} }
} }
[MethodImpl(MethodImplOptions.Synchronized | MethodImplOptions.AggressiveOptimization)]
public override int Decrypt(Span<byte> plain, ReadOnlySpan<byte> cipher) public override int Decrypt(Span<byte> plain, ReadOnlySpan<byte> cipher)
{ {
int outlength = 0; int outlength = 0;
// drop all into buffer // drop all into buffer
Span<byte> tmp = sharedBuffer.AsSpan(0, cipher.Length + bufPtr);
Span<byte> tmp = buffer.AsSpan(0, cipher.Length + bufPtr);
cipher.CopyTo(tmp.Slice(bufPtr)); cipher.CopyTo(tmp.Slice(bufPtr));
int bufSize = tmp.Length; int bufSize = tmp.Length;
@@ -192,7 +181,7 @@ namespace Shadowsocks.Encryption.AEAD
if (bufSize <= saltLen) if (bufSize <= saltLen)
{ {
// need more, write back cache // need more, write back cache
tmp.CopyTo(sharedBuffer);
tmp.CopyTo(buffer);
bufPtr = tmp.Length; bufPtr = tmp.Length;
return outlength; return outlength;
} }
@@ -202,7 +191,7 @@ namespace Shadowsocks.Encryption.AEAD
byte[] salt = tmp.Slice(0, saltLen).ToArray(); byte[] salt = tmp.Slice(0, saltLen).ToArray();
tmp = tmp.Slice(saltLen); tmp = tmp.Slice(saltLen);
InitCipher(salt, false, false);
InitCipher(salt, false);
logger.Debug("get salt len " + saltLen); logger.Debug("get salt len " + saltLen);
} }
@@ -222,7 +211,7 @@ namespace Shadowsocks.Encryption.AEAD
{ {
// so we only have chunk length and its tag? // so we only have chunk length and its tag?
// wait more // wait more
tmp.CopyTo(sharedBuffer);
tmp.CopyTo(buffer);
bufPtr = tmp.Length; bufPtr = tmp.Length;
return outlength; return outlength;
} }
@@ -231,7 +220,7 @@ namespace Shadowsocks.Encryption.AEAD
if (len <= 0) if (len <= 0)
{ {
// no chunk decrypted // no chunk decrypted
tmp.CopyTo(sharedBuffer);
tmp.CopyTo(buffer);
bufPtr = tmp.Length; bufPtr = tmp.Length;
return outlength; return outlength;
} }
@@ -243,7 +232,7 @@ namespace Shadowsocks.Encryption.AEAD
if (outlength + 100 > TCPHandler.BufferSize) if (outlength + 100 > TCPHandler.BufferSize)
{ {
logger.Debug("dec outbuf almost full, giving up"); logger.Debug("dec outbuf almost full, giving up");
tmp.CopyTo(sharedBuffer);
tmp.CopyTo(buffer);
bufPtr = tmp.Length; bufPtr = tmp.Length;
return outlength; return outlength;
} }
@@ -260,21 +249,24 @@ namespace Shadowsocks.Encryption.AEAD
#endregion #endregion
#region UDP #region UDP
[MethodImpl(MethodImplOptions.Synchronized | MethodImplOptions.AggressiveOptimization)]
public override int EncryptUDP(ReadOnlySpan<byte> plain, Span<byte> cipher) public override int EncryptUDP(ReadOnlySpan<byte> plain, Span<byte> cipher)
{ {
RNG.GetSpan(cipher.Slice(0, saltLen)); RNG.GetSpan(cipher.Slice(0, saltLen));
InitCipher(cipher.Slice(0, saltLen).ToArray(), true, true);
InitCipher(cipher.Slice(0, saltLen).ToArray(), true);
return saltLen + CipherEncrypt(plain, cipher.Slice(saltLen)); return saltLen + CipherEncrypt(plain, cipher.Slice(saltLen));
} }
[MethodImpl(MethodImplOptions.Synchronized | MethodImplOptions.AggressiveOptimization)]
public override int DecryptUDP(Span<byte> plain, ReadOnlySpan<byte> cipher) public override int DecryptUDP(Span<byte> plain, ReadOnlySpan<byte> cipher)
{ {
InitCipher(cipher.Slice(0, saltLen).ToArray(), false, true);
InitCipher(cipher.Slice(0, saltLen).ToArray(), false);
return CipherDecrypt(plain, cipher.Slice(saltLen)); return CipherDecrypt(plain, cipher.Slice(saltLen));
} }
#endregion #endregion
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private int ChunkEncrypt(ReadOnlySpan<byte> plain, Span<byte> cipher) private int ChunkEncrypt(ReadOnlySpan<byte> plain, Span<byte> cipher)
{ {
if (plain.Length > ChunkLengthMask) if (plain.Length > ChunkLengthMask)
@@ -285,13 +277,14 @@ namespace Shadowsocks.Encryption.AEAD
byte[] lenbuf = BitConverter.GetBytes((ushort)IPAddress.HostToNetworkOrder((short)plain.Length)); byte[] lenbuf = BitConverter.GetBytes((ushort)IPAddress.HostToNetworkOrder((short)plain.Length));
int cipherLenSize = CipherEncrypt(lenbuf, cipher); int cipherLenSize = CipherEncrypt(lenbuf, cipher);
IncrementNonce();
CryptoUtils.SodiumIncrement(nonce);
int cipherDataSize = CipherEncrypt(plain, cipher.Slice(cipherLenSize)); int cipherDataSize = CipherEncrypt(plain, cipher.Slice(cipherLenSize));
IncrementNonce();
CryptoUtils.SodiumIncrement(nonce);
return cipherLenSize + cipherDataSize; return cipherLenSize + cipherDataSize;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private int ChunkDecrypt(Span<byte> plain, ReadOnlySpan<byte> cipher) private int ChunkDecrypt(Span<byte> plain, ReadOnlySpan<byte> cipher)
{ {
// try to dec chunk len // try to dec chunk len
@@ -311,11 +304,11 @@ namespace Shadowsocks.Encryption.AEAD
logger.Debug("No data to decrypt one chunk"); logger.Debug("No data to decrypt one chunk");
return 0; return 0;
} }
IncrementNonce();
CryptoUtils.SodiumIncrement(nonce);
// we have enough data to decrypt one chunk // we have enough data to decrypt one chunk
// drop chunk len and its tag from buffer // drop chunk len and its tag from buffer
int len = CipherDecrypt(plain, cipher.Slice(ChunkLengthBytes + tagLen, chunkLength + tagLen)); int len = CipherDecrypt(plain, cipher.Slice(ChunkLengthBytes + tagLen, chunkLength + tagLen));
IncrementNonce();
CryptoUtils.SodiumIncrement(nonce);
return len; return len;
} }
} }

+ 10
- 15
shadowsocks-csharp/Encryption/AEAD/AEADNaClEncryptor.cs View File

@@ -8,7 +8,7 @@ namespace Shadowsocks.Encryption.AEAD
public class AEADNaClEncryptor : AEADEncryptor public class AEADNaClEncryptor : AEADEncryptor
{ {


SnufflePoly1305 enc;
SnufflePoly1305? enc;
public AEADNaClEncryptor(string method, string password) : base(method, password) public AEADNaClEncryptor(string method, string password) : base(method, password)
{ {
} }
@@ -20,7 +20,7 @@ namespace Shadowsocks.Encryption.AEAD
{"xchacha20-ietf-poly1305", new CipherInfo("xchacha20-ietf-poly1305",32, 32, 24, 16, CipherFamily.XChacha20Poly1305)}, {"xchacha20-ietf-poly1305", new CipherInfo("xchacha20-ietf-poly1305",32, 32, 24, 16, CipherFamily.XChacha20Poly1305)},
}; };


protected override Dictionary<string, CipherInfo> getCiphers()
protected override Dictionary<string, CipherInfo> GetCiphers()
{ {
return _ciphers; return _ciphers;
} }
@@ -31,31 +31,26 @@ namespace Shadowsocks.Encryption.AEAD
} }
#endregion #endregion


public override void InitCipher(byte[] salt, bool isEncrypt, bool isUdp)
public override void InitCipher(byte[] salt, bool isEncrypt)
{ {
base.InitCipher(salt, isEncrypt, isUdp);
switch (cipherFamily)
base.InitCipher(salt, isEncrypt);
enc = cipherFamily switch
{ {
default:
case CipherFamily.Chacha20Poly1305:
enc = new ChaCha20Poly1305(sessionKey);
break;
case CipherFamily.XChacha20Poly1305:
enc = new XChaCha20Poly1305(sessionKey);
break;
}
CipherFamily.XChacha20Poly1305 => new XChaCha20Poly1305(sessionKey),
_ => new ChaCha20Poly1305(sessionKey),
};
} }


public override int CipherEncrypt(ReadOnlySpan<byte> plain, Span<byte> cipher) public override int CipherEncrypt(ReadOnlySpan<byte> plain, Span<byte> cipher)
{ {
byte[] ct = enc.Encrypt(plain, null, nonce);
byte[] ct = enc!.Encrypt(plain, null, nonce);
ct.CopyTo(cipher); ct.CopyTo(cipher);
return ct.Length; return ct.Length;
} }


public override int CipherDecrypt(Span<byte> plain, ReadOnlySpan<byte> cipher) public override int CipherDecrypt(Span<byte> plain, ReadOnlySpan<byte> cipher)
{ {
byte[] pt = enc.Decrypt(cipher, null, nonce);
byte[] pt = enc!.Decrypt(cipher, null, nonce);
pt.CopyTo(plain); pt.CopyTo(plain);
return pt.Length; return pt.Length;
} }


+ 1
- 0
shadowsocks-csharp/Encryption/EncryptorBase.cs View File

@@ -1,4 +1,5 @@
using System; using System;
using System.Runtime.CompilerServices;
namespace Shadowsocks.Encryption namespace Shadowsocks.Encryption
{ {


+ 5
- 5
shadowsocks-csharp/Encryption/EncryptorFactory.cs View File

@@ -11,8 +11,8 @@ namespace Shadowsocks.Encryption
{ {
public static string DefaultCipher = "chacha20-ietf-poly1305"; public static string DefaultCipher = "chacha20-ietf-poly1305";
private static Dictionary<string, Type> _registeredEncryptors = new Dictionary<string, Type>();
private static Dictionary<string, CipherInfo> ciphers = new Dictionary<string, CipherInfo>();
private static readonly Dictionary<string, Type> _registeredEncryptors = new Dictionary<string, Type>();
private static readonly Dictionary<string, CipherInfo> ciphers = new Dictionary<string, CipherInfo>();
private static readonly Type[] ConstructorTypes = { typeof(string), typeof(string) }; private static readonly Type[] ConstructorTypes = { typeof(string), typeof(string) };
static EncryptorFactory() static EncryptorFactory()
@@ -33,12 +33,12 @@ namespace Shadowsocks.Encryption
_registeredEncryptors.Add(method.Key, typeof(StreamRc4NativeEncryptor)); _registeredEncryptors.Add(method.Key, typeof(StreamRc4NativeEncryptor));
} }
} }
foreach (var method in StreamAesBouncyCastleEncryptor.SupportedCiphers())
foreach (var method in StreamAesCfbBouncyCastleEncryptor.SupportedCiphers())
{ {
if (!_registeredEncryptors.ContainsKey(method.Key)) if (!_registeredEncryptors.ContainsKey(method.Key))
{ {
ciphers.Add(method.Key, method.Value); ciphers.Add(method.Key, method.Value);
_registeredEncryptors.Add(method.Key, typeof(StreamAesBouncyCastleEncryptor));
_registeredEncryptors.Add(method.Key, typeof(StreamAesCfbBouncyCastleEncryptor));
} }
} }
foreach (var method in StreamChachaNaClEncryptor.SupportedCiphers()) foreach (var method in StreamChachaNaClEncryptor.SupportedCiphers())
@@ -77,7 +77,7 @@ namespace Shadowsocks.Encryption
} }
method = method.ToLowerInvariant(); method = method.ToLowerInvariant();
bool ok = _registeredEncryptors.TryGetValue(method, out Type t);
bool ok = _registeredEncryptors.TryGetValue(method, out Type? t);
if (!ok) if (!ok)
{ {
t = _registeredEncryptors[DefaultCipher]; t = _registeredEncryptors[DefaultCipher];


+ 4
- 5
shadowsocks-csharp/Encryption/Stream/ExtendedCfbBlockCipher.cs View File

@@ -13,9 +13,9 @@ namespace Org.BouncyCastle.Crypto.Modes
public class ExtendedCfbBlockCipher public class ExtendedCfbBlockCipher
: IBlockCipher : IBlockCipher
{ {
private byte[] IV;
private byte[] cfbV;
private byte[] cfbOutV;
private readonly byte[] IV;
private readonly byte[] cfbV;
private readonly byte[] cfbOutV;
private bool encrypting; private bool encrypting;


private readonly int blockSize; private readonly int blockSize;
@@ -63,9 +63,8 @@ namespace Org.BouncyCastle.Crypto.Modes
ICipherParameters parameters) ICipherParameters parameters)
{ {
encrypting = forEncryption; encrypting = forEncryption;
if (parameters is ParametersWithIV)
if (parameters is ParametersWithIV ivParam)
{ {
ParametersWithIV ivParam = (ParametersWithIV)parameters;
byte[] iv = ivParam.GetIV(); byte[] iv = ivParam.GetIV();
int diff = IV.Length - iv.Length; int diff = IV.Length - iv.Length;
Array.Copy(iv, 0, IV, diff, iv.Length); Array.Copy(iv, 0, IV, diff, iv.Length);


+ 8
- 6
shadowsocks-csharp/Encryption/Stream/StreamAesBouncyCastleEncryptor.cs View File

@@ -3,23 +3,24 @@ using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Crypto.Parameters;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices;


namespace Shadowsocks.Encryption.Stream namespace Shadowsocks.Encryption.Stream
{ {


public class StreamAesBouncyCastleEncryptor : StreamEncryptor
public class StreamAesCfbBouncyCastleEncryptor : StreamEncryptor
{ {
byte[] cfbBuf = new byte[MaxInputSize + 128];
readonly byte[] cfbBuf = new byte[MaxInputSize + 128];
int ptr = 0; int ptr = 0;
readonly ExtendedCfbBlockCipher b; readonly ExtendedCfbBlockCipher b;
public StreamAesBouncyCastleEncryptor(string method, string password) : base(method, password)
public StreamAesCfbBouncyCastleEncryptor(string method, string password) : base(method, password)
{ {
b = new ExtendedCfbBlockCipher(new AesEngine(), 128); b = new ExtendedCfbBlockCipher(new AesEngine(), 128);
} }


protected override void initCipher(byte[] iv, bool isEncrypt)
protected override void InitCipher(byte[] iv, bool isEncrypt)
{ {
base.initCipher(iv, isEncrypt);
base.InitCipher(iv, isEncrypt);
b.Init(isEncrypt, new ParametersWithIV(new KeyParameter(key), iv)); b.Init(isEncrypt, new ParametersWithIV(new KeyParameter(key), iv));
} }


@@ -35,6 +36,7 @@ namespace Shadowsocks.Encryption.Stream
return cipher.Length; return cipher.Length;
} }


[MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)]
private void CipherUpdate(ReadOnlySpan<byte> i, Span<byte> o) private void CipherUpdate(ReadOnlySpan<byte> i, Span<byte> o)
{ {
Span<byte> ob = new byte[o.Length + 128]; Span<byte> ob = new byte[o.Length + 128];
@@ -82,7 +84,7 @@ namespace Shadowsocks.Encryption.Stream
return _ciphers; return _ciphers;
} }


protected override Dictionary<string, CipherInfo> getCiphers()
protected override Dictionary<string, CipherInfo> GetCiphers()
{ {
return _ciphers; return _ciphers;
} }


+ 6
- 3
shadowsocks-csharp/Encryption/Stream/StreamChachaNaClEncryptor.cs View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices;
using NaCl.Core; using NaCl.Core;


namespace Shadowsocks.Encryption.Stream namespace Shadowsocks.Encryption.Stream
@@ -7,15 +8,16 @@ namespace Shadowsocks.Encryption.Stream
public class StreamChachaNaClEncryptor : StreamEncryptor public class StreamChachaNaClEncryptor : StreamEncryptor
{ {
const int BlockSize = 64; const int BlockSize = 64;

// tcp is stream, which can split into chunks at unexpected position... // tcp is stream, which can split into chunks at unexpected position...
// so we need some special handling, as we can't read all data before encrypt // so we need some special handling, as we can't read all data before encrypt
// we did it in AEADEncryptor.cs for AEAD, it can operate at block level // we did it in AEADEncryptor.cs for AEAD, it can operate at block level
// but we need do it ourselves in stream cipher. // but we need do it ourselves in stream cipher.


// when new data arrive, put it on correct offset // when new data arrive, put it on correct offset
// and update it, ignore other data, get it in correct offset... // and update it, ignore other data, get it in correct offset...
byte[] chachaBuf = new byte[MaxInputSize + BlockSize];
readonly byte[] chachaBuf = new byte[MaxInputSize + BlockSize];
// the 'correct offset', always in 0~BlockSize range, so input data always fit into buffer // the 'correct offset', always in 0~BlockSize range, so input data always fit into buffer
int remain = 0; int remain = 0;
// increase counter manually... // increase counter manually...
@@ -34,6 +36,7 @@ namespace Shadowsocks.Encryption.Stream
return CipherUpdate(plain, cipher, true); return CipherUpdate(plain, cipher, true);
} }


[MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)]
private int CipherUpdate(ReadOnlySpan<byte> i, Span<byte> o, bool enc) private int CipherUpdate(ReadOnlySpan<byte> i, Span<byte> o, bool enc)
{ {
int len = i.Length; int len = i.Length;
@@ -58,7 +61,7 @@ namespace Shadowsocks.Encryption.Stream
return _ciphers; return _ciphers;
} }


protected override Dictionary<string, CipherInfo> getCiphers()
protected override Dictionary<string, CipherInfo> GetCiphers()
{ {
return _ciphers; return _ciphers;
} }


+ 14
- 10
shadowsocks-csharp/Encryption/Stream/StreamEncryptor.cs View File

@@ -1,6 +1,7 @@
using NLog; using NLog;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Text; using System.Text;
namespace Shadowsocks.Encryption.Stream namespace Shadowsocks.Encryption.Stream
@@ -26,7 +27,7 @@ namespace Shadowsocks.Encryption.Stream
public StreamEncryptor(string method, string password) public StreamEncryptor(string method, string password)
: base(method, password) : base(method, password)
{ {
CipherInfo = getCiphers()[method.ToLower()];
CipherInfo = GetCiphers()[method.ToLower()];
cipherFamily = CipherInfo.Type; cipherFamily = CipherInfo.Type;
StreamCipherParameter parameter = (StreamCipherParameter)CipherInfo.CipherParameter; StreamCipherParameter parameter = (StreamCipherParameter)CipherInfo.CipherParameter;
keyLen = parameter.KeySize; keyLen = parameter.KeySize;
@@ -37,7 +38,7 @@ namespace Shadowsocks.Encryption.Stream
logger.Dump($"key {instanceId}", key, keyLen); logger.Dump($"key {instanceId}", key, keyLen);
} }
protected abstract Dictionary<string, CipherInfo> getCiphers();
protected abstract Dictionary<string, CipherInfo> GetCiphers();
private void InitKey(string password) private void InitKey(string password)
{ {
@@ -51,6 +52,7 @@ namespace Shadowsocks.Encryption.Stream
LegacyDeriveKey(passbuf, key, keyLen); LegacyDeriveKey(passbuf, key, keyLen);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void LegacyDeriveKey(byte[] password, byte[] key, int keylen) public static void LegacyDeriveKey(byte[] password, byte[] key, int keylen)
{ {
byte[] result = new byte[password.Length + MD5Length]; byte[] result = new byte[password.Length + MD5Length];
@@ -73,7 +75,7 @@ namespace Shadowsocks.Encryption.Stream
} }
} }
protected virtual void initCipher(byte[] iv, bool isEncrypt)
protected virtual void InitCipher(byte[] iv, bool isEncrypt)
{ {
if (ivLen == 0) if (ivLen == 0)
{ {
@@ -88,6 +90,7 @@ namespace Shadowsocks.Encryption.Stream
protected abstract int CipherDecrypt(Span<byte> plain, ReadOnlySpan<byte> cipher); protected abstract int CipherDecrypt(Span<byte> plain, ReadOnlySpan<byte> cipher);
#region TCP #region TCP
[MethodImpl(MethodImplOptions.Synchronized | MethodImplOptions.AggressiveOptimization)]
public override int Encrypt(ReadOnlySpan<byte> plain, Span<byte> cipher) public override int Encrypt(ReadOnlySpan<byte> plain, Span<byte> cipher)
{ {
int cipherOffset = 0; int cipherOffset = 0;
@@ -96,7 +99,7 @@ namespace Shadowsocks.Encryption.Stream
{ {
// Generate IV // Generate IV
byte[] ivBytes = RNG.GetBytes(ivLen); byte[] ivBytes = RNG.GetBytes(ivLen);
initCipher(ivBytes, true);
InitCipher(ivBytes, true);
ivBytes.CopyTo(cipher); ivBytes.CopyTo(cipher);
cipherOffset = ivLen; cipherOffset = ivLen;
cipher = cipher.Slice(cipherOffset); cipher = cipher.Slice(cipherOffset);
@@ -111,9 +114,9 @@ namespace Shadowsocks.Encryption.Stream
} }
private int recieveCtr = 0; private int recieveCtr = 0;
[MethodImpl(MethodImplOptions.Synchronized | MethodImplOptions.AggressiveOptimization)]
public override int Decrypt(Span<byte> plain, ReadOnlySpan<byte> cipher) public override int Decrypt(Span<byte> plain, ReadOnlySpan<byte> cipher)
{ {
Span<byte> tmp;// = cipher;
logger.Trace($"{instanceId} decrypt TCP, read iv: {!ivReady}"); logger.Trace($"{instanceId} decrypt TCP, read iv: {!ivReady}");
int cipherOffset = 0; int cipherOffset = 0;
@@ -135,14 +138,13 @@ namespace Shadowsocks.Encryption.Stream
{ {
// read iv // read iv
byte[] iv = sharedBuffer.AsSpan(0, ivLen).ToArray(); byte[] iv = sharedBuffer.AsSpan(0, ivLen).ToArray();
initCipher(iv, false);
InitCipher(iv, false);
} }
else else
{ {
initCipher(Array.Empty<byte>(), false);
InitCipher(Array.Empty<byte>(), false);
} }
cipherOffset += ivLen; cipherOffset += ivLen;
tmp = sharedBuffer.AsSpan(ivLen, recieveCtr - ivLen);
} }
// read all data from buffer // read all data from buffer
@@ -156,17 +158,19 @@ namespace Shadowsocks.Encryption.Stream
#endregion #endregion
#region UDP #region UDP
[MethodImpl(MethodImplOptions.Synchronized | MethodImplOptions.AggressiveOptimization)]
public override int EncryptUDP(ReadOnlySpan<byte> plain, Span<byte> cipher) public override int EncryptUDP(ReadOnlySpan<byte> plain, Span<byte> cipher)
{ {
byte[] iv = RNG.GetBytes(ivLen); byte[] iv = RNG.GetBytes(ivLen);
iv.CopyTo(cipher); iv.CopyTo(cipher);
initCipher(iv, true);
InitCipher(iv, true);
return ivLen + CipherEncrypt(plain, cipher.Slice(ivLen)); return ivLen + CipherEncrypt(plain, cipher.Slice(ivLen));
} }
[MethodImpl(MethodImplOptions.Synchronized | MethodImplOptions.AggressiveOptimization)]
public override int DecryptUDP(Span<byte> plain, ReadOnlySpan<byte> cipher) public override int DecryptUDP(Span<byte> plain, ReadOnlySpan<byte> cipher)
{ {
initCipher(cipher.Slice(0, ivLen).ToArray(), false);
InitCipher(cipher.Slice(0, ivLen).ToArray(), false);
return CipherDecrypt(plain, cipher.Slice(ivLen)); return CipherDecrypt(plain, cipher.Slice(ivLen));
} }


+ 1
- 1
shadowsocks-csharp/Encryption/Stream/StreamPlainNativeEncryptor.cs View File

@@ -33,7 +33,7 @@ namespace Shadowsocks.Encryption.Stream
return _ciphers; return _ciphers;
} }


protected override Dictionary<string, CipherInfo> getCiphers()
protected override Dictionary<string, CipherInfo> GetCiphers()
{ {
return _ciphers; return _ciphers;
} }


+ 8
- 4
shadowsocks-csharp/Encryption/Stream/StreamRc4NativeEncryptor.cs View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices;


namespace Shadowsocks.Encryption.Stream namespace Shadowsocks.Encryption.Stream
{ {
@@ -11,9 +12,9 @@ namespace Shadowsocks.Encryption.Stream
{ {
} }


protected override void initCipher(byte[] iv, bool isEncrypt)
protected override void InitCipher(byte[] iv, bool isEncrypt)
{ {
base.initCipher(iv, isEncrypt);
base.InitCipher(iv, isEncrypt);
// rc4-md5 is rc4 with md5 based session key // rc4-md5 is rc4 with md5 based session key
if (cipherFamily == CipherFamily.Rc4Md5) if (cipherFamily == CipherFamily.Rc4Md5)
{ {
@@ -39,6 +40,7 @@ namespace Shadowsocks.Encryption.Stream
return CipherUpdate(cipher, plain); return CipherUpdate(cipher, plain);
} }


[MethodImpl(MethodImplOptions.AggressiveInlining)]
private int CipherUpdate(ReadOnlySpan<byte> i, Span<byte> o) private int CipherUpdate(ReadOnlySpan<byte> i, Span<byte> o)
{ {
// don't know why we need third array, but it works... // don't know why we need third array, but it works...
@@ -62,7 +64,7 @@ namespace Shadowsocks.Encryption.Stream
return _ciphers; return _ciphers;
} }


protected override Dictionary<string, CipherInfo> getCiphers()
protected override Dictionary<string, CipherInfo> GetCiphers()
{ {
return _ciphers; return _ciphers;
} }
@@ -75,7 +77,7 @@ namespace Shadowsocks.Encryption.Stream
public int index2 = 0; public int index2 = 0;
} }


private Context ctx = new Context();
private readonly Context ctx = new Context();


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


[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private void RC4(Context ctx, Span<byte> s, Span<byte> data, int length) private void RC4(Context ctx, Span<byte> s, Span<byte> data, int length)
{ {
for (int n = 0; n < length; n++) for (int n = 0; n < length; n++)
@@ -110,6 +113,7 @@ namespace Shadowsocks.Encryption.Stream
} }
} }


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


+ 4
- 4
test/CryptographyTest.cs View File

@@ -11,7 +11,7 @@ namespace Shadowsocks.Test
[TestClass] [TestClass]
public class CryptographyTest public class CryptographyTest
{ {
Random random = new Random();
readonly Random random = new Random();
[TestMethod] [TestMethod]
@@ -161,9 +161,9 @@ namespace Shadowsocks.Test
[TestMethod] [TestMethod]
public void TestStreamAesCfbBouncyCastleEncryption() public void TestStreamAesCfbBouncyCastleEncryption()
{ {
TestEncryptionMethod(typeof(StreamAesBouncyCastleEncryptor), "aes-128-cfb");
TestEncryptionMethod(typeof(StreamAesBouncyCastleEncryptor), "aes-192-cfb");
TestEncryptionMethod(typeof(StreamAesBouncyCastleEncryptor), "aes-256-cfb");
TestEncryptionMethod(typeof(StreamAesCfbBouncyCastleEncryptor), "aes-128-cfb");
TestEncryptionMethod(typeof(StreamAesCfbBouncyCastleEncryptor), "aes-192-cfb");
TestEncryptionMethod(typeof(StreamAesCfbBouncyCastleEncryptor), "aes-256-cfb");
} }
[TestMethod] [TestMethod]
public void TestStreamChachaNaClEncryption() public void TestStreamChachaNaClEncryption()


Loading…
Cancel
Save