HMACSHA1.ComputeHash () thread safety issue

I ask myself if it would be dangerous to use the asp.net page code to use a static (Shared) variable that contains an instance of HMACSHA1. the problem is that the same instance of HMACSHA1 will be used by all asp.net workflow threads when processing multiple simultaneous requests on the same asp.net page. all (HMACSHA1) instances and ComputeHash () are method variables that are used / modified by ComputeHash () will be shared (= can be changed) by all threads ?! is this assumption true? as a result, the return value of ComputeHash will not be guaranteed to be correct?!?! thus, I am not allowed to use a static / Shared HMACSHA1 instance on top of all asp.net threads.

I'm just wondering what you think about this issue.

the only solution for this would be sth as a critical path, etc. in the ComputeHash () method. but it is "out of our reach."

Regards, Kris

+4
source share
4 answers

Hash algorithms are deterministic, they must return the same hash for a given input every time.

As long as you use the same key every time, then there is no need to make them static. However, if you create an instance of HMACSHA1 without a constructor without parameters, it generates a random key. You must take a random value from the KeyValue property and store it with a hash.

It is definitely dangerous to use a static instance. If Thread1 sets the value to be calculated, and then Thread2 sets the value before Thread1 calls ComputerHash (), then Thread1 will receive a hash of the value of Thread2. The same thing will happen if any thread sets the key.

+4
source

I received an unknown cryptographic exception from SHA256Cng.ComputeHash when performing 8 or 16 parallel tasks that, among other things, performed hash calculations on a quad core HT processor.

Adding semantic semantics around ComputeHash solved the problem - therefore, it seems that at least the SHA256Cng version is not thread safe.

+7
source

It is worth knowing that KeyedHashAlgorithm.ComputeHash() not thread safe because it gives a non-deterministic result for the same KeyedHashAlgorithm.Key .

In my case, I want to cache KeyedHashAlgorithm, since my KeyedHashAlgorithm.Key always the same to authenticate from the client side. I understand that ComputeHash() not consistent, maybe it caches an internal variable in an instance of KeyedHashAlgorithm . I have to cache the instance on a ThreadStatic or ThreadLocal thread. This is a test:

Static KeyedHashAlgorithm gives inconsistent result:

 var kha = KeyedHashAlgorithm.Create("HMACSHA256"); kha.Key = Encoding.UTF8.GetBytes("key"); Action comp = () => { var computed = kha.ComputeHash(Encoding.UTF8.GetBytes("message")); Console.WriteLine(Convert.ToBase64String(computed)); }; Parallel.Invoke(comp, comp, comp, comp, comp, comp, comp, comp); 

Compared to KeyedHashAlgorithm for a stream:

 ThreadLocal<KeyedHashAlgorithm> tl= new ThreadLocal<KeyedHashAlgorithm>(() => { var kha = KeyedHashAlgorithm.Create("HMACSHA256"); kha.Key = Encoding.UTF8.GetBytes("key"); return kha; }); Action comp = () => { var computed = tl.Value.ComputeHash(Encoding.UTF8.GetBytes("message")); Console.WriteLine(Convert.ToBase64String(computed)); }; Parallel.Invoke(comp, comp, comp, comp, comp, comp, comp, comp); 

This code can be used to test other functions for the result of "thread safety". Hope this helps others.

+2
source

If you want thread safety without blocking, you can use the ThreadStatic attribute to create a unique instance for each thread, for example:

 [ThreadStatic] private static HMACSHA1 _hmacSha1; public static HMACSHA1 HmacSha1 { get { if (_hmacSha1 == null) { // this will happen once on each thread _hmacSha1 = new HMACSHA1(GetKeyBytes()); } return _hmacSha1; } } 

Now two side notes:

  • Access to the stream field takes significantly longer than access to a regular static field. Thus, the streaming-static version may or may not be better for you.

  • If you do this once on the query page, the difference will be so small that it does not matter which approach you choose. If you do this in a very narrow loop or the code in the lock section takes a lot of time, the choice may be important.

+1
source

All Articles