diff --git a/shadowsocks-csharp/Controller/Service/PACServer.cs b/shadowsocks-csharp/Controller/Service/PACServer.cs
index b17fece0..9e02b68d 100644
--- a/shadowsocks-csharp/Controller/Service/PACServer.cs
+++ b/shadowsocks-csharp/Controller/Service/PACServer.cs
@@ -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;
}
diff --git a/shadowsocks-csharp/Controller/ShadowsocksController.cs b/shadowsocks-csharp/Controller/ShadowsocksController.cs
index f4ea1294..548d9f17 100644
--- a/shadowsocks-csharp/Controller/ShadowsocksController.cs
+++ b/shadowsocks-csharp/Controller/ShadowsocksController.cs
@@ -325,7 +325,6 @@ namespace Shadowsocks.Controller
{
SystemProxy.Update(_config, true, null);
}
- Encryption.RNG.Close();
}
private void StopPlugins()
diff --git a/shadowsocks-csharp/Encryption/AEAD/AEADEncryptor.cs b/shadowsocks-csharp/Encryption/AEAD/AEADEncryptor.cs
index daa3ff07..924dfa8e 100644
--- a/shadowsocks-csharp/Encryption/AEAD/AEADEncryptor.cs
+++ b/shadowsocks-csharp/Encryption/AEAD/AEADEncryptor.cs
@@ -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
-
+ ///
+ /// Perform AEAD UDP packet encryption
+ ///
+ /// payload => [salt][encrypted payload][tag]
+ ///
+ ///
+ ///
+ ///
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;
}
}
diff --git a/shadowsocks-csharp/Encryption/CipherInfo.cs b/shadowsocks-csharp/Encryption/CipherInfo.cs
index 79753cbd..1f3b8939 100644
--- a/shadowsocks-csharp/Encryption/CipherInfo.cs
+++ b/shadowsocks-csharp/Encryption/CipherInfo.cs
@@ -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}";
+ }
}
}
\ No newline at end of file
diff --git a/shadowsocks-csharp/Encryption/CryptoUtils.cs b/shadowsocks-csharp/Encryption/CryptoUtils.cs
index cd4fe394..1a31a84e 100644
--- a/shadowsocks-csharp/Encryption/CryptoUtils.cs
+++ b/shadowsocks-csharp/Encryption/CryptoUtils.cs
@@ -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 MD5(Span 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 HKDF(int keylen, Span master, Span salt, Span 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 salt)
+ {
+ bool o = true; // overflow flag
+ for (int i = 0; i < salt.Length; i++)
+ {
+ if (!o) continue;
+ salt[i]++;
+ o = salt[i] == 0;
+ }
+ }
}
}
diff --git a/shadowsocks-csharp/Encryption/EncryptorFactory.cs b/shadowsocks-csharp/Encryption/EncryptorFactory.cs
index c9eadb7f..a2c239a2 100644
--- a/shadowsocks-csharp/Encryption/EncryptorFactory.cs
+++ b/shadowsocks-csharp/Encryption/EncryptorFactory.cs
@@ -9,6 +9,8 @@ namespace Shadowsocks.Encryption
{
public static class EncryptorFactory
{
+ public static string DefaultCipher = "chacha20-ietf-poly1305";
+
private static Dictionary _registeredEncryptors = new Dictionary();
private static Dictionary ciphers = new Dictionary();
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];
}
diff --git a/shadowsocks-csharp/Encryption/RNG.cs b/shadowsocks-csharp/Encryption/RNG.cs
index cd6c49f3..276a9b1c 100644
--- a/shadowsocks-csharp/Encryption/RNG.cs
+++ b/shadowsocks-csharp/Encryption/RNG.cs
@@ -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 span)
{
- _rng?.Dispose();
- _rng = null;
+ _rng.GetBytes(span);
}
- public static void Reload()
+ public static Span GetSpan(int length)
{
- Close();
- Init();
+ Span 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);
diff --git a/test/CryptographyTest.cs b/test/CryptographyTest.cs
index 189449cf..ed194f3a 100644
--- a/test/CryptographyTest.cs
+++ b/test/CryptographyTest.cs
@@ -107,7 +107,6 @@ namespace Shadowsocks.Test
{
t.Join();
}
- RNG.Close();
Assert.IsFalse(encryptionFailed);
}