使用不同的派生密钥是否安全,但使用相同的密码短语进行 AES CBC 加密,然后是 HMAC SHA256 哈希?

信息安全 加密 哈希
2021-09-07 09:51:37

我正在开发一个跨平台(JS/iOS/Android)列表管理器应用程序,它通过 REST API 保存数据,我想确保在客户端正确加密任何文本数据,这样就无法解密数据服务器端,并且在数据库被盗的不幸情况下,不值得花任何精力尝试解密它。

经过数月的研究和反复试验,我决定 CBC 操作模式下的 AES 加密是最佳选择,因为它的强度和在所有平台上的广泛采用。我决定基于 OpenSSL 的类似算法进行密钥派生,以便我有一个可靠的命令行工具来测试我的实现的准确性。

剩下的唯一事情就是以某种方式确保用户提供的加密密码短语的有效性,它永远不会直接到达服务器端。到目前为止,我想到的最好的想法是在登录后解密几个列表项,以测试它们是否可以通过对密文应用 HMAC 散列来正确解密,而这又需要在服务器端存储 HMAC 散列。

我有一些问题:

  • 有没有其他方法可以安全地确保成功登录后提供的密码的有效性?
  • 在 AES CBC 加密中重复使用相同的密码作为相同加密数据的 HMAC 散列中的密钥是否安全?

我见过这个 TLS 线程,但我不需要典型的客户端/服务器设置之间的加密。在我的情况下,客户端加密数据,存储在云中,下次同一个客户端或另一个客户端将解密它。因此,TLS 中的握手等对我来说没有多大意义。

注意 1:我故意将其称为上面的“密码短语”,以强调它与在登录时验证并作为哈希存储在用户帐户中的用户密码不同。

注意 2:最重要的是,请求将通过 HTTPS 传输。上述重点不是确保传输安全,而是将数据的可读性限制在客户端以获得众多安全优势。

我很感激任何反馈。谢谢!

3个回答

您正在滚动自己的密码学。 不要推出自己的加密货币相反,我建议您使用 PGP 或 GPG,或者使用它们的格式:即 OpenPGP 文件格式。

您不应将相同的密钥用于加密和身份验证。 我不建议对 AES-CBC 和 HMAC 使用相同的密钥。

相反,我建议您从主密钥派生两个密钥。例如,K enc = AES(MK, 0), K auth = AES(MK, 1),其中 MK 是主密钥(一个 AES 密钥),0,1 是两个不同的 AES 明文。现在使用 K enc作为与 AES-CBC 一起使用的加密密钥,并使用 K auth作为与 SHA1-HMAC 或 AES-CMAC 一起使用的身份验证密钥。

或者,您可以使用经过身份验证的加密模式,例如 EAX、CCM、GCM 或 OCB。 认证加密负责从单个主密钥派生密钥,并负责提供认证和加密。

听起来您还犯了另一个错误:使用密码作为加密密钥。您应该尽量避免使用密码作为加密密钥

您是否有机会只使用 GPG 传统加密?GPG 已经过仔细编写和审查,以处理所有这些问题。

您可以使用 PBKDF2 和不同的盐来派生散列和加密的密钥。PBKDF 函数的目的是从 pass(words|phrases) 派生密钥。盐应该使用加密强的 PRNG 生成,并且应该很长(例如,与您的密钥一样长)。请注意,PBKDF2 的盐不一定是秘密,因此在必要时将它们发送到服务器是安全的(至少在派生用于 HMAC 的密钥时用作输入的盐)。

是的,您可以使用该模式。

  • 向用户提供明文和该文本的 HMAC 不会泄露 HMAC 的密钥。
  • 向用户提供明文不允许他们在不知道密钥的情况下推导出 HMAC。
  • 向用户提供没有密钥的 HMAC 不允许他们针对任何文本测试 HMAC。

有了这些已知因素,向用户提供使用相同密钥的 HMAC 和密文不会让用户在不知道密钥的情况下一无所获。那里没有任何东西可以减少破解加密所需的尝试次数。

该方案与提供纯文本的简单散列之间的实质性区别在于,人们无法有效地尝试暴力破解/彩虹表散列(尽管无论如何消息可能太长了)。

还有其他模式可以以确保真实性的方式加密消息。这些在其他人的答案中有所提及,根据您的需要可能更有用。我建议也调查这些。