如何简单有效地从一个密码生成不同的密钥?

信息安全 加密 密码 AES hmac
2021-08-15 14:58:37

我在这里看到,使用相同的密钥加密和 mac(按该顺序)消息最终可能是不安全的。

从相同密码生成两个不同密钥的最佳方法是什么(使用带有密码和盐的 PBKDF)?

  • 生成更长的输出并拆分它?
  • 使用相同的密码/盐生成两个密钥,但迭代次数不同?
  • 使用相同的密码但不同的盐生成两个密钥?
  • 还有什么?

(我知道使用AEAD模式会更好,但假设我别无选择)

3个回答

从技术上讲,PBKDF2 可以产生任意长的输出(它是一个Key Derivation Function),但它有一些问题:PBKDF2 在一些哈希函数上使用 HMAC,它的输出长度为k位(例如,对于通常的 SHA-1,k = 160)。如果你要求的输出比那个大小更多,那么计算成本会迅速上升:如果你想要 320 位,它的成本将是 160 位的两倍。

不幸的是,虽然 PBKDF2 被“强化”以阻止字典攻击,但攻击者的成本不会上升得那么快。例如,考虑使用 PBKDF2/SHA-1 生成 256 位的密钥材料:128 位用于对称加密,然后 128 位用于 MAC。作为防御者(普通用户),您必须获得全部 256 位。另一方面,攻击者不需要那么多。他可以以一半的成本简单地生成前 128 位,并查看解密是否会产生非垃圾数据。

这是 PBKDF2 的一个已知问题。请注意,如果您两次使用另一个密码散列函数并使用两种不同的盐,则会出现同样的问题:您为散列支付了两次费用,但攻击者可以忽略其中一个密钥,因此会比您快两倍。

如果您更喜欢使用 bcrypt,那么您会遇到另一个问题,即 bcrypt 不是 KDF;其输出大小为 192 位。不再。它的处理时间不取决于它的输出大小,因为它的输出大小是固定的。

通用方法是运行密码散列函数,然后使用Key Derivation Function扩展输出这就是 @CodesInChaos 所建议的,使用 HKDF -Expand那里有几个 KDF;通常,对于我自己的设计/提案,我依赖来自 NIST SP800-90 和 X9.62 的 HMAC_DRBG(例如在this中)。理想情况下,您需要一个经过严格审查的 KDF,即密码学家已经对其进行了调查,并且他们没有发现任何不好的说法(或者,更好的是,他们制作了“安全证明”)。

如果您赶时间并且不需要大量密钥材料,一个相对简单的方法是使用 SHA-512 对密码哈希函数输出进行哈希处理。这将为您提供价值 512 位的密钥材料。

使用 PBKDF2 时,您可以指定输出密钥的输出长度。如果要生成两个 256 位密钥,则生成一个 512 位输出并将其拆分。建议使用长盐,这样两个键的熵确实是512位。

使用相同的密码但不同的盐生成两个密钥?这是给出足够长和 [密码] 随机盐的正确答案。CodesInChaos 有两个优点 - 不要超过底层哈希的自然输出大小(PBKDF2-HMAC-SHA-1 为 160 位,PBKDF2-HMAC-SHA-512 为 512 位等)和 128 位盐可能没问题,特别是如果您使用 128 位加密。

根据RFC2898,PBKDF2/RFC2898/PKCS#5 规范之一,第 4.1 节:“基于密码的密码学中的盐传统上用于生成与给定密码相对应的大量密钥,其中一个在根据盐随机。” 4.1 的其余部分详细介绍了生成多种盐的其他注意事项,特别是其他各方如何轻松判断他们应该为哪种操作使用哪种盐。*

*即一个答案(未在 RFC 中明确引用)是生成盐,使得以 AA 开头的盐用于第一个操作,以 AB 开头的盐用于第二个操作,AC 用于第三个操作,等等;将非随机的第一个字节添加到盐中作为“放置指示符”,只要盐的其余部分是加密随机的并且足够长。