Ответ 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
, который проверяет, прошел ли массив байтов подписи, сравнивая его с некоторым внутренним байтовым массивом. До исправления, измеряя время работы этого метода, вы можете попытаться создать массив байтов, который пройдет сравнение (чем дольше этот метод будет выполняться, тем больше префикс из двух массивов равен).