Python Crypto.Cipher加密包
The Crypto.Cipher package contains algorithms for protecting the confidentiality of data.
Crypto.Cipher包含保护机密数据的加密算法。
Installation(安装)
an almost drop-in replacement for the old PyCrypto library. You install it with:
替换旧版本PyCrypto库安装pip install pycryptodome
a library independent of the old PyCrypto. You install it with:
独立于旧版本PyCrypto库的安装pip install pycryptodomex
Introduction(介绍)
There are three types of encryption algorithms:
Crypto.Cipher包含三种加密算法
Symmetric ciphers: all parties use the same key, for both decrypting and encrypting data. Symmetric ciphers are typically very fast and can process very large amount of data.
对称加密算法:加解密数据使用同一秘钥,对称加密算法速度极快,能够快速处理非常庞大的数据。Asymmetric ciphers: senders and receivers use different keys. Senders encrypt with public keys (non-secret) whereas receivers decrypt with private keys (secret). Asymmetric ciphers are typically very slow and can process only very small payloads. Example: PKCS#1 OAEP (RSA).
非对称加密算法:发送者与接收者使用不同的秘钥,发送者使用公钥(非密)加密而接收者使用私钥解密。非对称加密算法速度很慢,只能够处理非常少的有效载荷(数据)。例如PKCS#1 OAEP (RSA)。Hybrid ciphers: the two types of ciphers above can be combined in a construction that inherits the benefits of both. An asymmetric cipher is used to protect a short-lived symmetric key, and a symmetric cipher (under that key) encrypts the actual message.
混合型加密算法:结合以上两种加密算法的优势。非对称加密算法经常被用来保护短活的对称秘钥,对称加密算法(使用对称秘钥)加密真实的信息。
基本的cipher API
You instantiate a cipher object by calling the new() function from the relevant cipher module (e.g. Crypto.Cipher.AES.new()). The first parameter is always the cryptographic key; its length depends on the particular cipher. You can (and sometimes must) pass additional cipher- or mode-specific parameters to new() (such as a nonce or a mode of operation).
通过从相关的cipher模块中调用new()函数实例化一个cipher对象(e.g. Crypto.Cipher.AES.new()),第一个参数是秘钥,长度取决于具体的加密算法,也可以(有时必须)传递额外的参数(随机数或者操作模式)
For encrypting, you call the encrypt() method of the cipher object with the plaintext. The method returns the piece of ciphertext. For most algorithms, you may call encrypt() multiple times (i.e. once for each piece of plaintext).
加密的时候直接调用实例的encrypt()方法,传递明文文本参数,结果返回一段加密文本,对于大多数的算法,可以多次调用encrypt()方法(例如对于每个片段调用一次)
For decrypting, you call the decrypt() method of the cipher object with the ciphertext. The method returns the piece of plaintext. For most algorithms, you may call decrypt() multiple times (i.e. once for each piece of ciphertext).
解密的时候直接调用decrypt(),传递明文文本参数,结果返回一段明文文本,对于大多数的算法,可以多次调用decrypt()方法(例如对于每个片段调用一次)
一个最基本的例子
注意
Plaintexts and ciphertexts (input/output) are all byte strings. An error will occur with Python 3 strings, Python 2 Unicode strings, or byte arrays.
明文与加密文本(输入输出)都是字节字符,对于python3字符或者python2 Unicode字符或者字节数组会发生错误。
更过的例子
Salsa20 is a stream cipher designed by Daniel J. Bernstein. The secret key is by preference 256 bits long, but it can also work with 128 bit keys.
Salsa20是由Daniel J. Bernstein设计的算法,秘钥长度一般是256字节长,但是也支持128位
1.1 通过 Salsa20 加密数据:
>>> from Crypto.Cipher import Salsa20
>>> plaintext = b'Attack at dawn'
>>> secret = b'*Thirty-two byte (256 bits) key*'
>>> cipher = Salsa20.new(key=secret)
>>> msg = cipher.nonce + cipher.encrypt(plaintext)
1.2 通过 Salsa20 解密数据:
>>> from Crypto.Cipher import Salsa20
>>>
>>> secret = b'*Thirty-two byte (256 bits) key*'
>>> msg_nonce = msg[:8]
>>> ciphertext = msg[8:]
>>> cipher = Salsa20.new(key=secret, nonce=msg_nonce)
>>> plaintext = cipher.decrypt(ciphertext)
注意:
Salsa20 does not guarantee authenticity of the data you decrypt! In other words, an attacker may manipulate the data in transit. In order to prevent it, you must couple it with a Message Authentication Code (such as HMAC).
Salsa20并不保证加密数据的保密性,也就是说,攻击者可能在传输中或者数据,为了避免这种情况的发生,就需要使用信息保密代码去力偶数据(如HMAC)
ChaCha20 is a stream cipher designed by Daniel J. Bernstein. The secret key is 256 bits long.
ChaCha20是由Daniel J. Bernstein设计的流算法,秘钥长度为256字节。
2.1 通过 ChaCha20 加密数据:
>>> from Crypto.Cipher import ChaCha20
>>> plaintext = b'Attack at dawn'
>>> secret = b'*Thirty-two byte (256 bits) key*'
>>> cipher = ChaCha20.new(key=secret)
>>> msg = cipher.nonce + cipher.encrypt(plaintext)
2.2 通过 ChaCha20 解密数据:
>>> from Crypto.Cipher import ChaCha20
>>> secret = b'*Thirty-two byte (256 bits) key*'
>>> msg_nonce = msg[:8]
>>> ciphertext = msg[8:]
>>> cipher = ChaCha20.new(key=secret, nonce=msg_nonce)
>>> plaintext = cipher.decrypt(ciphertext)
注意事项同上
AES (Advanced Encryption Standard) is a symmetric block cipher standardized by NIST . It has a fixed data block size of 16 bytes. Its keys can be 128, 192, or 256 bits long.
AES is very fast and secure, and it is the de facto standard for symmetric encryption.
AES (高级/先进加密标准)是一个由NIST标准化的对称的块加密算法。它具有固定的16字节的数据块,秘钥可以是128、192、256位的。AES速度快并且安全,是对称加密的事实标准。
3.1通过 AES 加密数据:
>>> from Crypto.Cipher import AES
>>> key = b'Sixteen byte key'
>>> cipher = AES.new(key, AES.MODE_EAX)
>>>
>>> nonce = cipher.nonce
>>> ciphertext, tag = cipher.encrypt_and_digest(data)
3.2 通过 AES 解密数据:
>>> from Crypto.Cipher import AES
>>> key = b'Sixteen byte key'
>>> cipher = AES.new(key, AES.MODE_EAX, nonce=nonce)
>>> plaintext = cipher.decrypt(ciphertext)
>>> try:
>>> cipher.verify(tag)
>>> print("The message is authentic:", plaintext)
>>> except ValueError:
>>> print("Key incorrect or message corrupted")
最后上一个实用类
from Crypto.Cipher import AES
from binascii import b2a_hex, a2b_hex
class AESEncrypt(object):
def __init__(self, key, key_length=16, allow_null=False):
self.key = key
self.key_length = key_length
# It must be 16 (*AES-128*), 24 (*AES-192*), or 32 (*AES-256*) bytes long.
self.mode = AES.MODE_CBC
self.cryptor = AES.new(self.key, self.mode, self.key)
self.allow_null = allow_null
def encrypt(self, text):
if not isinstance(text, basestring):
raise TypeError("unicode/str objects only")
if len(text) == 0:
if self.allow_null:
return ''
_text = text + ('\0' * (self.key_length - len(text) % self.key_length))
ciphertext = self.cryptor.encrypt(_text)
return b2a_hex(ciphertext)
def decrypt(self, text):
if not isinstance(text, basestring):
raise TypeError("unicode/str objects only")
if len(text) == 0:
if self.allow_null:
return ''
plain_text = self.cryptor.decrypt(a2b_hex(text))
return plain_text.rstrip('\0')
def aes_encrypt(plain_text='', allow_null=False, key=DEFAULT_ENCRYPT_KEY):
assert len(key) == 16, u'key error, The length of the need to 16, not {}'.format(len(key))
return AESEncrypt(key=key, allow_null=allow_null).encrypt(plain_text)
def aes_decrypt(crypt_text='', allow_null=False, key=DEFAULT_ENCRYPT_KEY):
assert len(key) == 16, u'key error, The length of the need to 16, not {}'.format(len(key))
return AESEncrypt(key=key, allow_null=allow_null).decrypt(crypt_text)