Arrays.equals() vs MessageDigest.isEqual()

  Pi Ke        2015-05-14 22:03:29       20,251        0          English  简体中文  ภาษาไทย  Tiếng Việt 

同时使用Arrays.equals()MessageDigest.isEqual() 来比较两个数组的相等性。在许多情况下,它们可以互换使用。但是,它们确实有一些区别,导致在实际应用中使用场景不同。

一个区别是,传递给MessageDigest.isEqual()的数组不能为null,而Arrays.equals()则可以。

这两种方法之间的一个主要区别是,Arrays.equals()不是恒定时间算法,而MessageDigest.isEqual()是恒定时间算法。这意味着,当比较两个数组时,数组逐字节比较,Arrays.equals()将立即返回第一个不相等的字节。MessageDigest.isEqual()将比较数组中的所有字节,无论第一个不相等的字节在哪里。

Arrays.equals()的实现是:

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;
}

从for循环可以看出,Arrays.equals()是一种快速失败方法。如果第一个字节不相等,它将立即返回。这通常意味着效率高,但安全性低。实际上,从实现来看,此方法的设计是为了提高效率。它们进行了一些检查以快速确定两个数组是否相等,而无需实际比较数组的内容。

MessageDigest.isEqual()的实现是:

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;
}

从for循环可以看出,数组被完全比较。这意味着安全性高,但效率低。

在高安全要求的系统中,Arrays.equals()可能容易受到恒定时间攻击。例如,如果使用Arrays.equals()进行哈希或密钥比较,攻击者可以伪造哈希或密钥并与实际哈希或密钥进行比较。他们可以测量Arrays.equals()返回所需的时间,以了解有多少字节与伪造的哈希或密钥匹配。经过数百或数千次尝试后,他们可能会泄露实际的哈希和密钥。有关此攻击如何工作的详细信息,您可以阅读A Lesson In Timing Attacks (or, Don’t use MessageDigest.isEquals)

因此,当您决定使用哪种方法来比较两个数组时,请仔细考虑应用程序是关注安全性还是关注效率。如果需要效率,那么使用Arrays.equals();但是,如果您正在开发安全产品,那么请谨慎并继续使用MessageDigest.isDigest()。

记住,黑客是一群“无所不用其极;不择手段”的人。

ARRAYS.EQUAL()  MESSAGEDIGEST.ISEQUAL()  JAVA  SECURITY 

       

  RELATED


  0 COMMENT


No comment for this article.



  RANDOM FUN

Multithreading program written by newbie