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); }