2014-10-27 57 views
7

我看到我維護的一些代碼存在問題。下面的代碼有一個private static SHA1成員(這是一個IDisposable,但因爲它是static,它永遠不會被最終確定)。然而,在壓力下這段代碼拋出表明它已經關閉了異常:爲什麼SHA1.ComputeHash在高負載下有很多線程會失敗?

Caught exception. Safe handle has been closed" 
Stack trace: Call stack where exception was thrown 
at System.Runtime.InteropServices.SafeHandle.DangerousAddRef(Boolean& success) 
at System.Security.Cryptography.Utils.HashData(SafeHashHandle hHash, Byte[] data, Int32 cbData, Int32 ibStart, Int32 cbSize) 
at System.Security.Cryptography.Utils.HashData(SafeHashHandle hHash, Byte[] data, Int32 ibStart, Int32 cbSize) 
at System.Security.Cryptography.HashAlgorithm.ComputeHash(Byte[] buffer) 

的代碼中的問題是:

internal class TokenCache 
{ 
    private static SHA1 _sha1 = SHA1.Create(); 

    private string ComputeHash(string password) 
    { 
     byte[] passwordBytes = UTF8Encoding.UTF8.GetBytes(password); 
     return UTF8Encoding.UTF8.GetString(_sha1.ComputeHash(passwordBytes)); 
    } 

我的問題是明顯,是什麼引發了這個問題。對SHA1.Create的調用是否可以無提示失敗(有多少加密資源可用)?這可能是由應用程序域名下降造成的嗎?

其他理論?

+0

這是什麼都與處置呢?另外,哪個「SHA1」類是那個? – 2014-10-27 16:51:27

+1

你確定類SHA1是線程安全嗎?當它失敗時你能夠獲取被哈希處理的密碼嗎? – Rob 2014-10-27 16:51:56

+0

@約翰桑德斯,對不起,你是對的。這與Dispose無關。我認爲System.Security.Cryptography.SHA1CryptoServiceProvider上的終結器可能以某種方式被觸發。 http://msdn.microsoft.com/en-us/library/e7hyyd4e(v=vs.110).aspx – MvdD 2014-10-27 16:53:50

回答

23

按照the documentationHashAlgorithm基類

Any public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe.

你不應該在那裏的線程不同的線程試圖在同一時間在同一個實例調用ComputeHash之間共享這些類。

編輯 這是什麼導致你的錯誤。下面的壓力測試會由於多個線程在同一個哈希算法實例中調用ComputeHash而產生各種錯誤。你的錯誤就是其中之一。

具體而言,我已經看到了這種應力測試如下錯誤:

  • System.Security.Cryptography.CryptographicException:哈希不適於在指定狀態下使用。
  • System.ObjectDisposedException:安全句柄已關閉

壓力測試的代碼示例:

const int threadCount = 2; 
var sha1 = SHA1.Create(); 
var b = new Barrier(threadCount); 
Action start =() => { 
        b.SignalAndWait(); 
        for (int i = 0; i < 10000; i++) 
        { 
         var pwd = Guid.NewGuid().ToString(); 
         var bytes = Encoding.UTF8.GetBytes(pwd); 
         sha1.ComputeHash(bytes); 
        } 
       }; 
var threads = Enumerable.Range(0, threadCount) 
         .Select(_ => new ThreadStart(start)) 
         .Select(x => new Thread(x)) 
         .ToList(); 
foreach (var t in threads) t.Start(); 
foreach (var t in threads) t.Join(); 
+0

顯着的事故,安全處理看起來不錯。但不可否認,很好的答案。 – 2014-10-27 17:25:55

+1

@HansPassant。謝謝。我猜想它可能是'SHA1CryptoServiceProvider.Initialize'方法,它似乎做了一個非線程安全的'Dispose',然後在'_safeHashHandle'字段上重新創建。 – 2014-10-27 17:33:46

+0

hehe,bizarro,Initialize()在*計算散列之後調用*。必須是某種安全的東西。你說對了。 – 2014-10-27 17:42:44

相關問題