我想实现一个密码创建程序,类似于 Symantec 和 LastPass 提供的程序。该程序将允许用户简单地指定不同的密码长度和选项。
除了在算法中使用适当的加密安全伪随机数生成器之外,是否还有其他安全考虑?我的计划是使用类似 RNGCryptoServiceProvider 的东西。“安全随机密码生成器”是指至少不会因为实施不当而受到后门或容易受到轻率缺陷影响的密码生成器。这不是一个网络应用程序。
请注意:我无意“滚动我自己的”加密或散列。
我想实现一个密码创建程序,类似于 Symantec 和 LastPass 提供的程序。该程序将允许用户简单地指定不同的密码长度和选项。
除了在算法中使用适当的加密安全伪随机数生成器之外,是否还有其他安全考虑?我的计划是使用类似 RNGCryptoServiceProvider 的东西。“安全随机密码生成器”是指至少不会因为实施不当而受到后门或容易受到轻率缺陷影响的密码生成器。这不是一个网络应用程序。
请注意:我无意“滚动我自己的”加密或散列。
如果您有两个组件,则创建安全密码生成器相当容易:
加密安全的 RNG。这意味着 RNG 的输出是一个比特流,在任何条件下都不能预测。然而,在大多数情况下,您可以只使用专为密钥生成而设计的 PRNG,例如 /dev/urandom、/dev/random 或 CryptGenRandom。不应该使用像 Mersenne Twister 这样的常规 PRNG 来生成密钥。除非您在 CSPRNG 数学方面有深厚的背景,否则您不应该尝试编写自己的 CSPRNG。这是大多数“开发密码生成器的普通人”通常没有真正关注的部分。
一对一的编码算法。该算法将 RNG 产生的比特流编码为系统可接受的需要使用密码的东西,对于可记忆的密码,用户的偏好。一对一编码是一个函数,其输入没有任何输出冲突,因此该函数在编码期间不会丢失 RNG 产生的任何熵。这是实际上非常容易的部分,但大多数“开发密码生成器的普通人”经常不必要地过度复杂化,最终削弱了他们的密码生成方法。
一对一编码算法示例:Diceware、base64、十六进制编码、任何完美的散列函数。不适合密码生成的转换算法示例:大多数常规哈希算法。
一旦你有了这两个组件,你需要做的就是向 CSPRNG 询问长度为 n 的比特流,其中 n 是所需的密码强度,并使用你选择的编码算法对该比特流进行编码。
陷阱:您应该参数化编码算法,使其永远不会产生会被目标系统的密码策略拒绝的密码。如果您只是拒绝密码并使用不同的随机值再次生成密码,那么您正在减少熵。从理论上讲,这确实意味着您需要知道需要生成的每个系统的确切密码策略详细信息,才能正确计算密码强度。在实践中,您通常可以简单地添加更多位强度来补偿由于这种过于复杂的密码策略造成的熵损失。
陷阱:对于可记忆的密码,必须训练用户不要拒绝任何他们最终发现难以记住的密码,因为这也会降低熵。这意味着应尽可能设计可记忆的密码编码器,以便它生成最有可能在第一次尝试时被用户接受的密码/释义。很少有编码算法会尝试这样做,例如EFF Diceware wordlist或 Grammatical Diceware。
密码生成器的主要考虑因素是它不会产生可预测的输出。随机密码的关键在于,对它们的最佳攻击是暴力破解,但如果存在偏见,攻击者可以利用来减少他们的搜索空间。
类似地,人们通常想要额外的限制,比如“发音”。这可能是一个安全优势(您可以记住密码而不是存储它们)以及一个缺点(引入偏见,见上文)。如果您对此感兴趣,请务必小心不要在算法中引入额外的偏差,因为这是一个比简单地生成随机字符更复杂的问题。