Sunday, June 28, 2026

Unexpected usefulness of the MessageDigest::isEqual method

How one would compare two Strings for equality in Java? There are a few options that come to mind, String::equals or Objects::equals would probably be among those. But for certain, not MessageDigest::isEqual, not even close.

So what gives? No doubts, String::equals is very efficient and returns result as soon as possible. In majority of cases, this is the desired behavior. But what if you compare secrets or alike? For example, tokens, API keys, etc. Not a big deal, right? It turns out it is, your code might be susceptible to so called timing attacks. The gist of it is that comparing two String values is the function of a) their sizes b) how many matching characters they have consequently. The attacker could apply brute force tactics and figure out what the size of the expected secret should be and then, with some patience, guess the characters. All that just by capturing how much time the comparison takes.

How MessageDigest::isEqual helps, you may ask? It actually examines all the bytes of the first argument, as such the calculation time depends only on its length and it does not depend on the length of the second argument (nor the contents of both).

So next time you see the snippet like this

MessageDigest.isEqual(
    token1.getBytes(StandardCharsets.UTF_8), 
    token2.getBytes(StandardCharsets.UTF_8));

where there is seemingly nothing going on related to message digests, you know why.

I πŸ‡ΊπŸ‡¦ stand πŸ‡ΊπŸ‡¦ with πŸ‡ΊπŸ‡¦ Ukraine.

No comments: