什么是双重 HMAC 验证及其工作原理?

What is double HMAC verification and how does it work?

来自Mega Security Whitepaper

The API does not store the unhashed Authentication Key sent by the user. It only stores the Hashed Authentication Key to prevent “pass-the-hash” attacks (wherein the scenario of a leaked database, an attacker would just pass the Hashed Authentication Key to get authenticated and carry out actions as the real user). The server always hashes the Authentication Key received from the client which prevents this attack vector.

If the Hashed Authentication Key does not match the result in the database, the API responds with a negative response to indicate failure. The API side avoids timing attacks here by using Double HMAC Verification (https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2011/february/double-hmac-verification/).

不幸的是,link 已死,google 搜索通常指向同一个 source。当需要原始密钥验证签名时,请您解释一下双重hmac验证是如何工作的?谢谢

URL 已被 Wayback Machine 存档,因此您仍然可以阅读完整的博客 post:http://web.archive.org/web/20160203044316/https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2011/february/double-hmac-verification/

post 包含演示如何执行双 HMAC 验证的 C# 代码片段。最后很简单,正如名称“double HMAC”表明它使用相同的 HMAC-key.

执行两次 HMAC
public void validateHMACSHA256(byte[]receivedHMAC, byte[]message, byte[]key) {
    HashAlgorithm hashAlgorithm = new HMACSHA256(key);

    // size and algorithm choice are not secret; no weakness in failing fast here.
    if (receivedHMAC.Length != hashAlgorithm.HashSize / 8) {
        Throw new CryptographicException("HMAC verification failure.");
    }
    byte[]calculatedHMAC = hashAlgorithm.ComputeHash(message);
    // Now we HMAC both values again before comparing to randomize byte order.
    // These two lines are all that is required to prevent many existing implementations
    // vulnerable to adaptive chosen ciphertext attacks using the timing side channel.
    receivedHMAC = hashAlgorithm.ComputeHash(receivedHMAC);
    calculatedHMAC = hashAlgorithm.ComputeHash(calculatedHMAC);

    for (int i = 0; i < calculatedHMAC.Length; i++) {
        if (receivedHMAC[i] != calculatedHMAC[i]) {
            throw new CryptographicException("HMAC verification failure.");
        }
    }
}