tabs ↹ over ␣ ␣ ␣ spaces

by Jiří {x2} Činčura

SHA1Managed with asynchronous ComputeHash

3 Jan 2014 2 mins .NET, C#, Cryptography, Multithreading/Parallelism/Asynchronous/Concurrency

Mixing IO-bound and CPU-bound operations in a single chunk of code isn’t always a base idea. Like computing hashes/checksums. You read the data from storage and you compute the hash. When all bytes are read, you’re done. Of course you can do it as a producer-consumer with a ring buffer, but mixing IO-bound and CPU-bound here is damn straightforward.

If you look at SHA1Managed class you’ll find ComputeHash method. Sadly it’s synchronous. Thus if you’ll point it to a huge file (i.e. FileStream) on a slow media you’ll be wasting resources while waiting for the result. But given the reading from stream is basically the only IO operation here it shouldn’t be hard to make it asynchronous. I thought.

I dug into the ComputeHash method and it’s pretty simple. The IO operation that happens in loop can be easily transformed to asynchronous one and hence having whole method ComputeHash asynchronous. Welcome ComputeHashAsync for SHA1Managed.

public async Task<byte[]> ComputeHashAsync(Stream inputStream)
    byte[] array = new byte[4096];
    int num;
        num = await inputStream.ReadAsync(array, 0, 4096).ConfigureAwait(false);
        if (num > 0)
            this.HashCore(array, 0, num);
    while (num > 0);
    this.HashValue = this.HashFinal();
    byte[] result = (byte[])this.HashValue.Clone();
    return result;

It’s what the ComputeHash is doing only using ReadAsync on a stream.

I hope the BCL team will provide asynchronous implementation out-of-the box in a foreseable future.

Profile Picture Jiří Činčura is .NET, C# and Firebird expert. He focuses on data and business layers, language constructs, parallelism, databases and performance. For almost two decades he contributes to open-source, i.e. FirebirdClient. He works as a senior software engineer for Microsoft. Frequent speaker and blogger at