Asynchronous SHA256 Hashing

I have the following method:

public static string Sha256Hash(string input) { if(String.IsNullOrEmpty(input)) return String.Empty; using(HashAlgorithm algorithm = new SHA256CryptoServiceProvider()) { byte[] inputBytes = Encoding.UTF8.GetBytes(input); byte[] hashBytes = algorithm.ComputeHash(inputBytes); return BitConverter.ToString(hashBytes).Replace("-", String.Empty); } } 

Is there any way to make it asynchronous? I was hoping to use the async keywords and wait , but the HashAlgorithm class does not provide asynchronous support for this.

Another approach was to encapsulate all the logic in:

 public static async string Sha256Hash(string input) { return await Task.Run(() => { //Hashing here... }); } 

But this does not seem clean, and I'm not sure if it is the right (or efficient) way to perform the operation asynchronously.

What can I do for this?

+5
source share
3 answers

The work you do is inherently synchronous work with a link to the CPU. It is not inherently asynchronous as something like a network IO. If you want to start some work with the synchronous processor in another thread and wait for completion asynchronously, then Task.Run indeed a suitable tool for this, assuming that the operation is long enough to execute it asynchronously.

However, there really is no reason to open the asynchronous wrapper according to your synchronous method. As a rule, it makes sense to simply expose the method synchronously, and if a particular caller needs to run it asynchronously in another thread, he can use Task.Run to explicitly indicate the need for this particular call.

+6
source

The overhead of doing this asynchronous (using Task.Run) is likely to be higher than just running it synchronously.

The asynchronous interface is unavailable because it is a processor-bound operation. You can make it asynchronous (using Task.Run) as you pointed out, but I would recommend it against.

+1
source

As other responders said, hashing is processor related activity, so it does not have Async methods that you can call. You can, however, make your hash method asynchronous asynchronously read a block of files by block , and then hash the bytes that you read from the file. Hashing will be done synchronously, but reading will be asynchronous, and therefore your whole method will be asynchronous.

Here is a sample code to achieve the goal I just described.

 public static async Threading.Tasks.Task<string> GetHashAsync<T>(this Stream stream) where T : HashAlgorithm, new() { StringBuilder sb; using (var algo = new T()) { var buffer = new byte[8192]; int read; // compute the hash on 8KiB blocks while ((read = await stream.ReadAsync(buffer, 0, buffer.Length)) == buffer.Length) algo.TransformBlock(buffer, 0, read, buffer, 0); algo.TransformFinalBlock(buffer, 0, read); // build the hash string sb = new StringBuilder(algo.HashSize / 4); foreach (var b in algo.Hash) sb.AppendFormat("{0:x2}", b); } return sb?.ToString(); } 

Function can be called as such

 using (var stream = System.IO.File.OpenRead(@"C:\path\to\file.txt")) string sha256 = await stream.GetHashAsync<SHA256CryptoServiceProvider>(); 

Of course, you could also call the method with other hashing algorithms such as SHA1CryptoServiceProvider or SHA512CryptoServiceProvider as a type parameter.

Similarly, with some changes, you can also get it for hashing a string, as this is specific to your case.

+1
source

Source: https://habr.com/ru/post/1207686/


All Articles