Python Crypto AES加密模式踩坑记
前言:
demo code使用的lib 版本为 :pycryptodome 3.10.1
写了一小段AES加密的demo code, 运行起来错误不断,花费了半天时间逐一解决。分享出来,希望能对大家有所帮助!
同时,关于AES 加密模式的说明可以参考这篇文章,讲的很清晰:https://blog.csdn.net/slslslyxz/article/details/111232040
问题一:decrypt() cannot be called after encrypt()
运行时报告:Exception has occurred: TypeError, decrypt() cannot be called after encrypt()
出现这个问题的原因,在encrypt / decrypt函数中有说明,由于encrypt / decrypt是stateful,不能用加密的对象再去解蜜;
A cipher object is stateful: once you have encrypted a message , you cannot encrypt (or decrypt) another message using the same object.
解决方法就是重新new一个对象用来处理解密
from Crypto.Cipher import AES from Crypto.Util.Padding import pad from Crypto.Util.Padding import unpad key=b'1234567890123456'cipher=AES.new(key,AES.MODE_CBC) text=b'secret text' padtext=pad(text,16,style='pkcs7') cipherText=cipher.encrypt(padtext) print(padtext) print(cipherText) plaintext=cipher.decrypt(cipherText) #can't use same object to decrypt print(plaintext)
问题二:Data must be padded to 16 byte boundary in CBC mode
这个是AES加密算法模式导致的。 AES只能以Block的模式加密, 且Block大小为16Byte. 加密的key大小为:16,24,32,对应到128bit, 192bit, 256bit加密
from Crypto.Cipher import AES from Crypto.Util.Padding import pad from Crypto.Util.Padding import unpad key=b'1234567890123456'cipher=AES.new(key,AES.MODE_CBC) text=b'secret text' padtext=pad(text,16,style='pkcs7') cipherText=cipher.encrypt(padtext) print(padtext) print(cipherText) decrypter=AES.new(key,AES.MODE_CBC) plaintext=decrypter.decrypt(cipherText) print(plaintext)
问题三:每次加密得到的结果不一样
这个问题的原因是AES CBC_MODE需要初始化向量。如果不指定初始化向量,则AES会在初始化时随机生成一个。这样就导致了每次加密得到的密文不一样;
解决方法就是指定一个固定的初始化向量,同时也要注意解密时也使用同样的向量。
from Crypto.Cipher import AES from Crypto.Util.Padding import pad from Crypto.Util.Padding import unpad key=b'1234567890123456' iv=b'abcdefghijklmnop' cipher=AES.new(key,AES.MODE_CBC,iv) text=b'secret text' padtext=pad(text,16,style='pkcs7') cipherText=cipher.encrypt(padtext) print(padtext) print(cipherText) decrypter=AES.new(key,AES.MODE_CBC,iv) plaintext=decrypter.decrypt(cipherText) print(plaintext)
问题四:解密无法得到原始明文数据
上面的程序运行出来发现后面还是跟着之前Paddding的数据,这是因为decrypt并不会将Padding的数据去掉。
解决办法就是将解密的数据再进行unpad得到原始数据
from Crypto.Cipher import AES from Crypto.Util.Padding import pad from Crypto.Util.Padding import unpad key=b'1234567890123456' iv=b'abcdefghijklmnop' cipher=AES.new(key,AES.MODE_CBC,iv) text=b'secret text' padtext=pad(text,16,style='pkcs7') cipherText=cipher.encrypt(padtext) print(padtext) print(cipherText) decrypter=AES.new(key,AES.MODE_CBC,iv) plaintext=decrypter.decrypt(cipherText) unpadtext=unpad(plaintext,16,'pkcs7') print(plaintext) print(unpadtext)
经过上面的一系列的错误修正后,运行程序后可以得到正确的结果了
原始数据:secret text padding数据:b'secret text\x05\x05\x05\x05\x05' 加密数据:b'\xb0\xb0\xd4h\xbc\x85\xd3\xd1>\x13\xdf\xa7AE(8' 解密后数据:b'secret text'