Browse Source

Merge bouncy-castle into net-core-build

pull/2865/head
Student Main 4 years ago
parent
commit
eac24ede19
26 changed files with 527 additions and 1575 deletions
  1. +2
    -1
      shadowsocks-csharp/Controller/Service/PACServer.cs
  2. BIN
      shadowsocks-csharp/Data/libsscrypto.dll.gz
  3. +77
    -0
      shadowsocks-csharp/Encryption/AEAD/AEADBouncyCastleEncryptor.cs
  4. +2
    -4
      shadowsocks-csharp/Encryption/AEAD/AEADEncryptor.cs
  5. +0
    -178
      shadowsocks-csharp/Encryption/AEAD/AEADMbedTLSEncryptor.cs
  6. +48
    -0
      shadowsocks-csharp/Encryption/AEAD/AEADNativeEncryptor.cs
  7. +0
    -192
      shadowsocks-csharp/Encryption/AEAD/AEADOpenSSLEncryptor.cs
  8. +0
    -141
      shadowsocks-csharp/Encryption/AEAD/AEADSodiumEncryptor.cs
  9. +42
    -0
      shadowsocks-csharp/Encryption/CryptoUtils.cs
  10. +8
    -39
      shadowsocks-csharp/Encryption/EncryptorFactory.cs
  11. +0
    -109
      shadowsocks-csharp/Encryption/MbedTLS.cs
  12. +0
    -164
      shadowsocks-csharp/Encryption/OpenSSL.cs
  13. +0
    -113
      shadowsocks-csharp/Encryption/Sodium.cs
  14. +2
    -2
      shadowsocks-csharp/Encryption/Stream/StreamEncryptor.cs
  15. +0
    -155
      shadowsocks-csharp/Encryption/Stream/StreamMbedTLSEncryptor.cs
  16. +213
    -0
      shadowsocks-csharp/Encryption/Stream/StreamNativeEncryptor.cs
  17. +0
    -159
      shadowsocks-csharp/Encryption/Stream/StreamOpenSSLEncryptor.cs
  18. +0
    -107
      shadowsocks-csharp/Encryption/Stream/StreamSodiumEncryptor.cs
  19. +68
    -85
      shadowsocks-csharp/Properties/Resources.Designer.cs
  20. +0
    -3
      shadowsocks-csharp/Properties/Resources.resx
  21. +13
    -8
      shadowsocks-csharp/View/ConfigForm.cs
  22. +12
    -0
      shadowsocks-csharp/packages.config
  23. +1
    -6
      shadowsocks-csharp/shadowsocks-csharp.csproj
  24. +14
    -0
      test/App.config
  25. +24
    -108
      test/CryptographyTest.cs
  26. +1
    -1
      test/ShadowsocksTest.csproj

+ 2
- 1
shadowsocks-csharp/Controller/Service/PACServer.cs View File

@@ -51,7 +51,8 @@ namespace Shadowsocks.Controller
private static string GetHash(string content) private static string GetHash(string content)
{ {
return HttpServerUtilityUrlToken.Encode(MbedTLS.MD5(Encoding.ASCII.GetBytes(content)));
return HttpServerUtilityUrlToken.Encode(CryptoUtils.MD5(Encoding.ASCII.GetBytes(content)));
} }
public override bool Handle(byte[] firstPacket, int length, Socket socket, object state) public override bool Handle(byte[] firstPacket, int length, Socket socket, object state)


BIN
shadowsocks-csharp/Data/libsscrypto.dll.gz View File


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

@@ -0,0 +1,77 @@
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, IDisposable
{
static int CIPHER_AES = 1; // dummy
public AEADBouncyCastleEncryptor(string method, string password)
: base(method, password)
{
}
private static readonly Dictionary<string, EncryptorInfo> _ciphers = new Dictionary<string, EncryptorInfo>
{
{"aes-128-gcm", new EncryptorInfo("AES-128-GCM", 16, 16, 12, 16, CIPHER_AES)},
{"aes-192-gcm", new EncryptorInfo("AES-192-GCM", 24, 24, 12, 16, CIPHER_AES)},
{"aes-256-gcm", new EncryptorInfo("AES-256-GCM", 32, 32, 12, 16, CIPHER_AES)},
};
protected override Dictionary<string, EncryptorInfo> getCiphers()
{
return _ciphers;
}
public override void InitCipher(byte[] salt, bool isEncrypt, bool isUdp)
{
base.InitCipher(salt, isEncrypt, isUdp);
DeriveSessionKey(isEncrypt ? _encryptSalt : _decryptSalt,
_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);
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)
{
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 static List<string> SupportedCiphers()
{
return new List<string>(_ciphers.Keys);
}
public override void Dispose()
{
}
}
}

+ 2
- 4
shadowsocks-csharp/Encryption/AEAD/AEADEncryptor.cs View File

@@ -103,15 +103,13 @@ namespace Shadowsocks.Encryption.AEAD
public void DeriveSessionKey(byte[] salt, byte[] masterKey, byte[] sessionKey) public void DeriveSessionKey(byte[] salt, byte[] masterKey, byte[] sessionKey)
{ {
int ret = MbedTLS.hkdf(salt, saltLen, masterKey, keyLen, InfoBytes, InfoBytes.Length, sessionKey,
keyLen);
if (ret != 0) throw new System.Exception("failed to generate session key");
CryptoUtils.HKDF(keyLen, masterKey, salt, InfoBytes).CopyTo(sessionKey,0);
} }
protected void IncrementNonce(bool isEncrypt) protected void IncrementNonce(bool isEncrypt)
{ {
lock (_nonceIncrementLock) { lock (_nonceIncrementLock) {
Sodium.sodium_increment(isEncrypt ? _encNonce : _decNonce, nonceLen);
CryptoUtils.SodiumIncrement(isEncrypt ? _encNonce : _decNonce);
} }
} }


+ 0
- 178
shadowsocks-csharp/Encryption/AEAD/AEADMbedTLSEncryptor.cs View File

@@ -1,178 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Shadowsocks.Encryption.Exception;
namespace Shadowsocks.Encryption.AEAD
{
public class AEADMbedTLSEncryptor
: AEADEncryptor, IDisposable
{
const int CIPHER_AES = 1;
private IntPtr _encryptCtx = IntPtr.Zero;
private IntPtr _decryptCtx = IntPtr.Zero;
public AEADMbedTLSEncryptor(string method, string password)
: base(method, password)
{
}
private static readonly Dictionary<string, EncryptorInfo> _ciphers = new Dictionary<string, EncryptorInfo>
{
{"aes-128-gcm", new EncryptorInfo("AES-128-GCM", 16, 16, 12, 16, CIPHER_AES)},
{"aes-192-gcm", new EncryptorInfo("AES-192-GCM", 24, 24, 12, 16, CIPHER_AES)},
{"aes-256-gcm", new EncryptorInfo("AES-256-GCM", 32, 32, 12, 16, CIPHER_AES)},
};
public static List<string> SupportedCiphers()
{
return new List<string>(_ciphers.Keys);
}
protected override Dictionary<string, EncryptorInfo> getCiphers()
{
return _ciphers;
}
public override void InitCipher(byte[] salt, bool isEncrypt, bool isUdp)
{
base.InitCipher(salt, isEncrypt, isUdp);
IntPtr ctx = Marshal.AllocHGlobal(MbedTLS.cipher_get_size_ex());
if (isEncrypt)
{
_encryptCtx = ctx;
}
else
{
_decryptCtx = ctx;
}
MbedTLS.cipher_init(ctx);
if (MbedTLS.cipher_setup(ctx, MbedTLS.cipher_info_from_string(_innerLibName)) != 0)
throw new System.Exception("Cannot initialize mbed TLS cipher context");
DeriveSessionKey(isEncrypt ? _encryptSalt : _decryptSalt,
_Masterkey, _sessionKey);
CipherSetKey(isEncrypt, _sessionKey);
}
private void CipherSetKey(bool isEncrypt, byte[] key)
{
IntPtr ctx = isEncrypt ? _encryptCtx : _decryptCtx;
int ret = MbedTLS.cipher_setkey(ctx, key, keyLen * 8,
isEncrypt ? MbedTLS.MBEDTLS_ENCRYPT : MbedTLS.MBEDTLS_DECRYPT);
if (ret != 0) throw new System.Exception("failed to set key");
ret = MbedTLS.cipher_reset(ctx);
if (ret != 0) throw new System.Exception("failed to finish preparation");
}
public override void cipherEncrypt(byte[] plaintext, uint plen, byte[] ciphertext, ref uint clen)
{
// buf: all plaintext
// outbuf: ciphertext + tag
int ret;
byte[] tagbuf = new byte[tagLen];
uint olen = 0;
switch (_cipher)
{
case CIPHER_AES:
ret = MbedTLS.cipher_auth_encrypt(_encryptCtx,
/* nonce */
_encNonce, (uint) nonceLen,
/* AD */
IntPtr.Zero, 0,
/* plain */
plaintext, plen,
/* cipher */
ciphertext, ref olen,
tagbuf, (uint) tagLen);
if (ret != 0) throw new CryptoErrorException(String.Format("ret is {0}", ret));
Debug.Assert(olen == plen);
// attach tag to ciphertext
Array.Copy(tagbuf, 0, ciphertext, (int) plen, tagLen);
clen = olen + (uint) tagLen;
break;
default:
throw new System.Exception("not implemented");
}
}
public override void cipherDecrypt(byte[] ciphertext, uint clen, byte[] plaintext, ref uint plen)
{
// buf: ciphertext + tag
// outbuf: plaintext
int ret;
uint olen = 0;
// split tag
byte[] tagbuf = new byte[tagLen];
Array.Copy(ciphertext, (int) (clen - tagLen), tagbuf, 0, tagLen);
switch (_cipher)
{
case CIPHER_AES:
ret = MbedTLS.cipher_auth_decrypt(_decryptCtx,
_decNonce, (uint) nonceLen,
IntPtr.Zero, 0,
ciphertext, (uint) (clen - tagLen),
plaintext, ref olen,
tagbuf, (uint) tagLen);
if (ret != 0) throw new CryptoErrorException(String.Format("ret is {0}", ret));
Debug.Assert(olen == clen - tagLen);
plen = olen;
break;
default:
throw new System.Exception("not implemented");
}
}
#region IDisposable
private bool _disposed;
// instance based lock
private readonly object _lock = new object();
public override void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~AEADMbedTLSEncryptor()
{
Dispose(false);
}
protected virtual void Dispose(bool disposing)
{
lock (_lock)
{
if (_disposed) return;
_disposed = true;
}
if (disposing)
{
// free managed objects
}
// free unmanaged objects
if (_encryptCtx != IntPtr.Zero)
{
MbedTLS.cipher_free(_encryptCtx);
Marshal.FreeHGlobal(_encryptCtx);
_encryptCtx = IntPtr.Zero;
}
if (_decryptCtx != IntPtr.Zero)
{
MbedTLS.cipher_free(_decryptCtx);
Marshal.FreeHGlobal(_decryptCtx);
_decryptCtx = IntPtr.Zero;
}
}
#endregion
}
}

+ 48
- 0
shadowsocks-csharp/Encryption/AEAD/AEADNativeEncryptor.cs View File

@@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;

namespace Shadowsocks.Encryption.AEAD
{
public class AEADNativeEncryptor : AEADEncryptor
{
public AEADNativeEncryptor(string method, string password)
: base(method, password)
{
}

public override void cipherDecrypt(byte[] ciphertext, uint clen, byte[] plaintext, ref uint plen)
{
Array.Copy(ciphertext, plaintext, 0);
plen = clen;

}

public override void cipherEncrypt(byte[] plaintext, uint plen, byte[] ciphertext, ref uint clen)
{
Array.Copy(plaintext, ciphertext, 0);
clen = plen;
}

public override void Dispose()
{
return;
}

private static Dictionary<string, EncryptorInfo> _ciphers = new Dictionary<string, EncryptorInfo>()
{
{"plain-fake-aead",new EncryptorInfo("PLAIN_AEAD",0,0,0,0,0) }
};


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

public static IEnumerable<string> SupportedCiphers()
{
return _ciphers.Keys;
}

}
}

+ 0
- 192
shadowsocks-csharp/Encryption/AEAD/AEADOpenSSLEncryptor.cs View File

@@ -1,192 +0,0 @@
using System;
using System.Collections.Generic;
using Shadowsocks.Encryption.Exception;
namespace Shadowsocks.Encryption.AEAD
{
public class AEADOpenSSLEncryptor
: AEADEncryptor, IDisposable
{
const int CIPHER_AES = 1;
const int CIPHER_CHACHA20IETFPOLY1305 = 2;
private byte[] _opensslEncSubkey;
private byte[] _opensslDecSubkey;
private IntPtr _encryptCtx = IntPtr.Zero;
private IntPtr _decryptCtx = IntPtr.Zero;
private IntPtr _cipherInfoPtr = IntPtr.Zero;
public AEADOpenSSLEncryptor(string method, string password)
: base(method, password)
{
_opensslEncSubkey = new byte[keyLen];
_opensslDecSubkey = new byte[keyLen];
}
private static readonly Dictionary<string, EncryptorInfo> _ciphers = new Dictionary<string, EncryptorInfo>
{
{"aes-128-gcm", new EncryptorInfo("aes-128-gcm", 16, 16, 12, 16, CIPHER_AES)},
{"aes-192-gcm", new EncryptorInfo("aes-192-gcm", 24, 24, 12, 16, CIPHER_AES)},
{"aes-256-gcm", new EncryptorInfo("aes-256-gcm", 32, 32, 12, 16, CIPHER_AES)},
{"chacha20-ietf-poly1305", new EncryptorInfo("chacha20-poly1305", 32, 32, 12, 16, CIPHER_CHACHA20IETFPOLY1305)}
};
public static List<string> SupportedCiphers()
{
return new List<string>(_ciphers.Keys);
}
protected override Dictionary<string, EncryptorInfo> getCiphers()
{
return _ciphers;
}
public override void InitCipher(byte[] salt, bool isEncrypt, bool isUdp)
{
base.InitCipher(salt, isEncrypt, isUdp);
_cipherInfoPtr = OpenSSL.GetCipherInfo(_innerLibName);
if (_cipherInfoPtr == IntPtr.Zero) throw new System.Exception("openssl: cipher not found");
IntPtr ctx = OpenSSL.EVP_CIPHER_CTX_new();
if (ctx == IntPtr.Zero) throw new System.Exception("openssl: fail to create ctx");
if (isEncrypt)
{
_encryptCtx = ctx;
}
else
{
_decryptCtx = ctx;
}
DeriveSessionKey(isEncrypt ? _encryptSalt : _decryptSalt, _Masterkey,
isEncrypt ? _opensslEncSubkey : _opensslDecSubkey);
var ret = OpenSSL.EVP_CipherInit_ex(ctx, _cipherInfoPtr, IntPtr.Zero, null, null,
isEncrypt ? OpenSSL.OPENSSL_ENCRYPT : OpenSSL.OPENSSL_DECRYPT);
if (ret != 1) throw new System.Exception("openssl: fail to init ctx");
ret = OpenSSL.EVP_CIPHER_CTX_set_key_length(ctx, keyLen);
if (ret != 1) throw new System.Exception("openssl: fail to set key length");
ret = OpenSSL.EVP_CIPHER_CTX_ctrl(ctx, OpenSSL.EVP_CTRL_AEAD_SET_IVLEN,
nonceLen, IntPtr.Zero);
if (ret != 1) throw new System.Exception("openssl: fail to set AEAD nonce length");
ret = OpenSSL.EVP_CipherInit_ex(ctx, IntPtr.Zero, IntPtr.Zero,
isEncrypt ? _opensslEncSubkey : _opensslDecSubkey,
null,
isEncrypt ? OpenSSL.OPENSSL_ENCRYPT : OpenSSL.OPENSSL_DECRYPT);
if (ret != 1) throw new System.Exception("openssl: cannot set key");
OpenSSL.EVP_CIPHER_CTX_set_padding(ctx, 0);
}
public override void cipherEncrypt(byte[] plaintext, uint plen, byte[] ciphertext, ref uint clen)
{
OpenSSL.SetCtxNonce(_encryptCtx, _encNonce, true);
// buf: all plaintext
// outbuf: ciphertext + tag
int ret;
int tmpLen = 0;
clen = 0;
var tagBuf = new byte[tagLen];
ret = OpenSSL.EVP_CipherUpdate(_encryptCtx, ciphertext, out tmpLen,
plaintext, (int) plen);
if (ret != 1) throw new CryptoErrorException("openssl: fail to encrypt AEAD");
clen += (uint) tmpLen;
// For AEAD cipher, it should not output anything
ret = OpenSSL.EVP_CipherFinal_ex(_encryptCtx, ciphertext, ref tmpLen);
if (ret != 1) throw new CryptoErrorException("openssl: fail to finalize AEAD");
if (tmpLen > 0)
{
throw new System.Exception("openssl: fail to finish AEAD");
}
OpenSSL.AEADGetTag(_encryptCtx, tagBuf, tagLen);
Array.Copy(tagBuf, 0, ciphertext, clen, tagLen);
clen += (uint) tagLen;
}
public override void cipherDecrypt(byte[] ciphertext, uint clen, byte[] plaintext, ref uint plen)
{
OpenSSL.SetCtxNonce(_decryptCtx, _decNonce, false);
// buf: ciphertext + tag
// outbuf: plaintext
int ret;
int tmpLen = 0;
plen = 0;
// split tag
byte[] tagbuf = new byte[tagLen];
Array.Copy(ciphertext, (int) (clen - tagLen), tagbuf, 0, tagLen);
OpenSSL.AEADSetTag(_decryptCtx, tagbuf, tagLen);
ret = OpenSSL.EVP_CipherUpdate(_decryptCtx,
plaintext, out tmpLen, ciphertext, (int) (clen - tagLen));
if (ret != 1) throw new CryptoErrorException("openssl: fail to decrypt AEAD");
plen += (uint) tmpLen;
// For AEAD cipher, it should not output anything
ret = OpenSSL.EVP_CipherFinal_ex(_decryptCtx, plaintext, ref tmpLen);
if (ret <= 0)
{
// If this is not successful authenticated
throw new CryptoErrorException(String.Format("ret is {0}", ret));
}
if (tmpLen > 0)
{
throw new System.Exception("openssl: fail to finish AEAD");
}
}
#region IDisposable
private bool _disposed;
// instance based lock
private readonly object _lock = new object();
public override void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~AEADOpenSSLEncryptor()
{
Dispose(false);
}
protected virtual void Dispose(bool disposing)
{
lock (_lock)
{
if (_disposed) return;
_disposed = true;
}
if (disposing)
{
// free managed objects
}
// free unmanaged objects
if (_encryptCtx != IntPtr.Zero)
{
OpenSSL.EVP_CIPHER_CTX_free(_encryptCtx);
_encryptCtx = IntPtr.Zero;
}
if (_decryptCtx != IntPtr.Zero)
{
OpenSSL.EVP_CIPHER_CTX_free(_decryptCtx);
_decryptCtx = IntPtr.Zero;
}
}
#endregion
}
}

+ 0
- 141
shadowsocks-csharp/Encryption/AEAD/AEADSodiumEncryptor.cs View File

@@ -1,141 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using NLog;
using Shadowsocks.Controller;
using Shadowsocks.Encryption.Exception;
namespace Shadowsocks.Encryption.AEAD
{
public class AEADSodiumEncryptor
: AEADEncryptor, IDisposable
{
private static Logger logger = LogManager.GetCurrentClassLogger();
private const int CIPHER_CHACHA20IETFPOLY1305 = 1;
private const int CIPHER_XCHACHA20IETFPOLY1305 = 2;
private const int CIPHER_AES256GCM = 3;
private byte[] _sodiumEncSubkey;
private byte[] _sodiumDecSubkey;
public AEADSodiumEncryptor(string method, string password)
: base(method, password)
{
_sodiumEncSubkey = new byte[keyLen];
_sodiumDecSubkey = new byte[keyLen];
}
private static readonly Dictionary<string, EncryptorInfo> _ciphers = new Dictionary<string, EncryptorInfo>
{
{"chacha20-ietf-poly1305", new EncryptorInfo(32, 32, 12, 16, CIPHER_CHACHA20IETFPOLY1305)},
{"xchacha20-ietf-poly1305", new EncryptorInfo(32, 32, 24, 16, CIPHER_XCHACHA20IETFPOLY1305)},
{"aes-256-gcm", new EncryptorInfo(32, 32, 12, 16, CIPHER_AES256GCM)},
};
public static List<string> SupportedCiphers()
{
return new List<string>(_ciphers.Keys);
}
protected override Dictionary<string, EncryptorInfo> getCiphers()
{
return _ciphers;
}
public override void InitCipher(byte[] salt, bool isEncrypt, bool isUdp)
{
base.InitCipher(salt, isEncrypt, isUdp);
DeriveSessionKey(isEncrypt ? _encryptSalt : _decryptSalt, _Masterkey,
isEncrypt ? _sodiumEncSubkey : _sodiumDecSubkey);
}
public override void cipherEncrypt(byte[] plaintext, uint plen, byte[] ciphertext, ref uint clen)
{
Debug.Assert(_sodiumEncSubkey != null);
// buf: all plaintext
// outbuf: ciphertext + tag
int ret;
ulong encClen = 0;
logger.Dump("_encNonce before enc", _encNonce, nonceLen);
logger.Dump("_sodiumEncSubkey", _sodiumEncSubkey, keyLen);
logger.Dump("before cipherEncrypt: plain", plaintext, (int) plen);
switch (_cipher)
{
case CIPHER_CHACHA20IETFPOLY1305:
ret = Sodium.crypto_aead_chacha20poly1305_ietf_encrypt(ciphertext, ref encClen,
plaintext, (ulong) plen,
null, 0,
null, _encNonce,
_sodiumEncSubkey);
break;
case CIPHER_XCHACHA20IETFPOLY1305:
ret = Sodium.crypto_aead_xchacha20poly1305_ietf_encrypt(ciphertext, ref encClen,
plaintext, (ulong)plen,
null, 0,
null, _encNonce,
_sodiumEncSubkey);
break;
case CIPHER_AES256GCM:
ret = Sodium.crypto_aead_aes256gcm_encrypt(ciphertext, ref encClen,
plaintext, (ulong)plen,
null, 0,
null, _encNonce,
_sodiumEncSubkey);
break;
default:
throw new System.Exception("not implemented");
}
if (ret != 0) throw new CryptoErrorException(String.Format("ret is {0}", ret));
logger.Dump("after cipherEncrypt: cipher", ciphertext, (int) encClen);
clen = (uint) encClen;
}
public override void cipherDecrypt(byte[] ciphertext, uint clen, byte[] plaintext, ref uint plen)
{
Debug.Assert(_sodiumDecSubkey != null);
// buf: ciphertext + tag
// outbuf: plaintext
int ret;
ulong decPlen = 0;
logger.Dump("_decNonce before dec", _decNonce, nonceLen);
logger.Dump("_sodiumDecSubkey", _sodiumDecSubkey, keyLen);
logger.Dump("before cipherDecrypt: cipher", ciphertext, (int) clen);
switch (_cipher)
{
case CIPHER_CHACHA20IETFPOLY1305:
ret = Sodium.crypto_aead_chacha20poly1305_ietf_decrypt(plaintext, ref decPlen,
null,
ciphertext, (ulong) clen,
null, 0,
_decNonce, _sodiumDecSubkey);
break;
case CIPHER_XCHACHA20IETFPOLY1305:
ret = Sodium.crypto_aead_xchacha20poly1305_ietf_decrypt(plaintext, ref decPlen,
null,
ciphertext, (ulong)clen,
null, 0,
_decNonce, _sodiumDecSubkey);
break;
case CIPHER_AES256GCM:
ret = Sodium.crypto_aead_aes256gcm_decrypt(plaintext, ref decPlen,
null,
ciphertext, (ulong)clen,
null, 0,
_decNonce, _sodiumDecSubkey);
break;
default:
throw new System.Exception("not implemented");
}
if (ret != 0) throw new CryptoErrorException(String.Format("ret is {0}", ret));
logger.Dump("after cipherDecrypt: plain", plaintext, (int) decPlen);
plen = (uint) decPlen;
}
public override void Dispose()
{
}
}
}

+ 42
- 0
shadowsocks-csharp/Encryption/CryptoUtils.cs View File

@@ -0,0 +1,42 @@
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;

namespace Shadowsocks.Encryption
{
public static class CryptoUtils
{
public static byte[] MD5(byte[] b)
{
MD5Digest md5 = new MD5Digest();
md5.BlockUpdate(b, 0, b.Length);
byte[] r = new byte[16];
md5.DoFinal(r, 0);
return r;
}

public static byte[] HKDF(int keylen, byte[] master, byte[] salt, byte[] info)
{
byte[] ret = new byte[keylen];
IDigest degist = new Sha1Digest();
HkdfParameters parameters = new HkdfParameters(master, salt, info);
HkdfBytesGenerator hkdf = new HkdfBytesGenerator(degist);
hkdf.Init(parameters);
hkdf.GenerateBytes(ret, 0, keylen);
return ret;
}

public static void SodiumIncrement(byte[] salt)
{
bool o = true; // overflow flag
for (int i = 0; i < salt.Length; i++)
{
if (!o) continue;

salt[i]++;
o = salt[i] == 0;
}
}
}
}

+ 8
- 39
shadowsocks-csharp/Encryption/EncryptorFactory.cs View File

@@ -11,59 +11,28 @@ namespace Shadowsocks.Encryption
{ {
private static Dictionary<string, Type> _registeredEncryptors = new Dictionary<string, Type>(); private static Dictionary<string, Type> _registeredEncryptors = new Dictionary<string, Type>();
private static readonly Type[] ConstructorTypes = {typeof(string), typeof(string)};
private static readonly Type[] ConstructorTypes = { typeof(string), typeof(string) };
static EncryptorFactory() static EncryptorFactory()
{ {
var AEADMbedTLSEncryptorSupportedCiphers = AEADMbedTLSEncryptor.SupportedCiphers();
var AEADSodiumEncryptorSupportedCiphers = AEADSodiumEncryptor.SupportedCiphers();
if (Sodium.AES256GCMAvailable)
{
// prefer to aes-256-gcm in libsodium
AEADMbedTLSEncryptorSupportedCiphers.Remove("aes-256-gcm");
}
else
{
AEADSodiumEncryptorSupportedCiphers.Remove("aes-256-gcm");
}
// XXX: sequence matters, OpenSSL > Sodium > MbedTLS
foreach (string method in StreamOpenSSLEncryptor.SupportedCiphers())
foreach (string method in StreamNativeEncryptor.SupportedCiphers())
{ {
if (!_registeredEncryptors.ContainsKey(method)) if (!_registeredEncryptors.ContainsKey(method))
_registeredEncryptors.Add(method, typeof(StreamOpenSSLEncryptor));
_registeredEncryptors.Add(method, typeof(StreamNativeEncryptor));
} }
foreach (string method in StreamSodiumEncryptor.SupportedCiphers())
foreach (string method in AEADNativeEncryptor.SupportedCiphers())
{ {
if (!_registeredEncryptors.ContainsKey(method)) if (!_registeredEncryptors.ContainsKey(method))
_registeredEncryptors.Add(method, typeof(StreamSodiumEncryptor));
_registeredEncryptors.Add(method, typeof(AEADNativeEncryptor));
} }
foreach (string method in StreamMbedTLSEncryptor.SupportedCiphers())
foreach (string method in AEADBouncyCastleEncryptor.SupportedCiphers())
{ {
if (!_registeredEncryptors.ContainsKey(method)) if (!_registeredEncryptors.ContainsKey(method))
_registeredEncryptors.Add(method, typeof(StreamMbedTLSEncryptor));
_registeredEncryptors.Add(method, typeof(AEADBouncyCastleEncryptor));
} }
foreach (string method in AEADOpenSSLEncryptor.SupportedCiphers())
{
if (!_registeredEncryptors.ContainsKey(method))
_registeredEncryptors.Add(method, typeof(AEADOpenSSLEncryptor));
}
foreach (string method in AEADSodiumEncryptorSupportedCiphers)
{
if (!_registeredEncryptors.ContainsKey(method))
_registeredEncryptors.Add(method, typeof(AEADSodiumEncryptor));
}
foreach (string method in AEADMbedTLSEncryptorSupportedCiphers)
{
if (!_registeredEncryptors.ContainsKey(method))
_registeredEncryptors.Add(method, typeof(AEADMbedTLSEncryptor));
}
} }
public static IEncryptor GetEncryptor(string method, string password) public static IEncryptor GetEncryptor(string method, string password)
@@ -78,7 +47,7 @@ namespace Shadowsocks.Encryption
ConstructorInfo c = t.GetConstructor(ConstructorTypes); ConstructorInfo c = t.GetConstructor(ConstructorTypes);
if (c == null) throw new System.Exception("Invalid ctor"); if (c == null) throw new System.Exception("Invalid ctor");
IEncryptor result = (IEncryptor) c.Invoke(new object[] {method, password});
IEncryptor result = (IEncryptor)c.Invoke(new object[] { method, password });
return result; return result;
} }


+ 0
- 109
shadowsocks-csharp/Encryption/MbedTLS.cs View File

@@ -1,109 +0,0 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using NLog;
using Shadowsocks.Controller;
using Shadowsocks.Properties;
using Shadowsocks.Util;
namespace Shadowsocks.Encryption
{
public static class MbedTLS
{
private static Logger logger = LogManager.GetCurrentClassLogger();
private const string DLLNAME = "libsscrypto.dll";
public const int MBEDTLS_ENCRYPT = 1;
public const int MBEDTLS_DECRYPT = 0;
static MbedTLS()
{
string dllPath = Utils.GetTempPath(DLLNAME);
try
{
FileManager.UncompressFile(dllPath, Resources.libsscrypto_dll);
}
catch (IOException)
{
}
catch (System.Exception e)
{
logger.LogUsefulException(e);
}
LoadLibrary(dllPath);
}
public static byte[] MD5(byte[] input)
{
byte[] output = new byte[16];
if (md5_ret(input, (uint) input.Length, output) != 0)
throw new System.Exception("mbedtls: MD5 failure");
return output;
}
[DllImport("Kernel32.dll")]
private static extern IntPtr LoadLibrary(string path);
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int md5_ret(byte[] input, uint ilen, byte[] output);
/// <summary>
/// Get cipher ctx size for unmanaged memory allocation
/// </summary>
/// <returns></returns>
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int cipher_get_size_ex();
#region Cipher layer wrappers
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr cipher_info_from_string(string cipher_name);
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern void cipher_init(IntPtr ctx);
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int cipher_setup(IntPtr ctx, IntPtr cipher_info);
// XXX: Check operation before using it
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int cipher_setkey(IntPtr ctx, byte[] key, int key_bitlen, int operation);
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int cipher_set_iv(IntPtr ctx, byte[] iv, int iv_len);
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int cipher_reset(IntPtr ctx);
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int cipher_update(IntPtr ctx, byte[] input, int ilen, byte[] output, ref int olen);
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern void cipher_free(IntPtr ctx);
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int cipher_auth_encrypt(IntPtr ctx,
byte[] iv, uint iv_len,
IntPtr ad, uint ad_len,
byte[] input, uint ilen,
byte[] output, ref uint olen,
byte[] tag, uint tag_len);
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int cipher_auth_decrypt(IntPtr ctx,
byte[] iv, uint iv_len,
IntPtr ad, uint ad_len,
byte[] input, uint ilen,
byte[] output, ref uint olen,
byte[] tag, uint tag_len);
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int hkdf(byte[] salt,
int salt_len, byte[] ikm, int ikm_len,
byte[] info, int info_len, byte[] okm,
int okm_len);
#endregion
}
}

+ 0
- 164
shadowsocks-csharp/Encryption/OpenSSL.cs View File

@@ -1,164 +0,0 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using NLog;
using Shadowsocks.Controller;
using Shadowsocks.Encryption.Exception;
using Shadowsocks.Properties;
using Shadowsocks.Util;
namespace Shadowsocks.Encryption
{
// XXX: only for OpenSSL 1.1.0 and higher
public static class OpenSSL
{
private static Logger logger = LogManager.GetCurrentClassLogger();
private const string DLLNAME = "libsscrypto.dll";
public const int OPENSSL_ENCRYPT = 1;
public const int OPENSSL_DECRYPT = 0;
public const int EVP_CTRL_AEAD_SET_IVLEN = 0x9;
public const int EVP_CTRL_AEAD_GET_TAG = 0x10;
public const int EVP_CTRL_AEAD_SET_TAG = 0x11;
static OpenSSL()
{
string dllPath = Utils.GetTempPath(DLLNAME);
try
{
FileManager.UncompressFile(dllPath, Resources.libsscrypto_dll);
}
catch (IOException)
{
}
catch (System.Exception e)
{
logger.LogUsefulException(e);
}
LoadLibrary(dllPath);
}
public static IntPtr GetCipherInfo(string cipherName)
{
var name = Encoding.ASCII.GetBytes(cipherName);
Array.Resize(ref name, name.Length + 1);
return EVP_get_cipherbyname(name);
}
/// <summary>
/// Need init cipher context after EVP_CipherFinal_ex to reuse context
/// </summary>
/// <param name="ctx"></param>
/// <param name="cipherType"></param>
/// <param name="nonce"></param>
public static void SetCtxNonce(IntPtr ctx, byte[] nonce, bool isEncrypt)
{
var ret = EVP_CipherInit_ex(ctx, IntPtr.Zero,
IntPtr.Zero, null,
nonce,
isEncrypt ? OPENSSL_ENCRYPT : OPENSSL_DECRYPT);
if (ret != 1) throw new System.Exception("openssl: fail to set AEAD nonce");
}
public static void AEADGetTag(IntPtr ctx, byte[] tagbuf, int taglen)
{
IntPtr tagBufIntPtr = IntPtr.Zero;
try
{
tagBufIntPtr = Marshal.AllocHGlobal(taglen);
var ret = EVP_CIPHER_CTX_ctrl(ctx,
EVP_CTRL_AEAD_GET_TAG, taglen, tagBufIntPtr);
if (ret != 1) throw new CryptoErrorException("openssl: fail to get AEAD tag");
// take tag from unmanaged memory
Marshal.Copy(tagBufIntPtr, tagbuf, 0, taglen);
}
finally
{
if (tagBufIntPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(tagBufIntPtr);
}
}
}
public static void AEADSetTag(IntPtr ctx, byte[] tagbuf, int taglen)
{
IntPtr tagBufIntPtr = IntPtr.Zero;
try
{
// allocate unmanaged memory for tag
tagBufIntPtr = Marshal.AllocHGlobal(taglen);
// copy tag to unmanaged memory
Marshal.Copy(tagbuf, 0, tagBufIntPtr, taglen);
var ret = EVP_CIPHER_CTX_ctrl(ctx,
EVP_CTRL_AEAD_SET_TAG, taglen, tagBufIntPtr);
if (ret != 1) throw new CryptoErrorException("openssl: fail to set AEAD tag");
}
finally
{
if (tagBufIntPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(tagBufIntPtr);
}
}
}
[DllImport("Kernel32.dll")]
private static extern IntPtr LoadLibrary(string path);
[SuppressUnmanagedCodeSecurity]
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr EVP_CIPHER_CTX_new();
[SuppressUnmanagedCodeSecurity]
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern void EVP_CIPHER_CTX_free(IntPtr ctx);
[SuppressUnmanagedCodeSecurity]
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int EVP_CIPHER_CTX_reset(IntPtr ctx);
[SuppressUnmanagedCodeSecurity]
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int EVP_CipherInit_ex(IntPtr ctx, IntPtr type,
IntPtr impl, byte[] key, byte[] iv, int enc);
[SuppressUnmanagedCodeSecurity]
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int EVP_CipherUpdate(IntPtr ctx, byte[] outb,
out int outl, byte[] inb, int inl);
[SuppressUnmanagedCodeSecurity]
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int EVP_CipherFinal_ex(IntPtr ctx, byte[] outm, ref int outl);
[SuppressUnmanagedCodeSecurity]
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int EVP_CIPHER_CTX_set_padding(IntPtr x, int padding);
[SuppressUnmanagedCodeSecurity]
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int EVP_CIPHER_CTX_set_key_length(IntPtr x, int keylen);
[SuppressUnmanagedCodeSecurity]
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int EVP_CIPHER_CTX_ctrl(IntPtr ctx, int type, int arg, IntPtr ptr);
/// <summary>
/// simulate NUL-terminated string
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
[SuppressUnmanagedCodeSecurity]
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr EVP_get_cipherbyname(byte[] name);
}
}

+ 0
- 113
shadowsocks-csharp/Encryption/Sodium.cs View File

@@ -1,113 +0,0 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using NLog;
using Shadowsocks.Controller;
using Shadowsocks.Properties;
using Shadowsocks.Util;
namespace Shadowsocks.Encryption
{
public static class Sodium
{
private static Logger logger = LogManager.GetCurrentClassLogger();
private const string DLLNAME = "libsscrypto.dll";
private static bool _initialized = false;
private static readonly object _initLock = new object();
public static bool AES256GCMAvailable { get; private set; } = false;
static Sodium()
{
string dllPath = Utils.GetTempPath(DLLNAME);
try
{
FileManager.UncompressFile(dllPath, Resources.libsscrypto_dll);
}
catch (IOException)
{
}
catch (System.Exception e)
{
logger.LogUsefulException(e);
}
LoadLibrary(dllPath);
lock (_initLock)
{
if (!_initialized)
{
if (sodium_init() == -1)
{
throw new System.Exception("Failed to initialize sodium");
}
else /* 1 means already initialized; 0 means success */
{
_initialized = true;
}
AES256GCMAvailable = crypto_aead_aes256gcm_is_available() == 1;
logger.Debug($"sodium: AES256GCMAvailable is {AES256GCMAvailable}");
}
}
}
[DllImport("Kernel32.dll")]
private static extern IntPtr LoadLibrary(string path);
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
private static extern int sodium_init();
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
private static extern int crypto_aead_aes256gcm_is_available();
#region AEAD
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int sodium_increment(byte[] n, int nlen);
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int crypto_aead_chacha20poly1305_ietf_encrypt(byte[] c, ref ulong clen_p, byte[] m,
ulong mlen, byte[] ad, ulong adlen, byte[] nsec, byte[] npub, byte[] k);
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int crypto_aead_chacha20poly1305_ietf_decrypt(byte[] m, ref ulong mlen_p,
byte[] nsec, byte[] c, ulong clen, byte[] ad, ulong adlen, byte[] npub, byte[] k);
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int crypto_aead_xchacha20poly1305_ietf_encrypt(byte[] c, ref ulong clen_p, byte[] m, ulong mlen,
byte[] ad, ulong adlen, byte[] nsec, byte[] npub, byte[] k);
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int crypto_aead_xchacha20poly1305_ietf_decrypt(byte[] m, ref ulong mlen_p, byte[] nsec, byte[] c,
ulong clen, byte[] ad, ulong adlen, byte[] npub, byte[] k);
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int crypto_aead_aes256gcm_encrypt(byte[] c, ref ulong clen_p, byte[] m, ulong mlen,
byte[] ad, ulong adlen, byte[] nsec, byte[] npub, byte[] k);
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int crypto_aead_aes256gcm_decrypt(byte[] m, ref ulong mlen_p, byte[] nsec, byte[] c,
ulong clen, byte[] ad, ulong adlen, byte[] npub, byte[] k);
#endregion
#region Stream
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int crypto_stream_salsa20_xor_ic(byte[] c, byte[] m, ulong mlen, byte[] n, ulong ic,
byte[] k);
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int crypto_stream_chacha20_xor_ic(byte[] c, byte[] m, ulong mlen, byte[] n, ulong ic,
byte[] k);
[DllImport(DLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern int crypto_stream_chacha20_ietf_xor_ic(byte[] c, byte[] m, ulong mlen, byte[] n, uint ic,
byte[] k);
#endregion
}
}

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

@@ -75,11 +75,11 @@ namespace Shadowsocks.Encryption.Stream
byte[] md5sum = null; byte[] md5sum = null;
while (i < keylen) { while (i < keylen) {
if (i == 0) { if (i == 0) {
md5sum = MbedTLS.MD5(password);
md5sum = CryptoUtils.MD5(password);
} else { } else {
Array.Copy(md5sum, 0, result, 0, MD5_LEN); Array.Copy(md5sum, 0, result, 0, MD5_LEN);
Array.Copy(password, 0, result, MD5_LEN, password.Length); Array.Copy(password, 0, result, MD5_LEN, password.Length);
md5sum = MbedTLS.MD5(result);
md5sum = CryptoUtils.MD5(result);
} }
Array.Copy(md5sum, 0, key, i, Math.Min(MD5_LEN, keylen - i)); Array.Copy(md5sum, 0, key, i, Math.Min(MD5_LEN, keylen - i));
i += MD5_LEN; i += MD5_LEN;


+ 0
- 155
shadowsocks-csharp/Encryption/Stream/StreamMbedTLSEncryptor.cs View File

@@ -1,155 +0,0 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Shadowsocks.Encryption.Exception;
namespace Shadowsocks.Encryption.Stream
{
public class StreamMbedTLSEncryptor
: StreamEncryptor, IDisposable
{
const int CIPHER_RC4 = 1;
const int CIPHER_AES = 2;
const int CIPHER_BLOWFISH = 3;
const int CIPHER_CAMELLIA = 4;
private IntPtr _encryptCtx = IntPtr.Zero;
private IntPtr _decryptCtx = IntPtr.Zero;
public StreamMbedTLSEncryptor(string method, string password)
: base(method, password)
{
}
private static Dictionary<string, EncryptorInfo> _ciphers = new Dictionary<string, EncryptorInfo> {
{ "aes-128-cfb", new EncryptorInfo("AES-128-CFB128", 16, 16, CIPHER_AES) },
{ "aes-192-cfb", new EncryptorInfo("AES-192-CFB128", 24, 16, CIPHER_AES) },
{ "aes-256-cfb", new EncryptorInfo("AES-256-CFB128", 32, 16, CIPHER_AES) },
{ "aes-128-ctr", new EncryptorInfo("AES-128-CTR", 16, 16, CIPHER_AES) },
{ "aes-192-ctr", new EncryptorInfo("AES-192-CTR", 24, 16, CIPHER_AES) },
{ "aes-256-ctr", new EncryptorInfo("AES-256-CTR", 32, 16, CIPHER_AES) },
{ "bf-cfb", new EncryptorInfo("BLOWFISH-CFB64", 16, 8, CIPHER_BLOWFISH) },
{ "camellia-128-cfb", new EncryptorInfo("CAMELLIA-128-CFB128", 16, 16, CIPHER_CAMELLIA) },
{ "camellia-192-cfb", new EncryptorInfo("CAMELLIA-192-CFB128", 24, 16, CIPHER_CAMELLIA) },
{ "camellia-256-cfb", new EncryptorInfo("CAMELLIA-256-CFB128", 32, 16, CIPHER_CAMELLIA) },
{ "rc4-md5", new EncryptorInfo("ARC4-128", 16, 16, CIPHER_RC4) }
};
public static List<string> SupportedCiphers()
{
return new List<string>(_ciphers.Keys);
}
protected override Dictionary<string, EncryptorInfo> getCiphers()
{
return _ciphers;
}
protected override void initCipher(byte[] iv, bool isEncrypt)
{
base.initCipher(iv, isEncrypt);
IntPtr ctx = Marshal.AllocHGlobal(MbedTLS.cipher_get_size_ex());
if (isEncrypt)
{
_encryptCtx = ctx;
}
else
{
_decryptCtx = ctx;
}
byte[] realkey;
if (_method == "rc4-md5")
{
byte[] temp = new byte[keyLen + ivLen];
Array.Copy(_key, 0, temp, 0, keyLen);
Array.Copy(iv, 0, temp, keyLen, ivLen);
realkey = MbedTLS.MD5(temp);
}
else
{
realkey = _key;
}
MbedTLS.cipher_init(ctx);
if (MbedTLS.cipher_setup( ctx, MbedTLS.cipher_info_from_string( _innerLibName ) ) != 0 )
throw new System.Exception("Cannot initialize mbed TLS cipher context");
/*
* MbedTLS takes key length by bit
* cipher_setkey() will set the correct key schedule
* and operation
*
* MBEDTLS_AES_{EN,DE}CRYPT
* == MBEDTLS_BLOWFISH_{EN,DE}CRYPT
* == MBEDTLS_CAMELLIA_{EN,DE}CRYPT
* == MBEDTLS_{EN,DE}CRYPT
*
*/
if (MbedTLS.cipher_setkey(ctx, realkey, keyLen * 8,
isEncrypt ? MbedTLS.MBEDTLS_ENCRYPT : MbedTLS.MBEDTLS_DECRYPT) != 0 )
throw new System.Exception("Cannot set mbed TLS cipher key");
if (MbedTLS.cipher_set_iv(ctx, iv, ivLen) != 0)
throw new System.Exception("Cannot set mbed TLS cipher IV");
if (MbedTLS.cipher_reset(ctx) != 0)
throw new System.Exception("Cannot finalize mbed TLS cipher context");
}
protected override void cipherUpdate(bool isEncrypt, int length, byte[] buf, byte[] outbuf)
{
// C# could be multi-threaded
if (_disposed)
{
throw new ObjectDisposedException(this.ToString());
}
if (MbedTLS.cipher_update(isEncrypt ? _encryptCtx : _decryptCtx,
buf, length, outbuf, ref length) != 0 )
throw new CryptoErrorException();
}
#region IDisposable
private bool _disposed;
// instance based lock
private readonly object _lock = new object();
public override void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~StreamMbedTLSEncryptor()
{
Dispose(false);
}
protected virtual void Dispose(bool disposing)
{
lock (_lock)
{
if (_disposed) return;
_disposed = true;
}
if (disposing)
{
// free managed objects
}
// free unmanaged objects
if (_encryptCtx != IntPtr.Zero)
{
MbedTLS.cipher_free(_encryptCtx);
Marshal.FreeHGlobal(_encryptCtx);
_encryptCtx = IntPtr.Zero;
}
if (_decryptCtx != IntPtr.Zero)
{
MbedTLS.cipher_free(_decryptCtx);
Marshal.FreeHGlobal(_decryptCtx);
_decryptCtx = IntPtr.Zero;
}
}
#endregion
}
}

+ 213
- 0
shadowsocks-csharp/Encryption/Stream/StreamNativeEncryptor.cs View File

@@ -0,0 +1,213 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Shadowsocks.Encryption.Stream
{
public class StreamNativeEncryptor : StreamEncryptor
{
const int Plain = 0;
const int Table = 1;
const int Rc4 = 2;
const int Rc4Md5 = 3;

string _password;

byte[] realkey;
byte[] sbox;
public StreamNativeEncryptor(string method, string password) : base(method, password)
{
_password = password;
}

public override void Dispose()
{
return;
}

protected override void initCipher(byte[] iv, bool isEncrypt)
{
base.initCipher(iv, isEncrypt);
if (_cipher >= Rc4)
{
if (_cipher == Rc4Md5)
{
byte[] temp = new byte[keyLen + ivLen];
Array.Copy(_key, 0, temp, 0, keyLen);
Array.Copy(iv, 0, temp, keyLen, ivLen);
realkey = CryptoUtils.MD5(temp);
}
else
{
realkey = _key;
}
sbox = SBox(realkey);
}
else if (_cipher == Table)
{
ulong a = BitConverter.ToUInt64(CryptoUtils.MD5(Encoding.UTF8.GetBytes(_password)), 0);
for (int i = 0; i < 256; i++)
{
_encryptTable[i] = (byte)i;
}
for (int i = 1; i < 1024; i++)
{
_encryptTable = MergeSort(_encryptTable, a, i);
}
for (int i = 0; i < 256; i++)
{
_decryptTable[_encryptTable[i]] = (byte)i;
}
}
}

protected override void cipherUpdate(bool isEncrypt, int length, byte[] buf, byte[] outbuf)
{
if (_cipher == Table)
{
var table = isEncrypt ? _encryptTable : _decryptTable;
for (int i = 0; i < length; i++)
{
outbuf[i] = table[buf[i]];
}
}
else if (_cipher == Plain)
{
Array.Copy(buf, outbuf, length);
}
else
{
var ctx = isEncrypt ? enc_ctx : dec_ctx;

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

RC4(ctx, sbox, t, length);
Array.Copy(t, outbuf, length);
}
}

private static readonly Dictionary<string, EncryptorInfo> _ciphers = new Dictionary<string, EncryptorInfo>
{
{"plain", new EncryptorInfo("PLAIN", 0, 0, Plain) },
{"table", new EncryptorInfo("TABLE", 0, 0, Table) },
{ "rc4", new EncryptorInfo("RC4", 16, 0, Rc4) }, // original RC4 doesn't use IV
{ "rc4-md5", new EncryptorInfo("RC4", 16, 16, Rc4Md5) },
};

public static IEnumerable<string> SupportedCiphers()
{
return _ciphers.Keys;
}

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

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

private static long Compare(byte x, byte y, ulong a, int i)
{
return (long)(a % (ulong)(x + i)) - (long)(a % (ulong)(y + i));
}

private byte[] MergeSort(byte[] array, ulong a, int j)
{
if (array.Length == 1)
{
return array;
}
int middle = array.Length / 2;
byte[] left = new byte[middle];
for (int i = 0; i < middle; i++)
{
left[i] = array[i];
}
byte[] right = new byte[array.Length - middle];
for (int i = 0; i < array.Length - middle; i++)
{
right[i] = array[i + middle];
}
left = MergeSort(left, a, j);
right = MergeSort(right, a, j);

int leftptr = 0;
int rightptr = 0;

byte[] sorted = new byte[array.Length];
for (int k = 0; k < array.Length; k++)
{
if (rightptr == right.Length || ((leftptr < left.Length) && (Compare(left[leftptr], right[rightptr], a, j) <= 0)))
{
sorted[k] = left[leftptr];
leftptr++;
}
else if (leftptr == left.Length || ((rightptr < right.Length) && (Compare(right[rightptr], left[leftptr], a, j)) <= 0))
{
sorted[k] = right[rightptr];
rightptr++;
}
}
return sorted;
}
#endregion

#region RC4
class Context
{
public int index1 = 0;
public int index2 = 0;
}

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

private byte[] SBox(byte[] key)
{
byte[] s = new byte[256];

for (int i = 0; i < 256; i++)
{
s[i] = (byte)i;
}

for (int i = 0, j = 0; i < 256; i++)
{
j = (j + key[i % key.Length] + s[i]) & 255;

Swap(s, i, j);
}

return s;
}

private void RC4(Context ctx, byte[] s, byte[] data, int length)
{
for (int n = 0; n < length; n++)
{
byte b = data[n];

ctx.index1 = (ctx.index1 + 1) & 255;
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)
{
byte c = s[i];

s[i] = s[j];
s[j] = c;
}
#endregion
}
}

+ 0
- 159
shadowsocks-csharp/Encryption/Stream/StreamOpenSSLEncryptor.cs View File

@@ -1,159 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Shadowsocks.Encryption.Exception;
namespace Shadowsocks.Encryption.Stream
{
public class StreamOpenSSLEncryptor
: StreamEncryptor, IDisposable
{
const int CIPHER_RC4 = 1;
const int CIPHER_AES = 2;
const int CIPHER_CAMELLIA = 3;
const int CIPHER_BLOWFISH = 4;
const int CIPHER_CHACHA20_IETF = 5;
private IntPtr _encryptCtx = IntPtr.Zero;
private IntPtr _decryptCtx = IntPtr.Zero;
public StreamOpenSSLEncryptor(string method, string password)
: base(method, password)
{
}
// XXX: name=RC4,blkSz=1,keyLen=16,ivLen=0, do NOT pass IV to it
private static readonly Dictionary<string, EncryptorInfo> _ciphers = new Dictionary<string, EncryptorInfo>
{
{ "aes-128-cfb", new EncryptorInfo("AES-128-CFB", 16, 16, CIPHER_AES) },
{ "aes-192-cfb", new EncryptorInfo("AES-192-CFB", 24, 16, CIPHER_AES) },
{ "aes-256-cfb", new EncryptorInfo("AES-256-CFB", 32, 16, CIPHER_AES) },
{ "aes-128-ctr", new EncryptorInfo("aes-128-ctr", 16, 16, CIPHER_AES) },
{ "aes-192-ctr", new EncryptorInfo("aes-192-ctr", 24, 16, CIPHER_AES) },
{ "aes-256-ctr", new EncryptorInfo("aes-256-ctr", 32, 16, CIPHER_AES) },
{ "bf-cfb", new EncryptorInfo("bf-cfb", 16, 8, CIPHER_BLOWFISH) },
{ "camellia-128-cfb", new EncryptorInfo("CAMELLIA-128-CFB", 16, 16, CIPHER_CAMELLIA) },
{ "camellia-192-cfb", new EncryptorInfo("CAMELLIA-192-CFB", 24, 16, CIPHER_CAMELLIA) },
{ "camellia-256-cfb", new EncryptorInfo("CAMELLIA-256-CFB", 32, 16, CIPHER_CAMELLIA) },
{ "rc4-md5", new EncryptorInfo("RC4", 16, 16, CIPHER_RC4) },
// it's using ivLen=16, not compatible
//{ "chacha20-ietf", new EncryptorInfo("chacha20", 32, 12, CIPHER_CHACHA20_IETF) }
};
public static List<string> SupportedCiphers()
{
return new List<string>(_ciphers.Keys);
}
protected override Dictionary<string, EncryptorInfo> getCiphers()
{
return _ciphers;
}
protected override void initCipher(byte[] iv, bool isEncrypt)
{
base.initCipher(iv, isEncrypt);
IntPtr cipherInfo = OpenSSL.GetCipherInfo(_innerLibName);
if (cipherInfo == IntPtr.Zero) throw new System.Exception("openssl: cipher not found");
IntPtr ctx = OpenSSL.EVP_CIPHER_CTX_new();
if (ctx == IntPtr.Zero) throw new System.Exception("fail to create ctx");
if (isEncrypt)
{
_encryptCtx = ctx;
}
else
{
_decryptCtx = ctx;
}
byte[] realkey;
if (_method == "rc4-md5")
{
byte[] temp = new byte[keyLen + ivLen];
Array.Copy(_key, 0, temp, 0, keyLen);
Array.Copy(iv, 0, temp, keyLen, ivLen);
realkey = MbedTLS.MD5(temp);
}
else
{
realkey = _key;
}
var ret = OpenSSL.EVP_CipherInit_ex(ctx, cipherInfo, IntPtr.Zero, null,null,
isEncrypt ? OpenSSL.OPENSSL_ENCRYPT : OpenSSL.OPENSSL_DECRYPT);
if (ret != 1) throw new System.Exception("openssl: fail to set key length");
ret = OpenSSL.EVP_CIPHER_CTX_set_key_length(ctx, keyLen);
if (ret != 1) throw new System.Exception("openssl: fail to set key length");
ret = OpenSSL.EVP_CipherInit_ex(ctx, IntPtr.Zero, IntPtr.Zero, realkey,
_method == "rc4-md5" ? null : iv,
isEncrypt ? OpenSSL.OPENSSL_ENCRYPT : OpenSSL.OPENSSL_DECRYPT);
if (ret != 1) throw new System.Exception("openssl: cannot set key and iv");
OpenSSL.EVP_CIPHER_CTX_set_padding(ctx, 0);
}
protected override void cipherUpdate(bool isEncrypt, int length, byte[] buf, byte[] outbuf)
{
// C# could be multi-threaded
if (_disposed)
{
throw new ObjectDisposedException(this.ToString());
}
int outlen = 0;
var ret = OpenSSL.EVP_CipherUpdate(isEncrypt ? _encryptCtx : _decryptCtx,
outbuf, out outlen, buf, length);
if (ret != 1)
throw new CryptoErrorException(String.Format("ret is {0}", ret));
Debug.Assert(outlen == length);
}
#region IDisposable
private bool _disposed;
// instance based lock
private readonly object _lock = new object();
public override void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~StreamOpenSSLEncryptor()
{
Dispose(false);
}
protected virtual void Dispose(bool disposing)
{
lock (_lock)
{
if (_disposed) return;
_disposed = true;
}
if (disposing)
{
// free managed objects
}
// free unmanaged objects
if (_encryptCtx != IntPtr.Zero)
{
OpenSSL.EVP_CIPHER_CTX_free(_encryptCtx);
_encryptCtx = IntPtr.Zero;
}
if (_decryptCtx != IntPtr.Zero)
{
OpenSSL.EVP_CIPHER_CTX_free(_decryptCtx);
_decryptCtx = IntPtr.Zero;
}
}
#endregion
}
}

+ 0
- 107
shadowsocks-csharp/Encryption/Stream/StreamSodiumEncryptor.cs View File

@@ -1,107 +0,0 @@
using System;
using System.Collections.Generic;
using Shadowsocks.Encryption.Exception;
namespace Shadowsocks.Encryption.Stream
{
public class StreamSodiumEncryptor
: StreamEncryptor, IDisposable
{
const int CIPHER_SALSA20 = 1;
const int CIPHER_CHACHA20 = 2;
const int CIPHER_CHACHA20_IETF = 3;
const int SODIUM_BLOCK_SIZE = 64;
protected int _encryptBytesRemaining;
protected int _decryptBytesRemaining;
protected ulong _encryptIC;
protected ulong _decryptIC;
protected byte[] _encryptBuf;
protected byte[] _decryptBuf;
public StreamSodiumEncryptor(string method, string password)
: base(method, password)
{
_encryptBuf = new byte[MAX_INPUT_SIZE + SODIUM_BLOCK_SIZE];
_decryptBuf = new byte[MAX_INPUT_SIZE + SODIUM_BLOCK_SIZE];
}
private static readonly Dictionary<string, EncryptorInfo> _ciphers = new Dictionary<string, EncryptorInfo> {
{ "salsa20", new EncryptorInfo(32, 8, CIPHER_SALSA20) },
{ "chacha20", new EncryptorInfo(32, 8, CIPHER_CHACHA20) },
{ "chacha20-ietf", new EncryptorInfo(32, 12, CIPHER_CHACHA20_IETF) }
};
protected override Dictionary<string, EncryptorInfo> getCiphers()
{
return _ciphers;
}
public static List<string> SupportedCiphers()
{
return new List<string>(_ciphers.Keys);
}
protected override void cipherUpdate(bool isEncrypt, int length, byte[] buf, byte[] outbuf)
{
// TODO write a unidirection cipher so we don't have to if if if
int bytesRemaining;
ulong ic;
byte[] sodiumBuf;
byte[] iv;
int ret = -1;
if (isEncrypt)
{
bytesRemaining = _encryptBytesRemaining;
ic = _encryptIC;
sodiumBuf = _encryptBuf;
iv = _encryptIV;
}
else
{
bytesRemaining = _decryptBytesRemaining;
ic = _decryptIC;
sodiumBuf = _decryptBuf;
iv = _decryptIV;
}
int padding = bytesRemaining;
Buffer.BlockCopy(buf, 0, sodiumBuf, padding, length);
switch (_cipher)
{
case CIPHER_SALSA20:
ret = Sodium.crypto_stream_salsa20_xor_ic(sodiumBuf, sodiumBuf, (ulong)(padding + length), iv, ic, _key);
break;
case CIPHER_CHACHA20:
ret = Sodium.crypto_stream_chacha20_xor_ic(sodiumBuf, sodiumBuf, (ulong)(padding + length), iv, ic, _key);
break;
case CIPHER_CHACHA20_IETF:
ret = Sodium.crypto_stream_chacha20_ietf_xor_ic(sodiumBuf, sodiumBuf, (ulong)(padding + length), iv, (uint)ic, _key);
break;
}
if (ret != 0) throw new CryptoErrorException();
Buffer.BlockCopy(sodiumBuf, padding, outbuf, 0, length);
padding += length;
ic += (ulong)padding / SODIUM_BLOCK_SIZE;
bytesRemaining = padding % SODIUM_BLOCK_SIZE;
if (isEncrypt)
{
_encryptBytesRemaining = bytesRemaining;
_encryptIC = ic;
}
else
{
_decryptBytesRemaining = bytesRemaining;
_decryptIC = ic;
}
}
public override void Dispose()
{
}
}
}

+ 68
- 85
shadowsocks-csharp/Properties/Resources.Designer.cs View File

@@ -1,10 +1,10 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <auto-generated> // <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
// 此代码由工具生成。
// 运行时版本:4.0.30319.42000
// //
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// </auto-generated> // </auto-generated>
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@@ -13,12 +13,12 @@ namespace Shadowsocks.Properties {
/// <summary> /// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// 一个强类型的资源类,用于查找本地化的字符串等。
/// </summary> /// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
// 此类是由 StronglyTypedResourceBuilder
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
// (以 /str 作为命令选项),或重新生成 VS 项目。
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
@@ -33,7 +33,7 @@ namespace Shadowsocks.Properties {
} }
/// <summary> /// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// 返回此类使用的缓存的 ResourceManager 实例。
/// </summary> /// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager { internal static global::System.Resources.ResourceManager ResourceManager {
@@ -47,8 +47,8 @@ namespace Shadowsocks.Properties {
} }
/// <summary> /// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// 重写当前线程的 CurrentUICulture 属性
/// 重写当前线程的 CurrentUICulture 属性。
/// </summary> /// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture { internal static global::System.Globalization.CultureInfo Culture {
@@ -61,7 +61,7 @@ namespace Shadowsocks.Properties {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to /* eslint-disable */
/// 查找类似 /* eslint-disable */
///// Was generated by gfwlist2pac in precise mode ///// Was generated by gfwlist2pac in precise mode
///// https://github.com/clowwindy/gfwlist2pac ///// https://github.com/clowwindy/gfwlist2pac
/// ///
@@ -76,7 +76,7 @@ namespace Shadowsocks.Properties {
///* This file is part of Adblock Plus &lt;http://adblockplus.org/&gt;, ///* This file is part of Adblock Plus &lt;http://adblockplus.org/&gt;,
///* Copyright (C) 2006-2014 Eyeo GmbH ///* Copyright (C) 2006-2014 Eyeo GmbH
///* ///*
///* Adblock Plus is free software: you can redistribute it and/or [rest of string was truncated]&quot;;.
///* Adblock Plus is free software: you can redistribute it and/or [字符串的其余部分被截断]&quot;; 的本地化字符串。
/// </summary> /// </summary>
internal static string abp_js { internal static string abp_js {
get { get {
@@ -85,29 +85,28 @@ namespace Shadowsocks.Properties {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to var __USERRULES__ = [];
///var __RULES__ = [
/// &quot;|http://85.17.73.31/&quot;,
/// &quot;||agnesb.fr&quot;,
/// &quot;||akiba-web.com&quot;,
/// &quot;||altrec.com&quot;,
/// &quot;||angela-merkel.de&quot;,
/// &quot;||angola.org&quot;,
/// &quot;||apartmentratings.com&quot;,
/// &quot;||apartments.com&quot;,
/// &quot;||arena.taipei&quot;,
/// &quot;||asianspiss.com&quot;,
/// &quot;||assimp.org&quot;,
/// &quot;||athenaeizou.com&quot;,
/// &quot;||azubu.tv&quot;,
/// &quot;||bankmobilevibe.com&quot;,
/// &quot;||banorte.com&quot;,
/// &quot;||bash-hackers.org&quot;,
/// &quot;||beeg.com&quot;,
/// &quot;||global.bing.com&quot;,
/// &quot;||bloombergview.com&quot;,
/// &quot;||booktopia.com.au&quot;,
/// [rest of string was truncated]&quot;;.
/// 查找类似 var __USERRULES__ = [];
///var __RULES__ = [
/// &quot;|http://85.17.73.31/&quot;,
/// &quot;||agnesb.fr&quot;,
/// &quot;||akiba-web.com&quot;,
/// &quot;||altrec.com&quot;,
/// &quot;||angela-merkel.de&quot;,
/// &quot;||angola.org&quot;,
/// &quot;||apartmentratings.com&quot;,
/// &quot;||apartments.com&quot;,
/// &quot;||arena.taipei&quot;,
/// &quot;||asianspiss.com&quot;,
/// &quot;||assimp.org&quot;,
/// &quot;||athenaeizou.com&quot;,
/// &quot;||azubu.tv&quot;,
/// &quot;||bankmobilevibe.com&quot;,
/// &quot;||banorte.com&quot;,
/// &quot;||bash-hackers.org&quot;,
/// &quot;||beeg.com&quot;,
/// &quot;||global.bing.com&quot;,
/// &quot;||bloombergview.com&quot;,
/// &quot; [字符串的其余部分被截断]&quot;; 的本地化字符串。
/// </summary> /// </summary>
internal static string default_abp_rule { internal static string default_abp_rule {
get { get {
@@ -116,24 +115,21 @@ namespace Shadowsocks.Properties {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to en,zh-CN,zh-TW,ja
///#Restart program to apply translation,,,
///#This is comment line,,,
///#Always keep language name at head of file,,,
///#Language name is output in log,,,
///&quot;#You can find it by search &quot;&quot;Current language is:&quot;&quot;&quot;,,,
///#Please use UTF-8 with BOM encoding so we can edit it in Excel,,,
///,,,
///Shadowsocks,Shadowsocks,Shadowsocks,Shadowsocks
///,,,
///#Menu,,,
///,,,
///System Proxy,系统代理,系統代理,システムプロキシ
///Disable,禁用,禁用,無効
///PAC,PAC 模式,PAC 模式,PAC
///Global,全局模式,全局模式,全般
///Servers,服务器,伺服器,サーバー
///Edit Servers...,编辑服务器...,編輯伺服器...,サーバーの編集.. [rest of string was truncated]&quot;;.
/// 查找类似 en,ru-RU,zh-CN,zh-TW,ja
///#Restart program to apply translation,,,,
///#This is comment line,,,,
///#Always keep language name at head of file,,,,
///#Language name is output in log,,,,
///&quot;#You can find it by search &quot;&quot;Current language is:&quot;&quot;&quot;,,,,
///#Please use UTF-8 with BOM encoding so we can edit it in Excel,,,,
///,,,,
///Shadowsocks,Shadowsocks,Shadowsocks,Shadowsocks,Shadowsocks
///,,,,
///#Menu,,,,
///,,,,
///System Proxy,Системный прокси-сервер,系统代理,系統代理,システムプロキシ
///Disable,Отключен,禁用,禁用,無効
///PAC,Сценарий настройки (PAC),PA [字符串的其余部分被截断]&quot;; 的本地化字符串。
/// </summary> /// </summary>
internal static string i18n_csv { internal static string i18n_csv {
get { get {
@@ -142,26 +138,13 @@ namespace Shadowsocks.Properties {
} }
/// <summary> /// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] libsscrypto_dll {
get {
object obj = ResourceManager.GetObject("libsscrypto_dll", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt;
/// 查找类似 &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt;
///&lt;!-- Warning: Configuration may reset after shadowsocks upgrade. --&gt;
///&lt;!-- If you messed it up, delete this file and Shadowsocks will create a new one. --&gt;
///&lt;nlog xmlns=&quot;http://www.nlog-project.org/schemas/NLog.xsd&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;&gt; ///&lt;nlog xmlns=&quot;http://www.nlog-project.org/schemas/NLog.xsd&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;&gt;
/// &lt;targets&gt; /// &lt;targets&gt;
/// &lt;target name=&quot;file&quot; xsi:type=&quot;File&quot; fileName=&quot;shadowsocks.log&quot;/&gt;
///
/// &lt;/targets&gt;
/// &lt;rules&gt;
/// &lt;logger name=&quot;Name.Space.Class1&quot; minlevel=&quot;Debug&quot; writeTo=&quot;f1&quot; /&gt;
/// &lt;/rules&gt;
///&lt;/nlog&gt;.
/// &lt;!-- This line is managed by Shadowsocks. Do not modify it unless you know what you are doing.--&gt;
/// &lt;target name=&quot;file&quot; xsi:type=&quot;File&quot; fileName=&quot;ss_win_temp\shadowsocks.log&quot; writ [字符串的其余部分被截断]&quot;; 的本地化字符串。
/// </summary> /// </summary>
internal static string NLog_config { internal static string NLog_config {
get { get {
@@ -170,7 +153,7 @@ namespace Shadowsocks.Properties {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to listen-address __PRIVOXY_BIND_IP__:__PRIVOXY_BIND_PORT__
/// 查找类似 listen-address __PRIVOXY_BIND_IP__:__PRIVOXY_BIND_PORT__
///toggle 0 ///toggle 0
///logfile ss_privoxy.log ///logfile ss_privoxy.log
///show-on-task-bar 0 ///show-on-task-bar 0
@@ -178,7 +161,7 @@ namespace Shadowsocks.Properties {
///forward-socks5 / __SOCKS_HOST__:__SOCKS_PORT__ . ///forward-socks5 / __SOCKS_HOST__:__SOCKS_PORT__ .
///max-client-connections 2048 ///max-client-connections 2048
///hide-console ///hide-console
///.
/// 的本地化字符串。
/// </summary> /// </summary>
internal static string privoxy_conf { internal static string privoxy_conf {
get { get {
@@ -187,7 +170,7 @@ namespace Shadowsocks.Properties {
} }
/// <summary> /// <summary>
/// Looks up a localized resource of type System.Byte[].
/// 查找 System.Byte[] 类型的本地化资源。
/// </summary> /// </summary>
internal static byte[] privoxy_exe { internal static byte[] privoxy_exe {
get { get {
@@ -197,7 +180,7 @@ namespace Shadowsocks.Properties {
} }
/// <summary> /// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
/// </summary> /// </summary>
internal static System.Drawing.Bitmap ss32Fill { internal static System.Drawing.Bitmap ss32Fill {
get { get {
@@ -207,7 +190,7 @@ namespace Shadowsocks.Properties {
} }
/// <summary> /// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
/// </summary> /// </summary>
internal static System.Drawing.Bitmap ss32In { internal static System.Drawing.Bitmap ss32In {
get { get {
@@ -217,7 +200,7 @@ namespace Shadowsocks.Properties {
} }
/// <summary> /// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
/// </summary> /// </summary>
internal static System.Drawing.Bitmap ss32Out { internal static System.Drawing.Bitmap ss32Out {
get { get {
@@ -227,7 +210,7 @@ namespace Shadowsocks.Properties {
} }
/// <summary> /// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
/// </summary> /// </summary>
internal static System.Drawing.Bitmap ss32Outline { internal static System.Drawing.Bitmap ss32Outline {
get { get {
@@ -237,7 +220,7 @@ namespace Shadowsocks.Properties {
} }
/// <summary> /// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
/// </summary> /// </summary>
internal static System.Drawing.Bitmap ssw128 { internal static System.Drawing.Bitmap ssw128 {
get { get {
@@ -247,7 +230,7 @@ namespace Shadowsocks.Properties {
} }
/// <summary> /// <summary>
/// Looks up a localized resource of type System.Byte[].
/// 查找 System.Byte[] 类型的本地化资源。
/// </summary> /// </summary>
internal static byte[] sysproxy_exe { internal static byte[] sysproxy_exe {
get { get {
@@ -257,7 +240,7 @@ namespace Shadowsocks.Properties {
} }
/// <summary> /// <summary>
/// Looks up a localized resource of type System.Byte[].
/// 查找 System.Byte[] 类型的本地化资源。
/// </summary> /// </summary>
internal static byte[] sysproxy64_exe { internal static byte[] sysproxy64_exe {
get { get {
@@ -267,9 +250,9 @@ namespace Shadowsocks.Properties {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to ! Put user rules line by line in this file.
/// 查找类似 ! Put user rules line by line in this file.
///! See https://adblockplus.org/en/filter-cheatsheet ///! See https://adblockplus.org/en/filter-cheatsheet
///.
/// 的本地化字符串。
/// </summary> /// </summary>
internal static string user_rule { internal static string user_rule {
get { get {


+ 0
- 3
shadowsocks-csharp/Properties/Resources.resx View File

@@ -127,9 +127,6 @@
<data name="i18n_csv" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="i18n_csv" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Data\i18n.csv;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value> <value>..\Data\i18n.csv;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data> </data>
<data name="libsscrypto_dll" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Data\libsscrypto.dll.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="NLog_config" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="NLog_config" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\data\nlog.config;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value> <value>..\data\nlog.config;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data> </data>


+ 13
- 8
shadowsocks-csharp/View/ConfigForm.cs View File

@@ -31,6 +31,18 @@ namespace Shadowsocks.View
"salsa20", "salsa20",
"chacha20", "chacha20",
"bf-cfb", "bf-cfb",
"rc4",
"plain",
"table",
};
private static string[] inuseMethod = new string[]
{
"aes-256-gcm",
"aes-192-gcm",
"aes-128-gcm",
"chacha20-ietf-poly1305",
"xchacha20-ietf-poly1305",
"chacha20-ietf", "chacha20-ietf",
"aes-256-cfb", "aes-256-cfb",
"aes-192-cfb", "aes-192-cfb",
@@ -42,14 +54,7 @@ namespace Shadowsocks.View
"camellia-192-cfb", "camellia-192-cfb",
"camellia-128-cfb", "camellia-128-cfb",
}; };
private static string[] inuseMethod = new string[]
{
"aes-256-gcm",
"aes-192-gcm",
"aes-128-gcm",
"chacha20-ietf-poly1305",
"xchacha20-ietf-poly1305",
};
public static EncryptionMethod[] AllMethods public static EncryptionMethod[] AllMethods
{ {
get get


+ 12
- 0
shadowsocks-csharp/packages.config View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="BouncyCastle" version="1.8.5" targetFramework="net472" />
<package id="Caseless.Fody" version="1.8.3" targetFramework="net472" />
<package id="Costura.Fody" version="3.3.3" targetFramework="net472" />
<package id="Fody" version="4.2.1" targetFramework="net472" developmentDependency="true" />
<package id="GlobalHotKey" version="1.1.0" targetFramework="net472" />
<package id="Newtonsoft.Json" version="12.0.2" targetFramework="net472" />
<package id="NLog" version="4.6.8" targetFramework="net472" />
<package id="StringEx.CS" version="0.3.1" targetFramework="net472" developmentDependency="true" />
<package id="ZXing.Net" version="0.16.5" targetFramework="net472" />
</packages>

+ 1
- 6
shadowsocks-csharp/shadowsocks-csharp.csproj View File

@@ -14,11 +14,6 @@
<StartupObject /> <StartupObject />
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<Prefer32Bit>true</Prefer32Bit>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<None Remove="app.config" /> <None Remove="app.config" />
<None Remove="app.manifest" /> <None Remove="app.manifest" />
@@ -62,6 +57,7 @@
<PackageReference Include="GlobalHotKeyCore" Version="1.2.0" /> <PackageReference Include="GlobalHotKeyCore" Version="1.2.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="BouncyCastle.NetCore" Version="1.8.5" />
<PackageReference Include="Caseless.Fody" Version="1.9.0" /> <PackageReference Include="Caseless.Fody" Version="1.9.0" />
<PackageReference Include="Costura.Fody" Version="4.1.0" /> <PackageReference Include="Costura.Fody" Version="4.1.0" />
<PackageReference Include="Fody" Version="6.1.1"> <PackageReference Include="Fody" Version="6.1.1">
@@ -86,7 +82,6 @@
<Resource Include="Data\abp.js" /> <Resource Include="Data\abp.js" />
<Resource Include="Data\default-abp-rule.js" /> <Resource Include="Data\default-abp-rule.js" />
<Resource Include="Data\i18n.csv" /> <Resource Include="Data\i18n.csv" />
<Resource Include="Data\libsscrypto.dll.gz" />
<Resource Include="Data\NLog.config" /> <Resource Include="Data\NLog.config" />
<Resource Include="Data\privoxy.exe.gz" /> <Resource Include="Data\privoxy.exe.gz" />
<Resource Include="Data\privoxy_conf.txt" /> <Resource Include="Data\privoxy_conf.txt" />


+ 14
- 0
test/App.config View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog"/>
</configSections>
<nlog>
<targets>
<target name="logconsole" type="Debugger" />
</targets>
<rules>
<logger name="*" minlevel="Trace" writeTo="logconsole" />
</rules>
</nlog>
</configuration>

+ 24
- 108
test/CryptographyTest.cs View File

@@ -1,10 +1,9 @@
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Shadowsocks.Encryption; using Shadowsocks.Encryption;
using System.Threading;
using System.Collections.Generic;
using Shadowsocks.Encryption.Stream; using Shadowsocks.Encryption.Stream;
using System.Diagnostics;
using System;
using System.Collections.Generic;
using System.Threading;
namespace Shadowsocks.Test namespace Shadowsocks.Test
{ {
@@ -22,7 +21,7 @@ namespace Shadowsocks.Test
var random = new Random(); var random = new Random();
random.NextBytes(bytes); random.NextBytes(bytes);
string md5str = Convert.ToBase64String(md5.ComputeHash(bytes)); string md5str = Convert.ToBase64String(md5.ComputeHash(bytes));
string md5str2 = Convert.ToBase64String(MbedTLS.MD5(bytes));
string md5str2 = Convert.ToBase64String(CryptoUtils.MD5(bytes));
Assert.IsTrue(md5str == md5str2); Assert.IsTrue(md5str == md5str2);
} }
} }
@@ -31,7 +30,7 @@ namespace Shadowsocks.Test
{ {
RNG.Reload(); RNG.Reload();
byte[] plain = new byte[16384]; byte[] plain = new byte[16384];
byte[] cipher = new byte[plain.Length + 16];
byte[] cipher = new byte[plain.Length + 100];// AEAD with IPv4 address type needs +100
byte[] plain2 = new byte[plain.Length + 16]; byte[] plain2 = new byte[plain.Length + 16];
int outLen = 0; int outLen = 0;
int outLen2 = 0; int outLen2 = 0;
@@ -64,57 +63,15 @@ namespace Shadowsocks.Test
private static object locker = new object(); private static object locker = new object();
[TestMethod] [TestMethod]
public void TestMbedTLSEncryption()
{
encryptionFailed = false;
// run it once before the multi-threading test to initialize global tables
RunSingleMbedTLSEncryptionThread();
List<Thread> threads = new List<Thread>();
for (int i = 0; i < 10; i++)
{
Thread t = new Thread(new ThreadStart(RunSingleMbedTLSEncryptionThread));
threads.Add(t);
t.Start();
}
foreach (Thread t in threads)
{
t.Join();
}
RNG.Close();
Assert.IsFalse(encryptionFailed);
}
private void RunSingleMbedTLSEncryptionThread()
{
try
{
for (int i = 0; i < 100; i++)
{
IEncryptor encryptor;
IEncryptor decryptor;
encryptor = new StreamMbedTLSEncryptor("aes-256-cfb", "barfoo!");
decryptor = new StreamMbedTLSEncryptor("aes-256-cfb", "barfoo!");
RunEncryptionRound(encryptor, decryptor);
}
}
catch
{
encryptionFailed = true;
throw;
}
}
[TestMethod]
public void TestRC4Encryption()
public void TestBouncyCastleAEADEncryption()
{ {
encryptionFailed = false; encryptionFailed = false;
// run it once before the multi-threading test to initialize global tables // run it once before the multi-threading test to initialize global tables
RunSingleRC4EncryptionThread();
RunSingleBouncyCastleAEADEncryptionThread();
List<Thread> threads = new List<Thread>(); List<Thread> threads = new List<Thread>();
for (int i = 0; i < 10; i++) for (int i = 0; i < 10; i++)
{ {
Thread t = new Thread(new ThreadStart(RunSingleRC4EncryptionThread));
threads.Add(t);
Thread t = new Thread(new ThreadStart(RunSingleBouncyCastleAEADEncryptionThread)); threads.Add(t);
t.Start(); t.Start();
} }
foreach (Thread t in threads) foreach (Thread t in threads)
@@ -125,37 +82,16 @@ namespace Shadowsocks.Test
Assert.IsFalse(encryptionFailed); Assert.IsFalse(encryptionFailed);
} }
private void RunSingleRC4EncryptionThread()
{
try
{
for (int i = 0; i < 100; i++)
{
var random = new Random();
IEncryptor encryptor;
IEncryptor decryptor;
encryptor = new StreamMbedTLSEncryptor("rc4-md5", "barfoo!");
decryptor = new StreamMbedTLSEncryptor("rc4-md5", "barfoo!");
RunEncryptionRound(encryptor, decryptor);
}
}
catch
{
encryptionFailed = true;
throw;
}
}
[TestMethod] [TestMethod]
public void TestSodiumEncryption()
public void TestNativeEncryption()
{ {
encryptionFailed = false; encryptionFailed = false;
// run it once before the multi-threading test to initialize global tables // run it once before the multi-threading test to initialize global tables
RunSingleSodiumEncryptionThread();
RunSingleNativeEncryptionThread();
List<Thread> threads = new List<Thread>(); List<Thread> threads = new List<Thread>();
for (int i = 0; i < 10; i++) for (int i = 0; i < 10; i++)
{ {
Thread t = new Thread(new ThreadStart(RunSingleSodiumEncryptionThread));
Thread t = new Thread(new ThreadStart(RunSingleNativeEncryptionThread));
threads.Add(t); threads.Add(t);
t.Start(); t.Start();
} }
@@ -167,18 +103,17 @@ namespace Shadowsocks.Test
Assert.IsFalse(encryptionFailed); Assert.IsFalse(encryptionFailed);
} }
private void RunSingleSodiumEncryptionThread()
private void RunSingleNativeEncryptionThread()
{ {
try try
{ {
for (int i = 0; i < 100; i++) for (int i = 0; i < 100; i++)
{ {
var random = new Random();
IEncryptor encryptor;
IEncryptor decryptor;
encryptor = new StreamSodiumEncryptor("salsa20", "barfoo!");
decryptor = new StreamSodiumEncryptor("salsa20", "barfoo!");
RunEncryptionRound(encryptor, decryptor);
IEncryptor encryptorN;
IEncryptor decryptorN;
encryptorN = new StreamNativeEncryptor("rc4-md5", "barfoo!");
decryptorN = new StreamNativeEncryptor("rc4-md5", "barfoo!");
RunEncryptionRound(encryptorN, decryptorN);
} }
} }
catch catch
@@ -188,28 +123,7 @@ namespace Shadowsocks.Test
} }
} }
[TestMethod]
public void TestOpenSSLEncryption()
{
encryptionFailed = false;
// run it once before the multi-threading test to initialize global tables
RunSingleOpenSSLEncryptionThread();
List<Thread> threads = new List<Thread>();
for (int i = 0; i < 10; i++)
{
Thread t = new Thread(new ThreadStart(RunSingleOpenSSLEncryptionThread));
threads.Add(t);
t.Start();
}
foreach (Thread t in threads)
{
t.Join();
}
RNG.Close();
Assert.IsFalse(encryptionFailed);
}
private void RunSingleOpenSSLEncryptionThread()
private void RunSingleBouncyCastleAEADEncryptionThread()
{ {
try try
{ {
@@ -218,8 +132,10 @@ namespace Shadowsocks.Test
var random = new Random(); var random = new Random();
IEncryptor encryptor; IEncryptor encryptor;
IEncryptor decryptor; IEncryptor decryptor;
encryptor = new StreamOpenSSLEncryptor("aes-256-cfb", "barfoo!");
decryptor = new StreamOpenSSLEncryptor("aes-256-cfb", "barfoo!");
encryptor = new Encryption.AEAD.AEADBouncyCastleEncryptor("aes-256-gcm", "barfoo!");
encryptor.AddrBufLength = 1 + 4 + 2;// ADDR_ATYP_LEN + 4 + ADDR_PORT_LEN;
decryptor = new Encryption.AEAD.AEADBouncyCastleEncryptor("aes-256-gcm", "barfoo!");
decryptor.AddrBufLength = 1 + 4 + 2;// ADDR_ATYP_LEN + 4 + ADDR_PORT_LEN;
RunEncryptionRound(encryptor, decryptor); RunEncryptionRound(encryptor, decryptor);
} }
} }
@@ -230,4 +146,4 @@ namespace Shadowsocks.Test
} }
} }
} }
}
}

+ 1
- 1
test/ShadowsocksTest.csproj View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework> <TargetFramework>netcoreapp3.1</TargetFramework>


Loading…
Cancel
Save