Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/321.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
我如何在Java中实现一个字符串比较,无论它们是否匹配,或者在哪里发生不匹配(如果有的话),都需要相同的时间?_Java_String - Fatal编程技术网

我如何在Java中实现一个字符串比较,无论它们是否匹配,或者在哪里发生不匹配(如果有的话),都需要相同的时间?

我如何在Java中实现一个字符串比较,无论它们是否匹配,或者在哪里发生不匹配(如果有的话),都需要相同的时间?,java,string,Java,String,我想实现一个String比较函数,根据匹配的字符数或第一个不匹配的位置,它不会占用不同的时间。我想一定有一个图书馆在那里某处提供了这个,但我无法通过快速搜索找到它 到目前为止,我得到的最好方法是对每个字符的XOR求和,并返回和是否为0。然而,我很确定这在Unicode中不会很好地工作。我还模糊地担心HotSpot会进行一些优化,从而改变我的常数时间属性,但我想不出一个具体的优化可以在我的脑海中实现这一点 谢谢 更新:对不起,我不相信我是清楚的。我不是在寻找O(1),我是在寻找不会泄露定时信息的东

我想实现一个
String
比较函数,根据匹配的字符数或第一个不匹配的位置,它不会占用不同的时间。我想一定有一个图书馆在那里某处提供了这个,但我无法通过快速搜索找到它

到目前为止,我得到的最好方法是对每个字符的XOR求和,并返回和是否为
0
。然而,我很确定这在Unicode中不会很好地工作。我还模糊地担心HotSpot会进行一些优化,从而改变我的常数时间属性,但我想不出一个具体的优化可以在我的脑海中实现这一点

谢谢


更新:对不起,我不相信我是清楚的。我不是在寻找
O(1)
,我是在寻找不会泄露定时信息的东西。这将用于比较散列密码值,如果比较所用的时间与第一次不匹配发生的位置不同,则会将信息泄漏给攻击者。

我认为有两种可能不会及时泄漏密码相关信息:

1/用已知的固定字符(如
a
)将密码字符串和候选字符串填充到1K。然后运行以下命令(伪代码):

这样,无论在哪里匹配,您总是使用相同数量的循环来进行比较

没有必要乱搞
xor
,因为您仍然可以进行简单的比较,但不必提前退出循环

如果发现不匹配,只需将匹配标志设置为false,然后继续。一旦循环退出(无论密码和候选密码的大小或内容如何,都会占用相同的时间),然后检查它是否匹配

2/只需在比较结束时添加一个大的(相对于正常比较时间)但稍微随机的延迟。例如,0.9到1.1秒之间的随机值。比较所花费的时间应该被延迟所淹没,并且随机性应该完全掩盖任何信息泄漏(当然,除非您的随机性算法泄漏信息)

这还具有防止暴力攻击的额外优势,因为密码检查至少需要一秒钟

我想实现一个字符串比较函数,它不需要 不同的时间量取决于 匹配或第一个不匹配的位置。我想一定有什么问题 图书馆提供了这个,但我无法 通过快速搜索找到它

到目前为止,我得到的最好的主意是对每个字符的异或求和

你看到矛盾了吗

更新: 对于更新的,因此是不同的问题:

您能否获得一次信息,根据两个字符串的长度,以恒定的数量和时间比较两个字符串需要多少时间

a + b*s(1).length + c*s(2).length + d*f(s(1), s(2))? 
字符串1和2是否有字符的上限

如果时间为,则取决于机器的系数,例如,您期望的最长字符串为0.01ms。您测量对字符串进行编码的时间,并保持空闲状态,直到达到该时间,可能是时间的+rand(10%)的一个因素


如果输入长度不受限制,您可以根据您的安全需求和机器速度,以适合99%、99.9%或99.99%典型输入的方式计算计时。如果程序与用户交互,通常会经历高达0.2秒的延迟作为即时反应,因此如果代码休眠0.19994s,而实际计算时间为0.00006s,则不会打扰用户。

如果插入字符串,则可以进行常量时间字符串比较。然后您可以将它们与==运算符进行比较,从而进行恒定时间相等检查


阅读更多详细信息

对于任何匹配长度的字符串,这应该需要大约相同的时间。这是常数时间,有一个大常数

public static boolean areEqualConstantTime(String a, String b) {
    if ( a.length != b.length ) {
        return false;
    }

    boolean equal = true;
    for ( long i = 0; i < (Long)Integer.MAX_INT; i++ ) {
        if ( a.charAt((int)(i % aChars.length)) != b.charAt((int)(i % bChars.length))) {
            equal = false;
        }
    }
    return equal;
}
公共静态布尔值areEqualConstantTime(字符串a、字符串b){
如果(a.长度!=b.长度){
返回false;
}
布尔等于真;
对于(长i=0;i<(长)整数.MAX_INT;i++){
如果(a.charAt((int)(i%aChars.length))!=b.charAt((int)(i%bChars.length))){
相等=错误;
}
}
回报相等;
}
编辑 哇,如果你只是想避免泄露时间信息的话,这个滑稽的回答就很贴切了!我们可以从这样一个天真的方法开始:

public static boolean arePasswordsEqual(String a, String b) {
    boolean equal = true;
    if ( a.length != b.length ) {
       equal = false;
    }

    for ( int i = 0; i < MAX_PASSWORD_LENGTH; i++ ) {
        if ( a.charAt(i%a.length()) != b.charAt(i%b.length()) ) {
            equal = false;
        }
    }
    return equal;
 }
公共静态布尔值arePasswordsEqual(字符串a、字符串b){
布尔等于真;
如果(a.长度!=b.长度){
相等=错误;
}
对于(int i=0;i

我们需要
MAX\u PASSWORD\u LENGTH
常量,因为我们不能简单地使用两个输入长度的MAX或min,因为这也会泄漏定时信息。攻击者可以从一个非常小的猜测开始,并查看函数需要多长时间。当函数时间稳定时,他会知道自己的密码具有正确的长度,这消除了他需要尝试的大部分值范围。

通常的解决方案是设置计时器,直到计时器过期后才返回结果


比较字符串或散列所用的时间并不重要,只需将超时值设置得足够大即可。

以下代码是在Java中执行恒定时间
字节[]
比较的一种常见方法,以避免通过所用时间泄露密码信息:

public static boolean isEqual(byte[] a, byte[] b) {
    if (a.length != b.length) {
        return false;
    }

    int result = 0;
    for (int i = 0; i < a.length; i++) {
      result |= a[i] ^ b[i];
    }
    return result == 0;
}
publicstaticbooleaniesequal(字节[]a,字节[]b){
如果(a.长度!=b.长度){
返回false;
public static boolean isEqual(byte[] a, byte[] b) {
    if (a.length != b.length) {
        return false;
    }

    int result = 0;
    for (int i = 0; i < a.length; i++) {
      result |= a[i] ^ b[i];
    }
    return result == 0;
}