Why does SHA1.ComputeHash fail at high load with many threads?

I see a problem with some code that I support. The code below has a private static SHA1 member (which is IDisposable , but since it is static , it should never terminate). However, under stress, this code raises an exception that assumes that it was closed:

 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) 

This code:

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

My question can obviously cause this problem. Can the SHA1.Create call fail (how many cryptographic resources are available)? Could this be caused by a decrease in the approximation?

Any other theories?

+7
c # sha finalizer stress-testing
source share
1 answer

As documentation for the HashAlgorithm base class

Any public static (Shared in Visual Basic) members of this type are thread safe. Any instance members do not guarantee thread safety.

You should not share these classes between threads in which different threads try and call ComputeHash in the same instance at the same time.

EDIT This is what causes your error. The stress test below gives a lot of errors due to several threads causing ComputeHash on the same instance of the hashing algorithm. Your mistake is one of them.

In particular, I saw the following errors in this stress test:

  • System.Security.Cryptography.CryptographicException: Hash is not valid for use in the specified state.
  • System.ObjectDisposedException: secure handle closed

Sample test test code:

 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(); 
+23
source share

All Articles