我目前正在开发一个使用 AES 256 加密文件的应用程序。
问题是我希望用户在解密文件之前查看密码是否错误。
比如你要解密一个1GB左右的文件,你需要20分钟才能解密,但是解密后你才发现密码错误,你等了20分钟都没用!
所以必须有可能在解密之前检查密码。因此,您需要将密码与文件一起传输。
但是怎么做?MD5可以破解。SHA 也可能很快被破解。
那么最好的方法是什么,我怎样才能超级安全地加密密码呢?
我目前正在开发一个使用 AES 256 加密文件的应用程序。
问题是我希望用户在解密文件之前查看密码是否错误。
比如你要解密一个1GB左右的文件,你需要20分钟才能解密,但是解密后你才发现密码错误,你等了20分钟都没用!
所以必须有可能在解密之前检查密码。因此,您需要将密码与文件一起传输。
但是怎么做?MD5可以破解。SHA 也可能很快被破解。
那么最好的方法是什么,我怎样才能超级安全地加密密码呢?
我希望用户在解密文件之前查看密码是否错误。
解密不会告诉您密码是否正确。如果您提供了错误的密码,您将得到一个解密的结果。一个错误的,但你怎么知道?
通常,您加密的数据具有一些事先已知的结构。比如说,它是一个文本文件,它必须只包含可打印的字符。或者它是一个视频文件,必须以格式良好的 MPEG 标头开头。如果密码意外错误,那么输出仍然具有这种结构的概率可以忽略不计。在大多数情况下,前几个解密字节将泄露输出是否格式正确,因此密码是否正确。但是你的应用程序很难判断——它是在解密前几个字节之后还是在解密所有内容之后执行验证——除非应用程序专门用于特定的文件格式。
所以你可以做的是用一个已知的标题开始你的明文,比如Elefantosque's exercise in password-protected encryption. 如果前几个解密的字节是正确的,那么你就知道密码是正确的。标头的长度取决于您的加密强度;它至少应该是密钥的长度(即此处为 32 个字节)。
顺便说一句,如果您的解密应用程序可以通过某种通用方式判断输出是否正确,那么它所做的不仅仅是加密:它还在验证其输入的完整性。AES 不这样做(如果在特定模式下使用它可以)。因此,要么您的应用程序正在对您没有告诉我们的数据执行其他一些加密验证,要么您的应用程序并没有真正验证完整性,特别是没有检测到错误的密码。
如果您使用上述已知的标头方法,那么您的应用程序将通过验证标头的完整性来检测错误密码(这里,完整性检查是标头必须等于已知值)。请注意,您仍然不会验证数据的完整性。
如果您担心攻击者会修改传输中的数据,那么您需要的是在单个算法中某种形式的经过身份验证的加密(可以是 AES 链接模式),或者通过MAC将加密与身份验证相结合(加密-then-MAC 或 MAC-then-encrypt)。
您没有说的另一件事是 AES 的使用与提供的密码有何关系。AES-256 密钥通常由 256 位组成,攻击者必须完全不知道这些位(在整个密钥空间中随机生成)。密码是一个字符串,通常由人选择,它可能具有仅由可打印字符组成的限制,具有最小长度要求等。从密码中生成 AES 密钥是一项非常重要的操作,您执行此操作的方式对您的应用程序(或者更确切地说是您的协议)的安全性至关重要。
从密码生成 AES 密钥的一种可接受的方法是密钥拉伸和加盐。密码的问题在于攻击者通常可以通过蛮力破解它们。无论您的密码如何使用,如果攻击者知道它是其中之一password,1234或者l33t,那么攻击者可以尝试所有三种可能性。您最多可以期望(在像您这样的情况下)是让攻击者尝试多种可能性的代价高昂。一个好的拉伸函数需要很长时间来计算。对于合法用途,您只执行该功能一次,因此成本无关紧要,而攻击者的成本乘以他执行的尝试次数。至于加盐,它减少了想要破解多个加密文件的攻击者的重用量。加盐意味着在拉伸数据中包含随机分量(以明文形式存储)。由于每个文件的盐值都不同,因此攻击者无法预先计算从通用密码派生的延伸密钥列表。
作为更一般的说明,您似乎对安全性有一种不平衡的看法(别担心,这在初学者中很常见)。您非常重视算法的选择(AES-256,忽略 SHA-1),而对其他重要的部分则完全不重视,例如是什么让您断定密码是正确的或您如何使用您的方案中的密码。事实上,与发现协议中的漏洞(即信息流和算法的使用方式)相比,在常用密码算法中发现漏洞非常罕见(尤其是实际漏洞) 。密码算法很难设计,但其中一些足以满足大多数目的,您无需了解它们为什么工作(甚至如何真正地)使用它们。协议很难设计同样,它们通常是特定于应用程序的,至少部分是这样的;所以你需要非常注意你的协议设计。尽可能重用现有协议(但请注意正确使用它们!),并在需要设计时小心行事。同样,您可以打赌您的应用程序会因为协议损坏(或实现损坏,如果您不是一个细心的实现者)而崩溃,而不是因为密码算法损坏。
事实上,没有充分的理由不使用 AES-128。它将减少解密时间,并且不会明显降低安全性。SHA-1 的使用确实很久没有被推荐了,尽管人们担心的攻击需要比预期更长的时间才能到达。尽管如此,SHA-1 并没有因为这里重要的目的而被破坏,即反转散列(已知的弱点与冲突有关,即查找与某些已知数据具有相同散列的数据)。尽管如此,在设计需要加密摘要的情况下,建议使用 SHA-256。
对不起,什么?您需要将密码与文件一起传输吗?我们在这里谈论的是什么类型的密码,加密证据,或者只是“donkey12”?
简洁版本
如果这是出于任何严肃的目的,请不要这样做。密码学很难。你不是密码学家。
更长的版本
如果您只是为了好玩而这样做,您可以通过应用于加密文件的标头来执行此操作。所以 C=([标题]+[文件内容])
标头将使验证密码变得更容易,而且攻击者在尝试解密时也更容易确定他们是否拥有正确的密钥。
依赖“直接”PKI 可能更简单(即更安全),并假设另一端的用户除了他们的私钥之外没有其他密钥,并且除了他们的公共密钥之外你没有其他密钥钥匙。
我假设以下内容:
如果这些都是正确的,那么与文件一起传输密码会显着降低加密文件的安全优势。加密文件的原因通常是为了防止在传输过程中被拦截或在存储中未经授权访问的威胁。如果您将密码与文件一起传输,这两者都会受到损害。
为了获得安全优势,您应该始终将密码带外传输到文件传输中。通过另一种更安全的机制传输密码。例如,安全电子邮件、给授权个人的电话、安全 USB。
一些优先顺序的建议:
A) 使用非对称加密并远离密码。
理想情况下,使用开放 SSL 之类的东西在接收方机器上生成公钥对。使用权限或硬件安全模块保护私钥。例如通过电子邮件或文件传输获取公钥,然后将文件加密为该公钥。这可确保永远不会出现任何密码问题并减轻已定义的威胁。
B)在解密之前编写您的代码或使用程序检查密码
例如,这就是使用密码进行 Winzip 和 PGP 文件加密的工作原理。它将在解密文件之前首先验证密码。这应该可以解决您的 20 分钟延迟问题。如果您不确定如何执行此操作,那么它应该成为 stackoverflow 上的另一个问题,其中包含您特定的应用程序开发语言详细信息。
通过使某人更容易判断密码是正确还是不正确,您也必然会使蛮力攻击更容易。因此,您需要选择一种不允许简单暴力破解的密码确认算法。
MD5 和 SHA 的问题类型不影响此使用。仅发送密码的 MD5 的问题是有人可以使用庞大的 MD5 哈希数据库。除非密码强且随机,否则这是一个大问题。
如果您使用 AES-256 的随机 256 位密钥,您可以只发送密钥的 MD5。在 MD5 中没有任何可以想象的中断会很重要。平均而言,79,228,162,514,264,337,593,543,950,336 个不同的 AES-256 密钥无论如何都会具有该 MD5 哈希值。
如果密码不是随机的,您将需要阻止使用彩虹表。您可以使用带有随机标签的散列,并将标签包含在散列中。一个安全的解决方案可以按如下方式工作:
1) 生成一个随机的 128 位值。
2) 将密码散列为 128 位值。
3) HMAC 随机值的密码。(对这两个值和散列进行 XOR 也一样。)
4) 在文件中包含 HMAC 和随机值。