A-A+

Python Crypto AES加密模式踩坑记

2021年04月10日 23:20 汪洋大海 暂无评论 共2798字 (阅读281 views次)

前言:

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一个对象用来处理解密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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)
 
#can't use same object to decrypt
plaintext=cipher.decrypt(cipherText)  #注意这里,因为引用同一对象会导致报错!!!
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加密

# Size of a data block (in bytes)
block_size = 16
# Size of a key (in bytes)
key_size = (16, 24, 32)
解决方法就是将需要加密的数据Padding到16Byte的整数倍;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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')  ##注意这里,text需要加密的字符串需要是16字节的整数倍
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会在初始化时随机生成一个。这样就导致了每次加密得到的密文不一样;
解决方法就是指定一个固定的初始化向量,同时也要注意解密时也使用同样的向量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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得到原始数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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'

文章来源:https://www.cnblogs.com/linuxcat/p/14494630.html

布施恩德可便相知重

微信扫一扫打赏

支付宝扫一扫打赏

×

给我留言