加密.NET,避免了定时攻击 [英] Cryptography .NET, Avoiding Timing Attack

查看:122
本文介绍了加密.NET,避免了定时攻击的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在浏览crackstation.net网站并在此代码,有人评论如下传来:




在与长度比较两​​个字节数组恒定的时间。使用这种比较方法,以便密码散列不能从使用的定时攻击的在线系统进行提取和然后攻击离线




 私有静态布尔SlowEquals(字节[]一,字节[] b)
{
UINT差异=(UINT)则为a.length ^(UINT)b.length个;
的for(int i = 0; I<则为a.length&放大器;&安培; I< b.length个;我++)
差异| =(UINT)(A [I] ^ B [I] );
的回报差异== 0;
}



任何人都可以请解释如何做这个功能的实际工作,为什么我们需要长度转换为无符号整数,这种方法是如何避免一个计时攻击?什么行差异| =(UINT)(A [I] ^ B [I]);


解决方案

设置差异根据是否有之间的差异 A b



它避免了总是通过两个<$的短全部走了计时攻击C $ C> A 和 b ,无论是否有不匹配比或没有更早。



差异| =(UINT)(A [I] ^(UINT)b〔I])取异或<一个字节的code> A 与乙。这将是0,如果两个字节是相同的,或非零如果它们是不同的。然后,它 s表示与差异



因此​​, ,差异将在一次迭代,如果差异,在该次迭代的输入之间发现被设置为非零。一旦差异给出在循环的任何迭代非零值时,将保留通过进一步的迭代中非零值



因此,最终的结果差异将非零如果有差异 A b 0仅当所有字节(和长度) A b 是相等的。



不同于典型的比较,然而,这将始终执行循环,直到在较短的所有字节两个输入已相比,在其他字节。一个典型的比较将有一个早期哪里出了循环将尽快错配被发现打破:

 布尔等于(字节[],BYTE b []){
如果(则为a.length()= b.length个())
返回假的!;

的for(int i = 0; I<则为a.length();我++)
如果(一个由[i] = B [I]!)
返回FALSE;
返回真;
}

通过此,基于消耗的返回<$ C $的时间量C>假,我们可以学习(至少近似)的之间的 A 匹配一个b个字节数。比方说,长的初始测试需要10纳秒,循环的每次迭代另需10纳秒。在此基础上,如果返回50 ns的假的,我们可以很快猜测,我们有​​正确的长度,前四个字节的 A b 匹配。



即使不知道时间的确切数额,我们仍然可以使用的时间差来确定正确的字符串。我们先从长度为1的串,并且在一个时间增加一个字节,直到我们看到在返回false所花费的时间的增加。然后我们通过在第一个字节的所有可能的值运行,直到我们看到另一个增加,表明它已执行的循环的另一次迭代。与同为连续字节,直到所有的字节比赛继续,我们得到的真正



原来是一回还是开出了的的时序攻击位 - 尽管我们不能轻易判断基于时序正确的字符串的内容,我们至少可以找到字符串的长度基于时序。因为它只比较最多两个串的短,我们可以与长度为1的串,然后2,则3,直到时间变​​得稳定开始,依此类推。只要时间增加我们提出字符串超过正确的字符串短。当我们给它更长的字符串,但时间保持不变,我们知道我们的字符串比正确的字符串长。字符串的正确长度将是最短的一个需要的最长持续时间来检验。



这是否是有用与否视情况而定,但它清楚地泄露一些信息, 而不管。对于真正的最大的安全性,我们可能要随机垃圾追加到真正的字符串的结尾,使其用户的输入的长度,所以时间保持正比于输入的长度,无论它是否更短,等于或大于正确的字符串长。


I was browsing crackstation.net website and came across this code which was commented as following:

Compares two byte arrays in length-constant time. This comparison method is used so that password hashes cannot be extracted from on-line systems using a timing attack and then attacked off-line.

 private static bool SlowEquals(byte[] a, byte[] b)
    {
        uint diff = (uint)a.Length ^ (uint)b.Length;
        for (int i = 0; i < a.Length && i < b.Length; i++)
            diff |= (uint)(a[i] ^ b[i]);
        return diff == 0;
    }

Can anyone please explain how does this function actual works, why do we need to convert the length to an unsigned integer and how this method avoids a timing attack? What does the line diff |= (uint)(a[i] ^ b[i]); do?

解决方案

This sets diff based on whether there's a difference between a and b.

It avoids a timing attack by always walking through the entirety of the shorter of the two of a and b, regardless of whether there's a mismatch sooner than that or not.

The diff |= (uint)(a[i] ^ (uint)b[i]) takes the exclusive-or of a byte of a with a corresponding byte of b. That will be 0 if the two bytes are the same, or non-zero if they're different. It then ors that with diff.

Therefore, diff will be set to non-zero in an iteration if a difference was found between the inputs in that iteration. Once diff is given a non-zero value at any iteration of the loop, it will retain the non-zero value through further iterations.

Therefore, the final result in diff will be non-zero if any difference is found between corresponding bytes of a and b, and 0 only if all bytes (and the lengths) of a and b are equal.

Unlike a typical comparison, however, this will always execute the loop until all the bytes in the shorter of the two inputs have been compared to bytes in the other. A typical comparison would have an early-out where the loop would be broken as soon as a mismatch was found:

bool equal(byte a[], byte b[]) { 
    if (a.length() != b.length())
        return false;

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

With this, based on the amount of time consumed to return false, we can learn (at least an approximation of) the number of bytes that matched between a and b. Let's say the initial test of length takes 10 ns, and each iteration of the loop takes another 10 ns. Based on that, if it returns false in 50 ns, we can quickly guess that we have the right length, and the first four bytes of a and b match.

Even without knowing the exact amounts of time, we can still use the timing differences to determine the correct string. We start with a string of length 1, and increase that one byte at a time until we see an increase in the time taken to return false. Then we run through all the possible values in the first byte until we see another increase, indicating that it has executed another iteration of the loop. Continue with the same for successive bytes until all bytes match and we get a return of true.

The original is still open to a little bit of a timing attack -- although we can't easily determine the contents of the correct string based on timing, we can at least find the string length based on timing. Since it only compares up to the shorter of the two strings, we can start with a string of length 1, then 2, then 3, and so on until the time becomes stable. As long as the time is increasing our proposed string is shorter than the correct string. When we give it longer strings, but the time remains constant, we know our string is longer than the correct string. The correct length of string will be the shortest one that takes that maximum duration to test.

Whether this is useful or not depends on the situation, but it's clearly leaking some information, regardless. For truly maximum security, we'd probably want to append random garbage to the end of the real string to make it the length of the user's input, so the time stays proportional to the length of the input, regardless of whether it's shorter, equal to, or longer than the correct string.

这篇关于加密.NET,避免了定时攻击的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆