首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >与AES一起加密文件的bcrypt/sha256密钥的安全性

与AES一起加密文件的bcrypt/sha256密钥的安全性
EN

Security用户
提问于 2013-01-22 04:03:43
回答 1查看 6.1K关注 0票数 6

我希望使用Python中的安全散列和加密算法对文件进行加密。在过去使用bcrypt之后,我决定将它用于我的密码计算器,然后通过SHA256传递输出以获取32字节的数据,然后使用它与AES一起加密/解密一个文件:

代码语言:javascript
运行
复制
#!/usr/bin/env python

from argparse import ArgumentParser
from bcrypt import gensalt, hashpw
from Crypto.Cipher import AES
from hashlib import sha256

import os, struct, sys

def main():
    parser = ArgumentParser(description = "Encrypts or decrypts a file using " +
            "bcrypt for the password and triple AES for file encryption.")
    parser.add_argument('-p', '--passphrase', required = True, 
            help = "The passphrase to use for encryption.")
    parser.add_argument('-i', '--input', required = True,
            help = "The input file for encryption / decryption.")
    parser.add_argument('-o', '--output', required = True,
            help = "The output file for encryption / decryption.")
    parser.add_argument('-r', '--rounds', default = 10, 
            help = "The number of bcrypt rounds to use.")
    parser.add_argument('-s', '--salt', default = None,
            help = "The salt to use with bcrypt in decryption.")
    parser.add_argument('operation', choices = ('encrypt', 'decrypt'),
            help = "The operation to apply, whether to encrypt or decrypt data.")

    parameters = parser.parse_args()

    if parameters.operation == 'encrypt':
        encrypt(parameters.input, parameters.output, parameters.passphrase,
                parameters.rounds)
    elif parameters.operation == 'decrypt':
        decrypt(parameters.input, parameters.output, parameters.passphrase,
                parameters.salt)

def encrypt(input_file, output_file, passphrase, rounds):
    bcrypt_salt = gensalt(rounds)
    bcrypt_passphrase = hashpw(passphrase, bcrypt_salt)
    passphrase_hash = sha256(bcrypt_passphrase).digest()

    print "Salt: %s" % (bcrypt_salt, )

    iv = os.urandom(16)

    cipher = AES.new(passphrase_hash, AES.MODE_CBC, iv)

    with open(input_file, 'rb') as infile:
        infile.seek(0, 2)
        input_size = infile.tell()

        infile.seek(0)  

        with open(output_file, 'wb') as outfile:
            outfile.write(struct.pack('<Q', input_size))
            outfile.write(iv)

            while True:
                chunk = infile.read(64 * 1024)
                if len(chunk) == 0:
                    break
                elif len(chunk) % 16 != 0:
                    chunk += ' ' * (16 - len(chunk) % 16)

                outfile.write(cipher.encrypt(chunk))

    return bcrypt_salt

def decrypt(input_file, output_file, passphrase, salt):
    print "Salt: %s" % (salt,)

    bcrypt_passphrase = hashpw(passphrase, salt)
    passphrase_hash = sha256(bcrypt_passphrase).digest()

    with open(input_file, 'rb') as infile:
        input_size = struct.unpack('<Q', infile.read(struct.calcsize('Q')))[0]
        iv = infile.read(16)

        cipher = AES.new(passphrase_hash, AES.MODE_CBC, iv)

        with open(output_file, 'wb') as outfile:
            while True:
                chunk = infile.read(64 * 1024)
                if len(chunk) == 0:
                    break

                outfile.write(cipher.decrypt(chunk))

            outfile.truncate(input_size)

if __name__ == "__main__":
    main()

这样的实现有哪些可能的弱点?

我所确定的是,攻击者很容易确定原始文件大小,但这并不能透露文件的多少信息。沙-256不是世界上最好的哈希算法,但是封装一个bcrypt密码会让我相信所有的威胁都会得到缓解。由于bcrypt能够随着时间的推移增加安全性,在算法中添加更多的回合,目前使用bcrypt似乎是一种非常安全的选择。

这个实现有什么漏洞吗?我不是密码专家,但我知道这里使用的三种算法的基础和用途。

EN

回答 1

Security用户

回答已采纳

发布于 2013-01-22 11:44:43

看了两分钟:

  • 使用bcrypt是很好的。SHA-256是最著名的散列函数之一(因为它已经存在了10多年,广泛部署,但没有损坏)。
  • 因为您为每个加密的文件生成一个新的盐分(这很好!),所以将其存储在文件头中是有意义的。这样,您就不必将它作为参数提供给解密例程。salt不需要保密(即salt,而不是密钥),但是必须为每次加密生成一个新的salt,因此外部处理可能很麻烦。您已经有了IV的自定义标题,您也可以对salt做同样的操作。替代方案:将salt存储为报头,并从bcrypt输出生成加密密钥和IV (将SHA-256输出拆分为两个128位块;第一个是密钥,第二个是IV)。这将使标题大小保持在16个字节。但是随机IV (来自os.urandom(),就像您所做的)也不坏。
  • 您使用加密,但没有MAC。攻击者可以观察数据的攻击模型不多(即需要保密),但不需要更改数据(即不需要完整性)。在实践中,您最好添加一个MAC。理想情况下,用同时处理加密和完整性的模式(GCMEAX)替换CBC。如果您的支持库没有提供这样的模式,则必须将加密与HMAC结合起来进行“旧样式”操作。我是不完全是琐碎的事。最佳实践是从bcrypt输出生成额外的MAC密钥(如果您生成加密密钥、IV和MAC密钥,您将需要一个更大的哈希函数,例如SHA-512),并通过IV和加密数据的连接计算MAC (只有在从密码生成IV时才能跳过IV,但将它包含在MAC输入中更安全)。解密后,首先验证MAC,然后只在MAC匹配的情况下继续解密。
  • 您可能需要包含一些算法敏捷性的规定,即在标头中添加一个字节值来标识您使用的算法的组合(bcrypt,SHA-256,AES+CBC,HMAC/sma-256)。这将允许您稍后切换到另一组算法,而不会破坏与现有文件的代码兼容性。在这种情况下,不要忘记将这个“算法标识符字节”添加到MAC的输入中。
  • 填充是模棱两可的:解密后,您将在末尾找到一些空格字符,但您将不知道额外的空格是输入文件的一部分,还是由encrypt函数添加的。而且,实际上,解密后你就离开了空格。对于特定的使用场景来说,这可能不是一个问题,但是,作为一般的加密/解密工具,如果文件在未经修改的情况下无法通过加密/解密过程,这通常被认为是一个问题。PKCS#7填充 (也称为PKCS#5填充)是常用的:您添加k字节(至少1字节,最多16,因此总长度为16的倍数),所有字节的值为k。解密后,查看最后一个字节,它将告诉您添加了多少填充字节。
票数 9
EN
页面原文内容由Security提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://security.stackexchange.com/questions/29481

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档