首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用pynacl的文件加密

使用pynacl的文件加密
EN

Code Review用户
提问于 2019-05-20 01:15:40
回答 1查看 564关注 0票数 3

我需要一个相当简单的Python文件加密/解密器,经过一些研究后,我决定使用tye pynacl库以块读取文件,将它们写回,最后使用Blake2b为文件生成一个签名。每个文件都使用一个唯一的密钥加密,该密钥将沿着加密文件的一侧分发,文件密钥RSA使用预共享密钥对加密,整个消息与ECDSA签署,以验证它来自我。

加密/解密示例代码:

代码语言:javascript
复制
import base64
import struct
import nacl.secret
import nacl.utils
import nacl.hashlib
import nacl.hash

BUFFER_SIZE = 4 * (1024 * 1024)

def read_file_blocks(file, extra_bytes=0):
    while True:
        data = file.read(BUFFER_SIZE + extra_bytes)
        if not data:
            break
        yield data

def hmac_file(file, key):
    blake = nacl.hashlib.blake2b(key=key)
    with open(file, 'rb') as in_file:
        for block in read_file_blocks(in_file):
            blake.update(block)
    return blake.hexdigest()

def encrypt_archive(archive_name, encrypted_name):
    key = nacl.utils.random(nacl.secret.SecretBox.KEY_SIZE)
    #Use 4 bytes less than the nonce size to make room for the block counter
    nonce = nacl.utils.random(nacl.secret.SecretBox.NONCE_SIZE - 4)
    block_num = 0

    box = nacl.secret.SecretBox(key)
    with open(archive_name, 'rb') as in_file, open(encrypted_name, 'wb') as out_file:
        for data in read_file_blocks(in_file):
            #Append the block counter to the nonce, so each block has a unique nonce
            block_nonce = nonce + struct.pack(">I", block_num)
            block = box.encrypt(data, block_nonce)
            out_file.write(block.ciphertext)
            block_num += 1

    hmac_key = nacl.hash.sha256(key + nonce, encoder=nacl.encoding.RawEncoder)
    output = {}
    output['key'] = base64.b64encode(key + nonce)
    output['signature'] = hmac_file(encrypted_name, hmac_key)
    return output

def decrypt_archive(encrypted_name, archive_name, key_info):
    key_bytes = base64.b64decode(key_info['key'])

    key = key_bytes[:nacl.secret.SecretBox.KEY_SIZE]
    nonce = key_bytes[nacl.secret.SecretBox.KEY_SIZE:]

    extra_bytes = nacl.secret.SecretBox.MACBYTES
    hmac_key = nacl.hash.sha256(key_bytes, encoder=nacl.encoding.RawEncoder)
    hmac = hmac_file(encrypted_name, hmac_key)
    if hmac != key_info['signature']:
        print('hmac mismatch')
        return

    block_num = 0
    box = nacl.secret.SecretBox(key)
    with open(encrypted_name, 'rb') as in_file, open(archive_name, 'wb') as out_file:
        # nacl adds a MAC to each block, when reading the file in, this needs to be taken into account
        for data in read_file_blocks(in_file, extra_bytes=extra_bytes):
            block_nonce = nonce + struct.pack(">I", block_num)
            block = box.decrypt(data, block_nonce)
            out_file.write(block)
            block_num += 1

key_info = encrypt_archive("C:\\temp\\test.csv", "C:\\temp\\test.enc")
print(key_info)
decrypt_archive("C:\\temp\\test.enc", "C:\\temp\\test.enc.csv", key_info)

除了一般的错误,我所做的两件事我并不完全确定是正确的:

  1. 为了保持块的非惟一性,我为nonce创建了一个比所需的稍微小一点的字节随机列表,然后在加密块号时,我将块号作为一个4字节的整数添加到该块中。
  2. 在生成blake2b哈希时,对于一个键,我会散列文件键和当前值。这似乎有点毫无用处,因为如果他们有钥匙和现在,他们可以只是替换文件。不过,我真的想不出一个更好的选择,那就是没有类似的弱点。我应该放弃这一点吗,因为NaCl无论如何都是每块MACs做的?(我是在写了hmac代码之后才发现的)
EN

回答 1

Code Review用户

发布于 2020-03-02 00:57:59

代码部分下的代码/协议注释。

代码语言:javascript
复制
def read_file_blocks(file, extra_bytes=0):
    while True:
        data = file.read(BUFFER_SIZE + extra_bytes)

至少要指定使用额外字节的原因,并记录extra-bytes参数的含义。

代码语言:javascript
复制
def hmac_file(file, key):

为什么要遍历整个文件,然后只释放读取的字节来执行HMAC?你刚刚处理了内存中的所有块!为什么blake2b而不是一个更常见的SHA-2散列呢?

代码语言:javascript
复制
#Use 4 bytes less than the nonce size to make room for the block counter

我敢打赌这不是必需的,毫无疑问,柜台已经包括在内了。也许你可以指出一个特定的要求,包括一个块计数器每4MiB?

代码语言:javascript
复制
hmac_key = nacl.hash.sha256(key + nonce, encoder=nacl.encoding.RawEncoder)

至少使用HMAC代替哈希来派生密钥,这是一个可怜的人的KDF。

代码语言:javascript
复制
output['key'] = base64.b64encode(key + nonce)

抱歉,输出什么?钥匙?

代码语言:javascript
复制
output['signature'] = hmac_file(encrypted_name, hmac_key)

CryptoBox使用经过验证的密码。根本不需要再来一次。

算法详细信息: 加密: Salsa20流cipher身份验证: Poly1305 MAC

票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/220536

复制
相关文章

相似问题

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