为什么 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;
而result
是0
。
我认为原因可能是只接受 ASCII 密码,或者 UTF 8(或其他字符集)被视为 ASCII 字符。
在 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;
而result
是0
。
我认为原因可能是只接受 ASCII 密码,或者 UTF 8(或其他字符集)被视为 ASCII 字符。