Функция MessageDigest.isEqual используется в Java

У меня есть два вопроса, которые я не понимаю. Пожалуйста, помогите мне взглянуть. Спасибо.

  • Что такое функция MessageDigest.isEqual в Java?

  • Объясните, почему в некоторых версиях, предшествующих Java SE 6 Update 17, он был уязвим для временной атаки.

Ответ 1

Рассматривая реализацию Java SE 6 Update 10, мы видим:

public static boolean isEqual(byte digesta[], byte digestb[]) {

    if (digesta.length != digestb.length)
        return false;

    for (int i = 0; i < digesta.length; i++) {
        if (digesta[i] != digestb[i]) {
            return false;
        }
    }
    return true;
}

Пока после исправления мы видим:

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

Старая реализация выглядит более эффективной, так как она возвращает false, когда найден первый неравный байт, но я предполагаю, что он был заменен, потому что он может позволить вызывающему пользователю проверить, насколько похожи два байта ввода массивы друг к другу основаны на времени выполнения метода.

Новая реализация всегда имеет одинаковое время работы (для массивов с одинаковой длиной), так как она выполняет итерацию по всем массивам (даже если массивы отличаются самым первым байтом).

Я искал, где этот метод вызывается. Одним из примеров является engineVerify(byte[] signature) в классе com.sun.org.apache.xml.internal.security.algorithms.implementations.IntegrityHmac, который проверяет, прошел ли массив байтов подписи, сравнивая его с некоторым внутренним байтовым массивом. До исправления, измеряя время работы этого метода, вы можете попытаться создать массив байтов, который пройдет сравнение (чем дольше этот метод будет выполняться, тем больше префикс из двух массивов равен).

Ответ 2

обратитесь к ссылке на веб-страницу ниже: http://codahale.com/a-lesson-in-timing-attacks/

Я могу выбрать, какое сообщение я хочу аутентифицировать - скажем, файл cookie сеанса с определенным идентификатором пользователя - и затем рассчитать 256 возможных значений:

0000000000000000000000000000000000000000
0100000000000000000000000000000000000000
0200000000000000000000000000000000000000
... snip 250 ...
FD00000000000000000000000000000000000000
FE00000000000000000000000000000000000000
FF00000000000000000000000000000000000000

Я перебираю каждое из этих значений, пока не найду одно - A100000000000000000000000000000000000000 - которое на долю миллисекунды дольше остальных. Теперь я знаю, что первым байтом HMAC для этого сообщения является A1. Повторите процесс для оставшихся 19 байтов, и я внезапно вошел как вы.