diff --git a/shadowsocks-csharp/Controller/ShadowsocksController.cs b/shadowsocks-csharp/Controller/ShadowsocksController.cs
index 6340213a..a50ed720 100644
--- a/shadowsocks-csharp/Controller/ShadowsocksController.cs
+++ b/shadowsocks-csharp/Controller/ShadowsocksController.cs
@@ -272,6 +272,7 @@ namespace Shadowsocks.Controller
{
SystemProxy.Update(_config, true);
}
+ Encryption.RNG.Close();
}
public void TouchPACFile()
@@ -413,6 +414,7 @@ namespace Shadowsocks.Controller
protected void Reload()
{
+ Encryption.RNG.Reload();
// some logic in configuration updated the config when saving, we need to read it again
_config = Configuration.Load();
StatisticsConfiguration = StatisticsStrategyConfiguration.Load();
diff --git a/shadowsocks-csharp/Encryption/IVEncryptor.cs b/shadowsocks-csharp/Encryption/IVEncryptor.cs
index f6781a29..8a9d88d2 100755
--- a/shadowsocks-csharp/Encryption/IVEncryptor.cs
+++ b/shadowsocks-csharp/Encryption/IVEncryptor.cs
@@ -1,8 +1,6 @@
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
-using System.Linq;
-using System.Security.Cryptography;
using System.Text;
using System.Net;
@@ -237,10 +235,7 @@ namespace Shadowsocks.Encryption
protected static void randBytes(byte[] buf, int length)
{
- using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
- {
- rng.GetBytes(buf, 0, length);
- }
+ RNG.GetBytes(buf, length);
}
public override void Encrypt(byte[] buf, int length, byte[] outbuf, out int outlength)
diff --git a/shadowsocks-csharp/Encryption/RNG.cs b/shadowsocks-csharp/Encryption/RNG.cs
new file mode 100644
index 00000000..cb783144
--- /dev/null
+++ b/shadowsocks-csharp/Encryption/RNG.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Security.Cryptography;
+
+namespace Shadowsocks.Encryption
+{
+ public static class RNG
+ {
+ private static RNGCryptoServiceProvider _rng = null;
+
+ public static void Init()
+ {
+ if (_rng == null)
+ _rng = new RNGCryptoServiceProvider();
+ }
+
+ public static void Close()
+ {
+ if (_rng == null) return;
+ _rng.Dispose();
+ _rng = null;
+ }
+
+ public static void Reload()
+ {
+ Close();
+ Init();
+ }
+
+ public static void GetBytes(byte[] buf, int len)
+ {
+ try
+ {
+ _rng.GetBytes(buf, 0, len);
+ }
+ catch (Exception)
+ {
+ // the backup way
+ byte[] tmp = new byte[len];
+ _rng.GetBytes(tmp);
+ Buffer.BlockCopy(tmp, 0, buf, 0, len);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/shadowsocks-csharp/Program.cs b/shadowsocks-csharp/Program.cs
index 198fbd5c..0f4e95a9 100755
--- a/shadowsocks-csharp/Program.cs
+++ b/shadowsocks-csharp/Program.cs
@@ -92,9 +92,10 @@ namespace Shadowsocks
{
if (Interlocked.Increment(ref exited) == 1)
{
- Logging.Error(e.ExceptionObject?.ToString());
+ string errMsg = e.ExceptionObject.ToString();
+ Logging.Error(errMsg);
MessageBox.Show(
- $"{I18N.GetString("Unexpected error, shadowsocks will exit. Please report to")} https://github.com/shadowsocks/shadowsocks-windows/issues {Environment.NewLine}{e.ExceptionObject?.ToString()}",
+ $"{I18N.GetString("Unexpected error, shadowsocks will exit. Please report to")} https://github.com/shadowsocks/shadowsocks-windows/issues {Environment.NewLine}{errMsg}",
"Shadowsocks non-UI Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
Application.Exit();
}
@@ -102,12 +103,15 @@ namespace Shadowsocks
private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
- string errorMsg = $"Exception Type: {e.Exception.GetType().Name}{Environment.NewLine}Stack Trace:{Environment.NewLine}{e.Exception.StackTrace}";
- Logging.Error(errorMsg);
- MessageBox.Show(
- $"{I18N.GetString("Unexpected error, shadowsocks will exit. Please report to")} https://github.com/shadowsocks/shadowsocks-windows/issues {Environment.NewLine}{errorMsg}",
- "Shadowsocks UI Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
- Application.Exit();
+ if (Interlocked.Increment(ref exited) == 1)
+ {
+ string errorMsg = $"Exception Detail: {Environment.NewLine}{e.Exception}";
+ Logging.Error(errorMsg);
+ MessageBox.Show(
+ $"{I18N.GetString("Unexpected error, shadowsocks will exit. Please report to")} https://github.com/shadowsocks/shadowsocks-windows/issues {Environment.NewLine}{errorMsg}",
+ "Shadowsocks UI Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
+ Application.Exit();
+ }
}
private static void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
@@ -168,7 +172,10 @@ namespace Shadowsocks
private static void Application_ApplicationExit(object sender, EventArgs e)
{
+ // detach static event handlers
+ Application.ApplicationExit -= Application_ApplicationExit;
SystemEvents.PowerModeChanged -= SystemEvents_PowerModeChanged;
+ Application.ThreadException -= Application_ThreadException;
HotKeys.Destroy();
if (_controller != null)
{
diff --git a/shadowsocks-csharp/shadowsocks-csharp.csproj b/shadowsocks-csharp/shadowsocks-csharp.csproj
index 77460a90..26ea4fd2 100644
--- a/shadowsocks-csharp/shadowsocks-csharp.csproj
+++ b/shadowsocks-csharp/shadowsocks-csharp.csproj
@@ -183,6 +183,7 @@
+
diff --git a/test/UnitTest.cs b/test/UnitTest.cs
index 6364dba2..539140d6 100755
--- a/test/UnitTest.cs
+++ b/test/UnitTest.cs
@@ -68,6 +68,7 @@ namespace test
private void RunEncryptionRound(IEncryptor encryptor, IEncryptor decryptor)
{
+ RNG.Reload();
byte[] plain = new byte[16384];
byte[] cipher = new byte[plain.Length + 16 + IVEncryptor.ONETIMEAUTH_BYTES + IVEncryptor.AUTH_BYTES];
byte[] plain2 = new byte[plain.Length + 16];
@@ -117,6 +118,7 @@ namespace test
{
t.Join();
}
+ RNG.Close();
Assert.IsFalse(encryptionFailed);
}
@@ -156,6 +158,7 @@ namespace test
{
t.Join();
}
+ RNG.Close();
Assert.IsFalse(encryptionFailed);
}
@@ -196,6 +199,7 @@ namespace test
{
t.Join();
}
+ RNG.Close();
Assert.IsFalse(encryptionFailed);
}