@@ -22,9 +22,7 @@ namespace Shadowsocks.Controller | |||
{ | |||
if (string.IsNullOrEmpty(_cachedPacSecret)) | |||
{ | |||
var rd = new byte[32]; | |||
RNG.GetBytes(rd); | |||
_cachedPacSecret = HttpServerUtilityUrlToken.Encode(rd); | |||
_cachedPacSecret = HttpServerUtilityUrlToken.Encode(RNG.GetBytes(32)); | |||
} | |||
return _cachedPacSecret; | |||
} | |||
@@ -325,7 +325,6 @@ namespace Shadowsocks.Controller | |||
{ | |||
SystemProxy.Update(_config, true, null); | |||
} | |||
Encryption.RNG.Close(); | |||
} | |||
private void StopPlugins() | |||
@@ -178,8 +178,7 @@ namespace Shadowsocks.Encryption.AEAD | |||
{ | |||
_encryptSaltSent = true; | |||
// Generate salt | |||
byte[] saltBytes = new byte[saltLen]; | |||
RNG.GetBytes(saltBytes, saltLen); | |||
byte[] saltBytes = RNG.GetBytes(saltLen); | |||
InitCipher(saltBytes, true, false); | |||
Array.Copy(saltBytes, 0, outbuf, 0, saltLen); | |||
outlength = saltLen; | |||
@@ -336,11 +335,19 @@ namespace Shadowsocks.Encryption.AEAD | |||
#endregion | |||
#region UDP | |||
/// <summary> | |||
/// Perform AEAD UDP packet encryption | |||
/// </summary> | |||
/// payload => [salt][encrypted payload][tag] | |||
/// <param name="buf"></param> | |||
/// <param name="length"></param> | |||
/// <param name="outbuf"></param> | |||
/// <param name="outlength"></param> | |||
public override void EncryptUDP(byte[] buf, int length, byte[] outbuf, out int outlength) | |||
{ | |||
// Generate salt | |||
RNG.GetBytes(outbuf, saltLen); | |||
//RNG.GetBytes(outbuf, saltLen); | |||
RNG.GetSpan(outbuf.AsSpan().Slice(0, saltLen)); | |||
InitCipher(outbuf, true, true); | |||
//uint olen = 0; | |||
lock (_udpTmpBuf) | |||
@@ -351,7 +358,7 @@ namespace Shadowsocks.Encryption.AEAD | |||
//Debug.Assert(olen == length + tagLen); | |||
Buffer.BlockCopy(cipher, 0, outbuf, saltLen, length + tagLen); | |||
//Buffer.BlockCopy(_udpTmpBuf, 0, outbuf, saltLen, (int)olen); | |||
outlength = (int)(saltLen + cipher.Length); | |||
outlength = saltLen + cipher.Length; | |||
} | |||
} | |||
@@ -35,6 +35,7 @@ namespace Shadowsocks.Encryption | |||
public class StreamCipherParameter : CipherParameter | |||
{ | |||
public int IvSize; | |||
public override string ToString() => $"stream (key:{KeySize * 8}, iv:{IvSize * 8})"; | |||
} | |||
public class AEADCipherParameter : CipherParameter | |||
@@ -42,6 +43,7 @@ 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 class CipherInfo | |||
@@ -87,5 +89,11 @@ namespace Shadowsocks.Encryption | |||
{ | |||
return StandardState == CipherStandardState.InUse ? Name : $"{Name} ({I18N.GetString("deprecated")})"; | |||
} | |||
public string ToString(bool verbose) | |||
{ | |||
if (!verbose) return ToString(); | |||
return $"{Name} {StandardState} {CipherParameter}"; | |||
} | |||
} | |||
} |
@@ -2,6 +2,7 @@ | |||
using Org.BouncyCastle.Crypto.Digests; | |||
using Org.BouncyCastle.Crypto.Generators; | |||
using Org.BouncyCastle.Crypto.Parameters; | |||
using System; | |||
namespace Shadowsocks.Encryption | |||
{ | |||
@@ -15,6 +16,16 @@ namespace Shadowsocks.Encryption | |||
md5.DoFinal(r, 0); | |||
return r; | |||
} | |||
// currently useless, just keep api same | |||
public static Span<byte> MD5(Span<byte> span) | |||
{ | |||
byte[] b = span.ToArray(); | |||
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) | |||
{ | |||
@@ -26,6 +37,17 @@ namespace Shadowsocks.Encryption | |||
hkdf.GenerateBytes(ret, 0, keylen); | |||
return ret; | |||
} | |||
// currently useless, just keep api same, again | |||
public static Span<byte> HKDF(int keylen, Span<byte> master, Span<byte> salt, Span<byte> info) | |||
{ | |||
byte[] ret = new byte[keylen]; | |||
IDigest degist = new Sha1Digest(); | |||
HkdfParameters parameters = new HkdfParameters(master.ToArray(), salt.ToArray(), info.ToArray()); | |||
HkdfBytesGenerator hkdf = new HkdfBytesGenerator(degist); | |||
hkdf.Init(parameters); | |||
hkdf.GenerateBytes(ret, 0, keylen); | |||
return ret.AsSpan(); | |||
} | |||
public static void SodiumIncrement(byte[] salt) | |||
{ | |||
@@ -38,5 +60,16 @@ namespace Shadowsocks.Encryption | |||
o = salt[i] == 0; | |||
} | |||
} | |||
public static void SodiumIncrement(Span<byte> salt) | |||
{ | |||
bool o = true; // overflow flag | |||
for (int i = 0; i < salt.Length; i++) | |||
{ | |||
if (!o) continue; | |||
salt[i]++; | |||
o = salt[i] == 0; | |||
} | |||
} | |||
} | |||
} |
@@ -9,6 +9,8 @@ namespace Shadowsocks.Encryption | |||
{ | |||
public static class EncryptorFactory | |||
{ | |||
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 Type[] ConstructorTypes = { typeof(string), typeof(string) }; | |||
@@ -48,15 +50,6 @@ namespace Shadowsocks.Encryption | |||
_registeredEncryptors.Add(method.Key, typeof(AEADNaClEncryptor)); | |||
} | |||
} | |||
foreach (var method in StreamRc4NativeEncryptor.SupportedCiphers()) | |||
{ | |||
if (!_registeredEncryptors.ContainsKey(method.Key)) | |||
{ | |||
ciphers.Add(method.Key, method.Value); | |||
_registeredEncryptors.Add(method.Key, typeof(StreamRc4NativeEncryptor)); | |||
} | |||
} | |||
} | |||
public static IEncryptor GetEncryptor(string method, string password) | |||
@@ -67,7 +60,11 @@ namespace Shadowsocks.Encryption | |||
} | |||
method = method.ToLowerInvariant(); | |||
Type t = _registeredEncryptors[method]; | |||
bool ok = _registeredEncryptors.TryGetValue(method, out Type t); | |||
if (!ok) | |||
{ | |||
t = _registeredEncryptors[DefaultCipher]; | |||
} | |||
ConstructorInfo c = t.GetConstructor(ConstructorTypes); | |||
if (c == null) throw new System.Exception("Invalid ctor"); | |||
@@ -83,7 +80,7 @@ namespace Shadowsocks.Encryption | |||
sb.AppendLine("Registered Encryptor Info"); | |||
foreach (var encryptor in _registeredEncryptors) | |||
{ | |||
sb.AppendLine(String.Format("{0}=>{1}", encryptor.Key, encryptor.Value.Name)); | |||
sb.AppendLine($"{ciphers[encryptor.Key].ToString(true)} => {encryptor.Value.Name}"); | |||
} | |||
// use ----- instead of =======, so when user paste it to Github, it won't became title | |||
sb.AppendLine("-------------------------"); | |||
@@ -92,6 +89,7 @@ namespace Shadowsocks.Encryption | |||
public static CipherInfo GetCipherInfo(string name) | |||
{ | |||
// TODO: Replace cipher when required not exist | |||
return ciphers[name]; | |||
} | |||
@@ -5,33 +5,35 @@ namespace Shadowsocks.Encryption | |||
{ | |||
public static class RNG | |||
{ | |||
private static RNGCryptoServiceProvider _rng = null; | |||
private static RNGCryptoServiceProvider _rng = new RNGCryptoServiceProvider(); | |||
public static void Init() | |||
public static void Reload() | |||
{ | |||
_rng = _rng ?? new RNGCryptoServiceProvider(); | |||
_rng.Dispose(); | |||
_rng = new RNGCryptoServiceProvider(); | |||
} | |||
public static void Close() | |||
public static void GetSpan(Span<byte> span) | |||
{ | |||
_rng?.Dispose(); | |||
_rng = null; | |||
_rng.GetBytes(span); | |||
} | |||
public static void Reload() | |||
public static Span<byte> GetSpan(int length) | |||
{ | |||
Close(); | |||
Init(); | |||
Span<byte> span = new byte[length]; | |||
_rng.GetBytes(span); | |||
return span; | |||
} | |||
public static void GetBytes(byte[] buf) | |||
public static byte[] GetBytes(int length) | |||
{ | |||
GetBytes(buf, buf.Length); | |||
byte[] buf = new byte[length]; | |||
_rng.GetBytes(buf); | |||
return buf; | |||
} | |||
public static void GetBytes(byte[] buf, int len) | |||
{ | |||
if (_rng == null) Init(); | |||
try | |||
{ | |||
_rng.GetBytes(buf, 0, len); | |||
@@ -107,7 +107,6 @@ namespace Shadowsocks.Test | |||
{ | |||
t.Join(); | |||
} | |||
RNG.Close(); | |||
Assert.IsFalse(encryptionFailed); | |||
} | |||