我正在尝试使用PyCrypto构建两个函数,这两个函数接受两个参数:消息和密钥,然后加密/解密消息。
我在网上找到了几个帮助我的链接,但每个链接都有缺陷:
This one at codekoala使用os.urandom,这是PyCrypto所不鼓励的。
此外,我提供给函数的密钥不能保证具有预期的确切长度。我能做些什么来实现这一点?
另外,有几种模式,推荐哪一种?我不知道该用什么:/
最后,静脉注射到底是什么?我可以为加密和解密提供不同的IV吗,或者这会以不同的结果返回吗?
编辑:删除了代码部分,因为它不安全。
发布于 2014-02-21 16:10:37
以下是我的实现,并对我进行了一些修复,并增强了密钥和秘密短语的对齐,将32字节和iv对齐为16字节:
import base64
import hashlib
from Crypto import Random
from Crypto.Cipher import AES
class AESCipher(object):
def __init__(self, key):
self.bs = AES.block_size
self.key = hashlib.sha256(key.encode()).digest()
def encrypt(self, raw):
raw = self._pad(raw)
iv = Random.new().read(AES.block_size)
cipher = AES.new(self.key, AES.MODE_CBC, iv)
return base64.b64encode(iv + cipher.encrypt(raw.encode()))
def decrypt(self, enc):
enc = base64.b64decode(enc)
iv = enc[:AES.block_size]
cipher = AES.new(self.key, AES.MODE_CBC, iv)
return self._unpad(cipher.decrypt(enc[AES.block_size:])).decode('utf-8')
def _pad(self, s):
return s + (self.bs - len(s) % self.bs) * chr(self.bs - len(s) % self.bs)
@staticmethod
def _unpad(s):
return s[:-ord(s[len(s)-1:])]
发布于 2012-09-21 14:12:54
当输入长度不是BLOCK_SIZE的倍数时,您可能需要以下两个函数:pad
-要填充(加密时)和unpad
-要取消填充(解密时)。
BS = 16
pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS)
unpad = lambda s : s[:-ord(s[len(s)-1:])]
所以你是在问密钥的长度?您可以使用密钥的md5sum,而不是直接使用它。
此外,根据我使用PyCrypto的一点经验,在输入相同的情况下,IV用于混合加密的输出,因此IV被选为随机字符串,并将其用作加密输出的一部分,然后使用它来解密消息。
下面是我的实现,希望对你有用:
import base64
from Crypto.Cipher import AES
from Crypto import Random
class AESCipher:
def __init__( self, key ):
self.key = key
def encrypt( self, raw ):
raw = pad(raw)
iv = Random.new().read( AES.block_size )
cipher = AES.new( self.key, AES.MODE_CBC, iv )
return base64.b64encode( iv + cipher.encrypt( raw ) )
def decrypt( self, enc ):
enc = base64.b64decode(enc)
iv = enc[:16]
cipher = AES.new(self.key, AES.MODE_CBC, iv )
return unpad(cipher.decrypt( enc[16:] ))
发布于 2017-06-21 04:17:25
让我来回答你关于“模式”的问题。AES256是一种分组密码。它接受一个32字节的密钥和一个称为块的16字节字符串作为输入,并输出一个块。为了加密,我们在操作的模式中使用AES。上面的解决方案建议使用CBC,这是一个例子。另一种是CTR,它更容易使用:
from Crypto.Cipher import AES
from Crypto.Util import Counter
from Crypto import Random
# AES supports multiple key sizes: 16 (AES128), 24 (AES192), or 32 (AES256).
key_bytes = 32
# Takes as input a 32-byte key and an arbitrary-length plaintext and returns a
# pair (iv, ciphtertext). "iv" stands for initialization vector.
def encrypt(key, plaintext):
assert len(key) == key_bytes
# Choose a random, 16-byte IV.
iv = Random.new().read(AES.block_size)
# Convert the IV to a Python integer.
iv_int = int(binascii.hexlify(iv), 16)
# Create a new Counter object with IV = iv_int.
ctr = Counter.new(AES.block_size * 8, initial_value=iv_int)
# Create AES-CTR cipher.
aes = AES.new(key, AES.MODE_CTR, counter=ctr)
# Encrypt and return IV and ciphertext.
ciphertext = aes.encrypt(plaintext)
return (iv, ciphertext)
# Takes as input a 32-byte key, a 16-byte IV, and a ciphertext, and outputs the
# corresponding plaintext.
def decrypt(key, iv, ciphertext):
assert len(key) == key_bytes
# Initialize counter for decryption. iv should be the same as the output of
# encrypt().
iv_int = int(iv.encode('hex'), 16)
ctr = Counter.new(AES.block_size * 8, initial_value=iv_int)
# Create AES-CTR cipher.
aes = AES.new(key, AES.MODE_CTR, counter=ctr)
# Decrypt and return the plaintext.
plaintext = aes.decrypt(ciphertext)
return plaintext
(iv, ciphertext) = encrypt(key, 'hella')
print decrypt(key, iv, ciphertext)
这通常被称为AES-CTR。我建议在PyCrypto中使用AES-CBC时要谨慎。原因是它要求您指定填充方案,如所给出的其他解决方案所示。一般来说,如果你不是非常小心的填充,有 是完全破解加密!
现在,重要的是要注意,密钥必须是随机的32字节字符串密码;密码不能满足的要求。正常情况下,密钥的生成方式如下:
# Nominal way to generate a fresh key. This calls the system's random number
# generator (RNG).
key1 = Random.new().read(key_bytes)
密钥也可以是从密码派生的:
# It's also possible to derive a key from a password, but it's important that
# the password have high entropy, meaning difficult to predict.
password = "This is a rather weak password."
# For added # security, we add a "salt", which increases the entropy.
#
# In this example, we use the same RNG to produce the salt that we used to
# produce key1.
salt_bytes = 8
salt = Random.new().read(salt_bytes)
# Stands for "Password-based key derivation function 2"
key2 = PBKDF2(password, salt, key_bytes)
上面的一些解决方案建议使用SHA256来派生密钥,但这通常被认为是bad cryptographic practice。有关操作模式的更多信息,请查看wikipedia。
https://stackoverflow.com/questions/12524994
复制相似问题