为什么比较两个相同的字节数组需要不同的时间来完成?

时间:2014-07-14 16:15:32

标签: c# cryptography md5

我正在尝试计算哈希值,然后比较它们来模拟c#中的时间攻击 这是我为此目的使用的代码:

private void btnHash_Click(object sender, EventArgs e)
{
    MD5 md5 = new MD5CryptoServiceProvider();
    var firstHashByte = md5.ComputeHash(ASCIIEncoding.ASCII.GetBytes(txtBoxText.Text));
    txtBoxHash.Text = Convert.ToBase64String(firstHashByte);

    var secondHashByte = md5.ComputeHash(ASCIIEncoding.ASCII.GetBytes(txtBoxSecondText.Text));
    txtBoxHashtwo.Text = Convert.ToBase64String(secondHashByte);

    Stopwatch stopwatch = new Stopwatch();
    stopwatch.Start();

    NormalEquality(firstHashByte, secondHashByte);
    //SlowEquals(firstHashByte, secondHashByte);

    stopwatch.Stop();
    lstBoxTimeSpan.Items.Add(stopwatch.ElapsedTicks.ToString());
}


private static void NormalEquality(byte[] hashByte, byte[] hashByte2)
{
    bool bEqual = false;
    if (hashByte.Length == hashByte2.Length)
    {
        int i = 0;
        while ((i < hashByte2.Length) && (hashByte2[i] == hashByte[i]))
        {
            i += 1;
        }
        if (i == hashByte2.Length)
        {
            bEqual = true;
        }
    }
}

每次我尝试运行它时,即使是相同的哈希,我也会得到不同的时间! 为什么会这样? 我还注意到使用以下方法,据说为相同和不同的哈希值生成一个常量时间,并且它就像前一个方法一样,为任何事物生成不同的时间! (相同的哈希或不同的哈希!)

    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;
    }

为什么会这样?任何的想法?

(顺便提一下:as C#string == compare在内部进行这种数组比较还是只是另一个故事? 因为每当我试图在Base64版本的哈希上使用==字符串时,我得到了0次,无论是相同的还是不同的哈希 我做了:

stopwatch.Start();
if ( firstHashString == secondHashString);
stopwatch.Stop();

2 个答案:

答案 0 :(得分:1)

你会得到不同的时间因为秒表分辨率太低而无法测量如此少的代码。虽然秒表的分辨率非常高,但CPU仍然有时间在秒表的每个刻度之间运行数千条指令。

在执行该方法期间,秒表只会进行几次滴答,因此产生的时间会有很大差异。

如果您运行该方法一千次或一百万次,您就可以通过足够小的时间变化进行测量。

答案 1 :(得分:1)

有许多因素影响方法调用的时间,计算机是一个庞大的系统,最微小的变化可能成为众所周知的蝴蝶。坦率地说,微小的时间差异无需担心,重要的是它是否总能产生正确的结果。

尝试一件事可能是多次重复方法调用,例如。一百万次或一千万次,并计时所有的呼叫,例如。

stopwatch.Start();
for (int i=0; i<1000000; i++) {
    // call test here
}
stopwatch.Stop();

如果你重复上述几次,时间应该非常接近。