Where Are The Constant Time Comparisons on .NET?

Written by William Roush on May 25, 2017 at 9:31 am

When cryptography is involved, a major rule is king: never write your own cryptography code. Well if this is the case why am I writing my own constant time comparisons in .NET?

StackOverflow took down my post as “Opinion based” so I’m posting it here so it doesn’t end up delisted on Google. I should probably do a write-up on why I struggle to contribute to StackOverflow at some point…

Constant-time comparisons are extremely important in cryptography code. A normal comparison will bail early from the comparison process if a mismatch is found, however this can leak information about how many bytes you got right before the comparison failed. If you’re guessing some kind of key (eg: comparing an API key), this can be catastrophic.

There are currently two open implementations for constant-time comparison methods, one in BouncyCastle and one in SecurityDriven.Inferno:

https://github.com/bcgit/bc-csharp/blob/1cdf80bc3f540b5531c158dacf4d67976b028fef/crypto/src/util/Arrays.cs -Org.BouncyCastle.Utilities.Arrays

https://github.com/sdrapkin/SecurityDriven.Inferno/blob/cfba069191247c8e24b096fd0f2dd899b5a25747/Utils.cs – SecurityDriven.Inferno.Utils.ConstantTimeEqual

http://securitydriven.net/inferno/ see: Constant-time Equality

My biggest hangup with SecurityDriven.Inferno is that ConstantTimeEqual will throw if the lengths aren’t the same. Throwing incurs a lot of overhead and disrupts program flow and I’d rather stay away from it. So generally your option is BouncyCastle (Edit: Lex pointed out below that BouncyCastle leaks the length of the byte array, so if that is a concern to you then Inferno is probably more of what you’re looking for).

 

6 thoughts on “Where Are The Constant Time Comparisons on .NET?

  1. Lex

    Unfortunately BouncyCastle’s implementation still leaks information about the length of the password, and there is no telling if the compiler today or sometime in the future might short-circuit their attempts anyway.

    At least Inferno is indicating that your input is invalid in some form, and preventing compiler interference.

    Reply
    1. William Roush Post author

      I really should have looked closer at this when I ported this question from StackOverflow…

      I’m going to reach out to the BouncyCastle team on fixing this.

      Reply
  2. Zack Warren

    It’s not a package, but this blog post goes through password hashing and comparison. The last code block at the bottom of the post is their implementation of a constant-time comparison. Thoughts?

    uint differences = (uint)originalHash.Length ^ (uint)testHash.Length;
    for (int position = 0; position < Math.Min(originalHash.Length,
    testHash.Length); position++)
    differences |= (uint)(originalHash[position] ^ testHash[position]);
    bool passwordMatches = (differences == 0);

    https://visualstudiomagazine.com/articles/2016/12/01/hashing-passwords.aspx?m=1

    Reply
    1. William Roush Post author

      This will still leak information as to the length of the hash, which may or may not be a deal breaker.

      Finding a suitable block of code generally isn’t too hard, but the point was more that it’s highly frowned upon to be doing this with *any* sort of crypto. Then found it funny that given all the basic crypto we get in .NET something as simple as constant-time comparisons was not available.

      Reply
  3. David LeBlanc

    You said: “This will still leak information as to the length of the hash, which may or may not be a deal breaker”

    You can never avoid leaking lengths. The length of the input data will get leaked by the number of rounds that the hash has to go. If you’re dealing with local CPU side channel attacks, there’s just too many ways to leak sizes. What you do want to do is to avoid leaking _values_, and there’s several approaches to that.

    Reply

Leave a Reply

Your email address will not be published.

Time limit is exhausted. Please reload CAPTCHA.