使用salt在python中加密/解密数据

时间:2011-06-21 12:21:16

标签: python encryption

我基本上想知道如何使用生成的salt密钥加密数据,然后使用python解密它?

我已经通过了很多网站和模块,他们在加密部分看起来都很棒,但是没有人可以解密。

我主要担心的是有很强的盐密钥,可能会在很短的时间内生成,然后使用该密钥加密数据 - 特别是我正在研究使用salt密钥加密JSON编码数据,发送加密数据到另一侧(侦听客户端),然后根据用于生成salt密钥的算法解密那里的数据。

我发现mcrypt模块在这方面效果最好,但是没有太多关于python-mcrypt模块的文档(目前已过时且未维护)。

2 个答案:

答案 0 :(得分:43)

您的问题的简短回答是,您将密码和salt组合在一起并重复哈希以创建密钥。然后将salt附加到密文上,以便生成解密密钥。为了确保我有正确的答案,我做了一些功能来完成工作。它们在下面给出。

在我的回答中,我使用了pycrypto,所以我们需要导入一些这些库。

import Crypto.Random
from Crypto.Cipher import AES
import hashlib

为了提高可读性,我已经定义了一些我将在稍后使用的常量。

# salt size in bytes
SALT_SIZE = 16

# number of iterations in the key generation
NUMBER_OF_ITERATIONS = 20

# the size multiple required for AES
AES_MULTIPLE = 16

要使用salt,我已经完成了基于密码的加密方案。我使用RSA PKCS #5 standard进行基于密码的加密密钥生成和填充,适用于AES加密算法。

要生成密钥,请将密码和salt连接起来。此组合根据要求进行多次散列。

def generate_key(password, salt, iterations):
    assert iterations > 0

    key = password + salt

    for i in range(iterations):
        key = hashlib.sha256(key).digest()  

    return key

要填充文本,你可以计算出除了16的偶数之外还有多少额外字节。如果是0,则添加16个字节的填充,如果是1,则添加15,等等。这样你总是添加填充。您填充的字符是与填充字节数(chr(padding_size))具有相同值的字符,以帮助删除末尾的填充(ord(padded_text[-1]))。

def pad_text(text, multiple):
    extra_bytes = len(text) % multiple

    padding_size = multiple - extra_bytes

    padding = chr(padding_size) * padding_size

    padded_text = text + padding

    return padded_text

def unpad_text(padded_text):
    padding_size = ord(padded_text[-1])

    text = padded_text[:-padding_size]

    return text

加密需要生成随机盐并将其与密码一起使用以生成加密密钥。使用上述pad_text函数填充文本,然后使用密码对象加密。密文和盐连接在一起并返回。如果您想以明文形式发送,则需要使用base64对其进行编码。

def encrypt(plaintext, password):
    salt = Crypto.Random.get_random_bytes(SALT_SIZE)

    key = generate_key(password, salt, NUMBER_OF_ITERATIONS)

    cipher = AES.new(key, AES.MODE_ECB)

    padded_plaintext = pad_text(plaintext, AES_MULTIPLE)

    ciphertext = cipher.encrypt(padded_plaintext)

    ciphertext_with_salt = salt + ciphertext

    return ciphertext_with_salt

解密继续进行,从密文中拉出盐并使用它来解密密文的其余部分。然后使用unpad_text解压缩明文。

def decrypt(ciphertext, password):
    salt = ciphertext[0:SALT_SIZE]

    ciphertext_sans_salt = ciphertext[SALT_SIZE:]

    key = generate_key(password, salt, NUMBER_OF_ITERATIONS)

    cipher = AES.new(key, AES.MODE_ECB)

    padded_plaintext = cipher.decrypt(ciphertext_sans_salt)

    plaintext = unpad_text(padded_plaintext)

    return plaintext

如果您有任何其他问题/说明,请与我们联系。

答案 1 :(得分:1)

除了RNCryptor之外,您不需要任何其他内容:

import rncryptor

data = '...'
password = '...'

# rncryptor.RNCryptor's methods
cryptor = rncryptor.RNCryptor()
encrypted_data = cryptor.encrypt(data, password)
decrypted_data = cryptor.decrypt(encrypted_data, password)
assert data == decrypted_data

# rncryptor's functions
encrypted_data = rncryptor.encrypt(data, password)
decrypted_data = rncryptor.decrypt(encrypted_data, password)
assert data == decrypted_data

它提供语义安全(每个加密的随机盐和IV)加密,并包括通过HMAC进行安全完整性检查(密文不能在没有注意的情况下进行操作)。

RNCryptor也有特定的数据格式,因此您不必考虑这些和实施in many languages