为什么 Spring Security 的 BCrypt 实现使用 no-early-return equals 方法?

Why Spring Security's BCrypt implementation uses a no-early-return equals method?

在 Spring Security 的 BCrypt 实现中,我遇到了以下方法 (source):

static boolean equalsNoEarlyReturn(String a, String b) {
  char[] caa = a.toCharArray();
  char[] cab = b.toCharArray();

  if (caa.length != cab.length) {
    return false;
  }

  byte ret = 0;
  for (int i = 0; i < caa.length; i++) {
    ret |= caa[i] ^ cab[i];
  }
  return ret == 0;
}

为什么使用这种 no-early-return equals 方法?它有什么好处:

static boolean equals(String a, String b) {
  char[] caa = a.toCharArray();
  char[] cab = b.toCharArray();

  if (caa.length != cab.length) {
    return false;
  }

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

甚至:

return a.equals(b)

?

是否出于安全考虑?

我认为这是出于安全目的,避免定时攻击。即使它与 BCrypt 并不真正相关,这样做也是一种很好的做法。 Here is an answer 更多信息

我不知道是不是真正的原因,但是在original article我发现

the key argument is a secret encryption key, which can be a user-chosen password of up to 56 bytes (including a terminating zero byte when the key is an ASCII string).

因为byte是8位而char是16位,所以ret |= caa[i] ^ cab[i];只用来比较最低有效位。

我尝试执行

final char a = '\uff11';
final char b = '\u1111';

byte result = 0;
result |= a ^ b;

result0

我认为原因可能是只接受 ASCII 密码,或者 UTF 8(或其他字符集)被视为 ASCII 字符。