我基本上想知道如何使用生成的salt密钥加密数据,然后使用python解密它?
我已经通过了很多网站和模块,他们在加密部分看起来都很棒,但是没有人可以解密。
我主要担心的是有很强的盐密钥,可能会在很短的时间内生成,然后使用该密钥加密数据 - 特别是我正在研究使用salt密钥加密JSON编码数据,发送加密数据到另一侧(侦听客户端),然后根据用于生成salt密钥的算法解密那里的数据。
我发现mcrypt模块在这方面效果最好,但是没有太多关于python-mcrypt模块的文档(目前已过时且未维护)。
答案 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。