我试图使用PyCrypto构建两个函数,它们接受两个参数:消息和密钥,然后加密/解密消息。
我在网上找到了几个链接来帮助我,但每一个都有缺陷:
codekoala的这个使用os。这是PyCrypto不鼓励的。
此外,我给函数的键不能保证具有预期的确切长度。我要怎么做才能做到呢?
还有,有几种模式,推荐哪种模式?我不知道用什么:/
最后,静脉注射到底是什么?我是否可以提供不同的IV来加密和解密,或者这将返回不同的结果?
我试图使用PyCrypto构建两个函数,它们接受两个参数:消息和密钥,然后加密/解密消息。
我在网上找到了几个链接来帮助我,但每一个都有缺陷:
codekoala的这个使用os。这是PyCrypto不鼓励的。
此外,我给函数的键不能保证具有预期的确切长度。我要怎么做才能做到呢?
还有,有几种模式,推荐哪种模式?我不知道用什么:/
最后,静脉注射到底是什么?我是否可以提供不同的IV来加密和解密,或者这将返回不同的结果?
当前回答
你可以使用新的django-mirage-field包。
其他回答
from Crypto import Random
from Crypto.Cipher import AES
import base64
BLOCK_SIZE=16
def trans(key):
return md5.new(key).digest()
def encrypt(message, passphrase):
passphrase = trans(passphrase)
IV = Random.new().read(BLOCK_SIZE)
aes = AES.new(passphrase, AES.MODE_CFB, IV)
return base64.b64encode(IV + aes.encrypt(message))
def decrypt(encrypted, passphrase):
passphrase = trans(passphrase)
encrypted = base64.b64decode(encrypted)
IV = encrypted[:BLOCK_SIZE]
aes = AES.new(passphrase, AES.MODE_CFB, IV)
return aes.decrypt(encrypted[BLOCK_SIZE:])
PyCrypto已经过时了。
如今,密码学有了更好的支持。
这是另一个实现。注意,这将返回字节,您需要使用base64将它们转换为用于传输的字符串。
import os
import hashlib
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
_BLOCK_SIZE = 16
class AesStringCipher:
def __init__(self, key):
self._key = hashlib.sha256(key.encode()).digest()
def encrypt_str(self, raw:str) -> bytes:
iv = os.urandom(_BLOCK_SIZE)
cipher = Cipher(algorithms.AES(self._key), modes.CBC(iv), default_backend())
encryptor = cipher.encryptor()
raw = _pad(raw)
return iv + encryptor.update(raw.encode('utf-8')) + encryptor.finalize()
def decrypt_str(self, enc:bytes) -> str:
iv = enc[:_BLOCK_SIZE]
enc = enc[_BLOCK_SIZE:]
cipher = Cipher(algorithms.AES(self._key), modes.CBC(iv), default_backend())
decryptor = cipher.decryptor()
raw = decryptor.update(enc) + decryptor.finalize()
raw = raw.decode('utf-8')
return _unpad(raw)
def _pad(s:str) -> str:
padding = (_BLOCK_SIZE - (len(s) % _BLOCK_SIZE))
return s + padding * chr(padding)
def _unpad(s:str) -> str:
return s[:-ord(s[len(s)-1:])]
if __name__ == '__main__':
cipher = AesStringCipher('my secret password')
secret_msg = 'this is a super secret msg ...'
enc_msg = cipher.encrypt_str(secret_msg)
dec_msg = cipher.decrypt_str(enc_msg)
assert secret_msg == dec_msg
这是另一种观点(主要源自上述解决方案),但是
uses null for padding does not use lambda (never been a fan) tested with python 2.7 and 3.6.5 #!/usr/bin/python2.7 # you'll have to adjust for your setup, e.g., #!/usr/bin/python3 import base64, re from Crypto.Cipher import AES from Crypto import Random from django.conf import settings class AESCipher: """ Usage: aes = AESCipher( settings.SECRET_KEY[:16], 32) encryp_msg = aes.encrypt( 'ppppppppppppppppppppppppppppppppppppppppppppppppppppppp' ) msg = aes.decrypt( encryp_msg ) print("'{}'".format(msg)) """ def __init__(self, key, blk_sz): self.key = key self.blk_sz = blk_sz def encrypt( self, raw ): if raw is None or len(raw) == 0: raise NameError("No value given to encrypt") raw = raw + '\0' * (self.blk_sz - len(raw) % self.blk_sz) raw = raw.encode('utf-8') iv = Random.new().read( AES.block_size ) cipher = AES.new( self.key.encode('utf-8'), AES.MODE_CBC, iv ) return base64.b64encode( iv + cipher.encrypt( raw ) ).decode('utf-8') def decrypt( self, enc ): if enc is None or len(enc) == 0: raise NameError("No value given to decrypt") enc = base64.b64decode(enc) iv = enc[:16] cipher = AES.new(self.key.encode('utf-8'), AES.MODE_CBC, iv ) return re.sub(b'\x00*$', b'', cipher.decrypt( enc[16:])).decode('utf-8')
请看mnothic的回答。
兼容UTF-8编码:
def _pad(self, s):
s = s.encode()
res = s + (self.bs - len(s) % self.bs) * chr(self.bs - len(s) % self.bs).encode()
return res
您可以使用类似PKCS#7填充的方案。您可以使用它来代替前面的函数来填充(进行加密时)和解封(进行解密时)。我将在下面提供完整的源代码。
import base64
import hashlib
from Crypto import Random
from Crypto.Cipher import AES
import pkcs7
class Encryption:
def __init__(self):
pass
def Encrypt(self, PlainText, SecurePassword):
pw_encode = SecurePassword.encode('utf-8')
text_encode = PlainText.encode('utf-8')
key = hashlib.sha256(pw_encode).digest()
iv = Random.new().read(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
pad_text = pkcs7.encode(text_encode)
msg = iv + cipher.encrypt(pad_text)
EncodeMsg = base64.b64encode(msg)
return EncodeMsg
def Decrypt(self, Encrypted, SecurePassword):
decodbase64 = base64.b64decode(Encrypted.decode("utf-8"))
pw_encode = SecurePassword.decode('utf-8')
iv = decodbase64[:AES.block_size]
key = hashlib.sha256(pw_encode).digest()
cipher = AES.new(key, AES.MODE_CBC, iv)
msg = cipher.decrypt(decodbase64[AES.block_size:])
pad_text = pkcs7.decode(msg)
decryptedString = pad_text.decode('utf-8')
return decryptedString
import StringIO
import binascii
def decode(text, k=16):
nl = len(text)
val = int(binascii.hexlify(text[-1]), 16)
if val > k:
raise ValueError('Input is not padded or padding is corrupt')
l = nl - val
return text[:l]
def encode(text, k=16):
l = len(text)
output = StringIO.StringIO()
val = k - (l % k)
for _ in xrange(val):
output.write('%02x' % val)
return text + binascii.unhexlify(output.getvalue())