解密文件时如何检查用户输入的密码是否正确?

信息安全 加密 密码
2021-08-26 12:51:52

我正在尝试创建一个用于加密/解密不同文件的程序。我的代码没有问题,我只是不知道如何保存通过我的程序加密的每个文件的密码。

用户可以使用密码加密他的文件,当他试图解密它时,必须有一条消息通知他密码错误,因为当他使用错误密码时,程序会生成一个解密文件,这将仍然无法阅读。

2个回答

你做错了!但这没关系,业余密码学是我们所有人开始和学习的地方。请注意,除非您让独立第三方对其进行审核,否则您的加密软件将不安全,即便如此,他们也不做任何保证。不要将您自己的爱好加密货币用于任何重要的事情!并且不要让其他人使用它而不确保他们知道它只是一个玩具!

想象一下,您有一个文件,上面写着“10:00 攻击”。加密,类似于aWJiaWtzIGliIDEzOjAw. 您的敌人可能知道您正在发送攻击消息,但不知道密码。但是,他们可以做的是更改一个字节。如果消息更改为aWJiaWtzIGliIDazOjAwE替换为a),它突然说:“在 03:00 攻击”。

如您所见,即使是盲目地修改密文,也可能对攻击者(敌人)有利。您希望在检测到修改的情况下进行身份验证加密。这也解决了您的密码问题。

您不需要将密码存储在文件中,因为如果他们输入错误的密码,身份验证检查将失败。软件会注意到解密后的文本与原始文本不同,你就会知道它是错误的。

还有一些关于为什么应该使用经过身份验证的加密的更多详细信息:

网上有很多关于如何进行身份验证加密的资源。寻找一些好的方法是 AES+HMAC,或 AES 在认证模式,如 GCM 或 OCB。这篇 Wikipedia 文章是一个很好的介绍,并包含指向您可能可以使用的算法的指针:https ://en.wikipedia.org/wiki/Authenticated_encryption

作为一个例子,让我们考虑前面的密文:aWJiaWtzIGliIDEzOjAw. 现在我们使用 SHA-256 对其进行HMAC,这给了我们3be635.... 我使用了一个随机在线站点来计算 HMAC,并使用了与加密时相同的密码。(作为对读者的挑战,请尝试打破它:)。它只是一个字符。)我们可以将两者存储在一起:aWJiaWtzIGliIDEzOjAw|3be635. 当用户尝试解密内容时,他们输入密码,您可以再次计算 HMAC,如果不匹配,您就知道消息被篡改,或者他们的密码不正确。

代码基本上是:

# Encrypt
password = user_input()
plaintext = "attack at 10:00"
ciphertext = encrypt(method = "AES-256-CTR", key = password, data = plaintext)
auth_code = hmac(method = "SHA-256", key = password, data = ciphertext
write_file(name = "encrypted", data = base64(ciphertext) + "|" + auth_code)

# Decrypt
password = user_input()
ciphertext, auth_code = read_file(name = "encrypted").split("|")
computed_auth_code = hmac(method = "SHA-256", key = password, data = ciphertext)
if computed_auth_code == auth_code:
    plaintext = decrypt(method = "AES-256-CTR", key = password, data = ciphertext)
    print(base64_decode(plaintext))

到目前为止一切顺利,但是...

这种方法允许攻击者非常快速地猜出密码。HMAC 操作需要几微秒来计算,因此攻击者可以在标准计算机上每秒进行许多猜测。代码非常简单:

ciphertext, auth_code = read_file(name = "encrypted").split("|")
for password in load_file("password_database.txt"):
    if auth_code == hmac(method = "SHA-256", key = password, data = ciphertext):
         print("The password is " + password)

因为for循环中唯一的操作是hmac(...)和快速比较,所以非常快。

在将用户密码用于任何操作之前,您应该应用慢速密钥派生函数 (KDF)问题中回答了如何最好地做到这一点:如何安全地散列密码?.

您的代码现在应该如下所示:

password = user_input()
password = argon2(iterations = 1_000_000, memory = 100_000_000, data = password)
# Below here, the normal encryption/decryption code

现在,攻击者的代码必须如下所示:

ciphertext, auth_code = read_file(name = "encrypted").split("|")
for password in load_file("password_database.txt"):
    password = argon2(iterations = 1_000_000, memory = 100_000_000, data = password)
    if auth_code == hmac(method = "SHA-256", key = password, data = ciphertext):
         print("The password is " + password)

现在攻击者必须做这个 argon2 的事情,这非常慢。如果在您的计算机上需要 1 秒,那么在他们的计算机上也将需要大约 1 秒(可能快一点,也可能慢一点)。这意味着攻击者每秒只能猜测一次密码。这样安全多了!当然,攻击者可以使用 100 台计算机,但这是一笔巨大的投资,他们仍然每秒只有 100 次猜测,而不是每秒数百万甚至数十亿次。

首先,您应该考虑这个免责声明

如果出现以下情况,请继续您的实施:

  • 您的工具仅用于教育目的
  • 您的工具不需要用于真正敏感的数据
  • 你真的知道,你在做什么

也就是说,您可以考虑在文件中存储密码哈希。如果你这样做,也请考虑这个问题然后,您的工具可以在解密之前检查密码哈希是否正确,从而向用户提供有效的反馈。

请记住,密码哈希可以(可能)被破解将密码或密码的哈希存储在文件中,您加密的因此会削弱工具的“安全性”。

TLDR;

你最好的选择是使用算法(和实现)来解决你的问题,避免重新发明轮子。看看 Luc 建议的经过身份验证的加密。