@@ -125,17 +125,18 @@ especially for feature development. | |||
#### Open Source Components / Libraries | |||
``` | |||
Caseless.Fody (MIT) https://github.com/Fody/Caseless | |||
Costura.Fody (MIT) https://github.com/Fody/Costura | |||
Fody (MIT) https://github.com/Fody/Fody | |||
GlobalHotKey (GPLv3) https://github.com/kirmir/GlobalHotKey | |||
Newtonsoft.Json (MIT) https://www.newtonsoft.com/json | |||
StringEx.CS () https://github.com/LazyMode/StringEx | |||
ZXing.Net (Apache 2.0) https://github.com/micjahn/ZXing.Net | |||
libsscrypto (GPLv2) https://github.com/shadowsocks/libsscrypto | |||
Privoxy (GPLv2) https://www.privoxy.org | |||
Sysproxy () https://github.com/Noisyfox/sysproxy | |||
Caseless.Fody (MIT) https://github.com/Fody/Caseless | |||
Costura.Fody (MIT) https://github.com/Fody/Costura | |||
Fody (MIT) https://github.com/Fody/Fody | |||
GlobalHotKey (GPLv3) https://github.com/kirmir/GlobalHotKey | |||
Newtonsoft.Json (MIT) https://www.newtonsoft.com/json | |||
StringEx.CS () https://github.com/LazyMode/StringEx | |||
ZXing.Net (Apache 2.0) https://github.com/micjahn/ZXing.Net | |||
BouncyCastle.NetCore (MIT) https://github.com/chrishaly/bc-csharp | |||
NaCl.Core (MIT) https://github.com/idaviddesmet/NaCl.Core | |||
Privoxy (GPLv2) https://www.privoxy.org | |||
Sysproxy () https://github.com/Noisyfox/sysproxy | |||
``` | |||
@@ -1,9 +1,6 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Security.Cryptography; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
namespace Shadowsocks.Encryption.AEAD | |||
{ | |||
@@ -34,7 +31,7 @@ namespace Shadowsocks.Encryption.AEAD | |||
public override int CipherEncrypt(Span<byte> plain, Span<byte> cipher) | |||
{ | |||
using var 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)); | |||
return plain.Length + tagLen; | |||
} | |||
@@ -42,9 +39,9 @@ namespace Shadowsocks.Encryption.AEAD | |||
public override int CipherDecrypt(Span<byte> plain, Span<byte> cipher) | |||
{ | |||
int clen = cipher.Length - tagLen; | |||
using var aes = new AesGcm(sessionKey); | |||
var ciphertxt = cipher.Slice(0, clen); | |||
var tag = cipher.Slice(clen); | |||
using AesGcm aes = new AesGcm(sessionKey); | |||
Span<byte> ciphertxt = cipher.Slice(0, clen); | |||
Span<byte> tag = cipher.Slice(clen); | |||
aes.Decrypt(nonce.AsSpan(), ciphertxt, tag, plain.Slice(0, clen)); | |||
return clen; | |||
} | |||
@@ -1,11 +1,11 @@ | |||
using NLog; | |||
using Shadowsocks.Controller; | |||
using Shadowsocks.Encryption.Exception; | |||
using Shadowsocks.Encryption.Stream; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Net; | |||
using System.Text; | |||
using Shadowsocks.Controller; | |||
using Shadowsocks.Encryption.Exception; | |||
using Shadowsocks.Encryption.Stream; | |||
namespace Shadowsocks.Encryption.AEAD | |||
{ | |||
@@ -48,7 +48,7 @@ namespace Shadowsocks.Encryption.AEAD | |||
{ | |||
CipherInfo = getCiphers()[method.ToLower()]; | |||
cipherFamily = CipherInfo.Type; | |||
var parameter = (AEADCipherParameter)CipherInfo.CipherParameter; | |||
AEADCipherParameter parameter = (AEADCipherParameter)CipherInfo.CipherParameter; | |||
keyLen = parameter.KeySize; | |||
saltLen = parameter.SaltSize; | |||
tagLen = parameter.TagSize; | |||
@@ -65,8 +65,16 @@ 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); | |||
if (masterKey == null) | |||
{ | |||
masterKey = new byte[keyLen]; | |||
} | |||
if (masterKey.Length != keyLen) | |||
{ | |||
Array.Resize(ref masterKey, keyLen); | |||
} | |||
DeriveKey(passbuf, masterKey, keyLen); | |||
// init session key | |||
sessionKey = new byte[keyLen]; | |||
@@ -142,8 +150,12 @@ namespace Shadowsocks.Encryption.AEAD | |||
{ | |||
// calculate next chunk size | |||
int bufSize = tmp.Length; | |||
if (bufSize <= 0) return; | |||
var chunklength = (int)Math.Min(bufSize, ChunkLengthMask); | |||
if (bufSize <= 0) | |||
{ | |||
return; | |||
} | |||
int chunklength = (int)Math.Min(bufSize, ChunkLengthMask); | |||
// read next chunk | |||
byte[] chunkBytes = tmp.Slice(0, chunklength).ToArray(); | |||
tmp = tmp.Slice(chunklength); | |||
@@ -1,10 +1,7 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
using NaCl.Core; | |||
using NaCl.Core; | |||
using NaCl.Core.Base; | |||
using System; | |||
using System.Collections.Generic; | |||
namespace Shadowsocks.Encryption.AEAD | |||
{ | |||
@@ -48,17 +45,17 @@ namespace Shadowsocks.Encryption.AEAD | |||
break; | |||
} | |||
} | |||
public override int CipherEncrypt(Span<byte> plain, Span<byte> cipher) | |||
{ | |||
var ct = enc.Encrypt(plain, null, nonce); | |||
byte[] ct = enc.Encrypt(plain, null, nonce); | |||
ct.CopyTo(cipher); | |||
return ct.Length; | |||
} | |||
public override int CipherDecrypt(Span<byte> plain, Span<byte> cipher) | |||
{ | |||
var pt = enc.Decrypt(cipher, null, nonce); | |||
byte[] pt = enc.Decrypt(cipher, null, nonce); | |||
pt.CopyTo(plain); | |||
return pt.Length; | |||
} | |||
@@ -1,5 +1,4 @@ | |||
using Shadowsocks.Controller; | |||
using System; | |||
namespace Shadowsocks.Encryption | |||
{ | |||
@@ -37,7 +36,10 @@ namespace Shadowsocks.Encryption | |||
public class StreamCipherParameter : CipherParameter | |||
{ | |||
public int IvSize; | |||
public override string ToString() => $"stream (key:{KeySize * 8}, iv:{IvSize * 8})"; | |||
public override string ToString() | |||
{ | |||
return $"stream (key:{KeySize * 8}, iv:{IvSize * 8})"; | |||
} | |||
} | |||
public class AEADCipherParameter : CipherParameter | |||
@@ -45,7 +47,10 @@ namespace Shadowsocks.Encryption | |||
public int SaltSize; | |||
public int TagSize; | |||
public int NonceSize; | |||
public override string ToString() => $"aead (key:{KeySize * 8}, salt:{SaltSize * 8}, tag:{TagSize * 8}, nonce:{NonceSize * 8})"; | |||
public override string ToString() | |||
{ | |||
return $"aead (key:{KeySize * 8}, salt:{SaltSize * 8}, tag:{TagSize * 8}, nonce:{NonceSize * 8})"; | |||
} | |||
} | |||
public class CipherInfo | |||
@@ -95,7 +100,10 @@ namespace Shadowsocks.Encryption | |||
} | |||
public string ToString(bool verbose) | |||
{ | |||
if (!verbose) return ToString(); | |||
if (!verbose) | |||
{ | |||
return ToString(); | |||
} | |||
return $"{Name} {StandardState} {CipherParameter}"; | |||
} | |||
@@ -54,7 +54,10 @@ namespace Shadowsocks.Encryption | |||
bool o = true; // overflow flag | |||
for (int i = 0; i < salt.Length; i++) | |||
{ | |||
if (!o) continue; | |||
if (!o) | |||
{ | |||
continue; | |||
} | |||
salt[i]++; | |||
o = salt[i] == 0; | |||
@@ -66,7 +69,11 @@ namespace Shadowsocks.Encryption | |||
bool o = true; // overflow flag | |||
for (int i = 0; i < salt.Length; i++) | |||
{ | |||
if (!o) continue; | |||
if (!o) | |||
{ | |||
continue; | |||
} | |||
salt[i]++; | |||
o = salt[i] == 0; | |||
} | |||
@@ -2,9 +2,8 @@ | |||
// changes: 5th parameter for ProcessBlock, to process without change internal state | |||
using System; | |||
using Org.BouncyCastle.Crypto.Parameters; | |||
using System; | |||
namespace Org.BouncyCastle.Crypto.Modes | |||
{ | |||
@@ -34,10 +33,10 @@ namespace Org.BouncyCastle.Crypto.Modes | |||
int bitBlockSize) | |||
{ | |||
this.cipher = cipher; | |||
this.blockSize = bitBlockSize / 8; | |||
this.IV = new byte[cipher.GetBlockSize()]; | |||
this.cfbV = new byte[cipher.GetBlockSize()]; | |||
this.cfbOutV = new byte[cipher.GetBlockSize()]; | |||
blockSize = bitBlockSize / 8; | |||
IV = new byte[cipher.GetBlockSize()]; | |||
cfbV = new byte[cipher.GetBlockSize()]; | |||
cfbOutV = new byte[cipher.GetBlockSize()]; | |||
} | |||
/** | |||
* return the underlying block cipher that we are wrapping. | |||
@@ -63,7 +62,7 @@ namespace Org.BouncyCastle.Crypto.Modes | |||
bool forEncryption, | |||
ICipherParameters parameters) | |||
{ | |||
this.encrypting = forEncryption; | |||
encrypting = forEncryption; | |||
if (parameters is ParametersWithIV) | |||
{ | |||
ParametersWithIV ivParam = (ParametersWithIV)parameters; | |||
@@ -89,15 +88,9 @@ namespace Org.BouncyCastle.Crypto.Modes | |||
* @return the name of the underlying algorithm followed by "/CFB" | |||
* and the block size in bits. | |||
*/ | |||
public string AlgorithmName | |||
{ | |||
get { return cipher.AlgorithmName + "/CFB" + (blockSize * 8); } | |||
} | |||
public string AlgorithmName => cipher.AlgorithmName + "/CFB" + (blockSize * 8); | |||
public bool IsPartialBlockOkay | |||
{ | |||
get { return true; } | |||
} | |||
public bool IsPartialBlockOkay => true; | |||
/** | |||
* return the block size we are operating at. | |||
@@ -1,8 +1,6 @@ | |||
using Org.BouncyCastle.Crypto; | |||
using Org.BouncyCastle.Crypto.Engines; | |||
using Org.BouncyCastle.Crypto.Engines; | |||
using Org.BouncyCastle.Crypto.Modes; | |||
using Org.BouncyCastle.Crypto.Parameters; | |||
using Org.BouncyCastle.Security; | |||
using System; | |||
using System.Collections.Generic; | |||
@@ -13,12 +11,10 @@ namespace Shadowsocks.Encryption.Stream | |||
{ | |||
byte[] cfbBuf = new byte[MaxInputSize + 128]; | |||
int ptr = 0; | |||
//ExtendedCfbBufferedBlockCipher c; | |||
ExtendedCfbBlockCipher b; | |||
readonly ExtendedCfbBlockCipher b; | |||
public StreamAesBouncyCastleEncryptor(string method, string password) : base(method, password) | |||
{ | |||
b = new ExtendedCfbBlockCipher(new AesEngine(), 128); | |||
// c = new ExtendedCfbBufferedBlockCipher(b); | |||
} | |||
protected override void initCipher(byte[] iv, bool isEncrypt) | |||
@@ -59,14 +55,18 @@ namespace Shadowsocks.Encryption.Stream | |||
tmp.CopyTo(ob.Slice(readPtr)); | |||
readPtr += blkSize; | |||
} | |||
if (readPtr != blkSize * blkCount) throw new System.Exception(); | |||
b.ProcessBlock(cfbBuf, readPtr, tmp, 0, false); | |||
tmp.CopyTo(ob.Slice(readPtr)); | |||
Array.Copy(cfbBuf, readPtr, cfbBuf, 0, restSize); | |||
if (restSize != 0) | |||
{ | |||
readPtr = blkSize * blkCount; | |||
// process last (partial) block without update state | |||
b.ProcessBlock(cfbBuf, readPtr, tmp, 0, false); | |||
tmp.CopyTo(ob.Slice(readPtr)); | |||
// write back the partial block block | |||
Array.Copy(cfbBuf, readPtr, cfbBuf, 0, restSize); | |||
} | |||
// cut correct part to output | |||
ob.Slice(ptr, o.Length).CopyTo(o); | |||
ptr = restSize; | |||
} | |||
#region Cipher Info | |||
@@ -9,6 +9,9 @@ namespace Shadowsocks.Encryption.Stream | |||
const int BlockSize = 64; | |||
// 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 | |||
// we did it in AEADEncryptor.cs for AEAD, it can operate at block level | |||
// but we need do it ourselves in stream cipher. | |||
// when new data arrive, put it on correct offset | |||
// and update it, ignore other data, get it in correct offset... | |||
@@ -29,7 +29,7 @@ namespace Shadowsocks.Encryption.Stream | |||
{ | |||
CipherInfo = getCiphers()[method.ToLower()]; | |||
cipherFamily = CipherInfo.Type; | |||
var parameter = (StreamCipherParameter)CipherInfo.CipherParameter; | |||
StreamCipherParameter parameter = (StreamCipherParameter)CipherInfo.CipherParameter; | |||
keyLen = parameter.KeySize; | |||
ivLen = parameter.IvSize; | |||
@@ -44,7 +44,11 @@ namespace Shadowsocks.Encryption.Stream | |||
{ | |||
byte[] passbuf = Encoding.UTF8.GetBytes(password); | |||
key ??= new byte[keyLen]; | |||
if (key.Length != keyLen) Array.Resize(ref key, keyLen); | |||
if (key.Length != keyLen) | |||
{ | |||
Array.Resize(ref key, keyLen); | |||
} | |||
LegacyDeriveKey(passbuf, key, keyLen); | |||
} | |||
@@ -72,7 +76,11 @@ namespace Shadowsocks.Encryption.Stream | |||
protected virtual void initCipher(byte[] iv, bool isEncrypt) | |||
{ | |||
if (ivLen == 0) return; | |||
if (ivLen == 0) | |||
{ | |||
return; | |||
} | |||
this.iv = new byte[ivLen]; | |||
Array.Copy(iv, this.iv, ivLen); | |||
} | |||
@@ -115,7 +123,7 @@ namespace Shadowsocks.Encryption.Stream | |||
{ | |||
Span<byte> tmp = buf.AsSpan(0, length); | |||
logger.Trace($"{instanceId} decrypt TCP, read iv: {!ivReady}"); | |||
// is first packet, need read iv | |||
if (!ivReady) | |||
{ | |||
@@ -137,7 +145,11 @@ namespace Shadowsocks.Encryption.Stream | |||
byte[] iv = sharedBuffer.AsSpan(0, ivLen).ToArray(); | |||
initCipher(iv, false); | |||
} | |||
else initCipher(Array.Empty<byte>(), false); | |||
else | |||
{ | |||
initCipher(Array.Empty<byte>(), false); | |||
} | |||
tmp = sharedBuffer.AsSpan(ivLen, recieveCtr - ivLen); | |||
} | |||
@@ -1,7 +1,5 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Runtime.CompilerServices; | |||
using System.Text; | |||
namespace Shadowsocks.Encryption.Stream | |||
{ | |||