Technical Article => Programming => Java

Both Arrays.equals() and MessageDigest.isEqual() are used to compare the equality of two arrays. They can be interchangeably in many cases. However, they do have some differences which lead to different use cases in real applications.

One difference is that the arrays passed to MessageDigest.isEqual() cannot be null while it's ok for Arrays.equals().

The one major difference between these two methods is that Arrays.equals() is not time-constant while MessageDigest.isEqual() is time-constant. This means that when comparing two arrays, the arrays are compared byte by byte, Arrays.equals() will return immediately for the first byte which is not equal. MessageDigest.isEqual() will compare all bytes in the arrays no matter where the first byte is not equal.

The implementation of Arrays.equals() is :

public static boolean equals(byte[] a, byte[] a2) { if (a==a2) return true; if (a==null || a2==null) return false; int length = a.length; if (a2.length != length) return false; for (int i=0; i<length; i++) if (a[i] != a2[i]) return false; return true; }

From the for loop, Arrays.equals() is a fail fast method. If the first byte is not equal, it will return immediately. This usually means high efficiency but less security. Actually from the implementation, this method is designed for efficiency. They have a few checks to determine whether two arrays are equal quickly without actually comparing the content of the array.

The implementation of MessageDigest.isEqual() is :

public static boolean isEqual(byte[] digesta, byte[] digestb) { if (digesta.length != digestb.length) { return false; } int result = 0; // time-constant comparison for (int i = 0; i < digesta.length; i++) { result |= digesta[i] ^ digestb[i]; } return result == 0; }

From the for loop, the arrays are compared completely. This means high security but less efficiency.

In high security requirement systems, Arrays.equals() may be vulnerable to time constant attack. For example, if there is a hash or key comparison using Arrays.equals(), the attack can fake a hash or key and do the comparison with the actual hash or key. They can measure the time taken for Arrays.equals() to return to understand how many bytes matched the faked hash or key has. After hundreds or thousands of tries, they may reveal the actual hash and key. For details about how this attack works, you can read more at A Lesson In Timing Attacks (or, Don’t use MessageDigest.isEquals).

So when you decide to use method to compare two arrays, please consider carefully whether the application is security concerned or efficiency concerned. If efficiency is what you need, then go and use Arrays.equals(), but if you are developing a security product, then be cautious and keep using MessageDigest.isDigest().

Remember hackers are a group of people who "resort to every conceivable means; stop at nothing".