MAC 用于检测您感兴趣的数据的更改,即解密的结果。所以你有以下选择:
- 要么您在明文数据上计算 HMAC(即在加密时加密之前,在解密时在解密之后);
- 或者您在加密数据本身上计算 HMAC(即在加密时加密之后,在解密时解密之前)。
在第二种情况下,您必须在 HMAC 输入中包含影响解密过程的所有内容,即不仅包括加密结果本身,还包括用于该加密的 IV,并且,如果整个协议支持算法敏捷性,您还应该输入加密算法的规范(否则,攻击者可能会更改消息的标头以将“AES-256”标签替换为“AES-128”标签,您会在不知不觉中解密错误的算法)。
对于安全性,第二种选择(加密然后MAC)更好;有关详细信息,请参阅crypto.SE 上的这个问题(总而言之,当 MAC 是在加密数据上计算时,它不会泄露有关明文数据的信息,并且由于在尝试解密之前对其进行了验证,因此可以防止选择的密文攻击)。SSL 使用 MAC-then-encrypt 并且它已成为许多问题的根源(所有“padding oracle 攻击”以及所谓的 BEAST 攻击都可以通过 encrypt-then-MAC 避免)。
至于密钥,理想情况下,加密密钥和 MAC 密钥应该从具有PRF的主密钥派生而来。简单来说:用 SHA-512散列你的主密钥K ;结果的前半部分将是加密密钥,后半部分将是 HMAC 的密钥。
但是,实际上,您应该使用EAX或GCM。他们正确地做所有事情并且(这是重要的一点)他们对 IV 选择的要求非常低:他们只需要一个不重复的 IV,因此可以使用一个简单的计数器,而手工 CTR 需要不重叠的 IV范围(一个均匀的 IV随机选择是正确的,但随机性是硬性要求)(CBC 更糟糕,它需要不可预测的随机性)。没有的唯一理由在新系统中使用 EAX 或 GCM(您不受向后兼容性的限制)可能无法使用 EAX 或 GCM 实现。我认为,即使在这种情况下,最好将一些 AES-ECB 代码改进为 EAX 实现。