第二次解密时AES解密失败
AES decryption fails when decrypting a second time
我有这个可逆编码的实现:
# coding=utf-8
from Crypto.Cipher import AES
from Crypto import Random
import uuid
import unittest
import random
key = r'Sixteen byte key' # Keep this real secret
iv = Random.new().read(AES.block_size)
cipher = AES.new(key, AES.MODE_CFB, iv)
def encode(role, plaintext):
'''Encode the message, prefix with the role specifier'''
msg = iv + cipher.encrypt(plaintext)
msg = msg.encode('hex')
msg = role + '-' + msg
return msg
def decode(msg):
'''Decode message, return role and plaintext'''
role, msg = msg.split('-', 1)
plaintext = cipher.decrypt(msg.decode('hex'))[len(iv):]
return role, plaintext
class TestMe(unittest.TestCase):
def test_whole(self):
ROLES = ['sales', 'vendor', 'designer']
for _ in xrange(100):
role = random.choice(ROLES)
txt = uuid.uuid4().hex
msg = encode(role, txt)
drole, dtxt = decode(msg)
self.assertEqual(role, drole)
self.assertEqual(txt, dtxt)
print 'ok'
if __name__ == '__main__':
unittest.main()
但这是失败的,总是在第二轮测试中。我在做一些明显错误的事情,但我不知道是什么。
备注
您需要:
pip install pycrypto
到运行那个代码
代码失败:
» python test.py
ok
F
======================================================================
FAIL: test_whole (__main__.TestMe)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test.py", line 40, in test_whole
self.assertEqual(txt, dtxt)
AssertionError: 'b2e7894dd6254b259ae06350f199e6a2' != '\xa7\xcd\t\xde~\x15\xce\x9d\xcfU\x8f\xb2\xfa\x08\x98\x1c9ae06350f199e6a2'
----------------------------------------------------------------------
Ran 1 test in 0.000s
FAILED (failures=1)
错误消息提供了有关正在发生的事情的重要线索。如您所见,解密消息的前 16 个字节不同,但接下来的 16 个字节相同。当密钥正确但 IV 不正确时会发生这种情况。
问题似乎是 pyCrypto 没有在 encryption/decryption 之后重置密码状态,而 IV 是其他值。
无论哪种方式,您都不应该设置一次 IV 并多次重复使用它。 IV是为了提供密文的随机化,使得观察密文的攻击者无法确定加密的明文是否重复。
将 AES 对象创建移到函数中,解决了这个问题:
key = r'Sixteen byte key' # Keep this real secret
def encode(role, plaintext):
'''Encode the message, prefix with the role specifier'''
iv = Random.new().read(AES.block_size)
cipher = AES.new(key, AES.MODE_CFB, iv)
msg = iv + cipher.encrypt(plaintext)
msg = msg.encode('hex')
msg = role + '-' + msg
return msg
def decode(msg):
'''Decode message, return role and plaintext'''
role, msg = msg.split('-', 1)
msg = msg.decode('hex')
iv = msg[:AES.block_size]
cipher = AES.new(key, AES.MODE_CFB, iv)
plaintext = cipher.decrypt(msg[AES.block_size:])
return role, plaintext
您应该查看 pyCrypto 的 2.7-alpha 版本,其中包括经过身份验证的模式,例如 GCM、EAX、SIV。密文身份验证很重要,因为可能会在您的系统中使用填充 oracle 攻击来解密任何密文。
我有这个可逆编码的实现:
# coding=utf-8
from Crypto.Cipher import AES
from Crypto import Random
import uuid
import unittest
import random
key = r'Sixteen byte key' # Keep this real secret
iv = Random.new().read(AES.block_size)
cipher = AES.new(key, AES.MODE_CFB, iv)
def encode(role, plaintext):
'''Encode the message, prefix with the role specifier'''
msg = iv + cipher.encrypt(plaintext)
msg = msg.encode('hex')
msg = role + '-' + msg
return msg
def decode(msg):
'''Decode message, return role and plaintext'''
role, msg = msg.split('-', 1)
plaintext = cipher.decrypt(msg.decode('hex'))[len(iv):]
return role, plaintext
class TestMe(unittest.TestCase):
def test_whole(self):
ROLES = ['sales', 'vendor', 'designer']
for _ in xrange(100):
role = random.choice(ROLES)
txt = uuid.uuid4().hex
msg = encode(role, txt)
drole, dtxt = decode(msg)
self.assertEqual(role, drole)
self.assertEqual(txt, dtxt)
print 'ok'
if __name__ == '__main__':
unittest.main()
但这是失败的,总是在第二轮测试中。我在做一些明显错误的事情,但我不知道是什么。
备注
您需要:
pip install pycrypto
到运行那个代码
代码失败:
» python test.py
ok
F
======================================================================
FAIL: test_whole (__main__.TestMe)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test.py", line 40, in test_whole
self.assertEqual(txt, dtxt)
AssertionError: 'b2e7894dd6254b259ae06350f199e6a2' != '\xa7\xcd\t\xde~\x15\xce\x9d\xcfU\x8f\xb2\xfa\x08\x98\x1c9ae06350f199e6a2'
----------------------------------------------------------------------
Ran 1 test in 0.000s
FAILED (failures=1)
错误消息提供了有关正在发生的事情的重要线索。如您所见,解密消息的前 16 个字节不同,但接下来的 16 个字节相同。当密钥正确但 IV 不正确时会发生这种情况。
问题似乎是 pyCrypto 没有在 encryption/decryption 之后重置密码状态,而 IV 是其他值。
无论哪种方式,您都不应该设置一次 IV 并多次重复使用它。 IV是为了提供密文的随机化,使得观察密文的攻击者无法确定加密的明文是否重复。
将 AES 对象创建移到函数中,解决了这个问题:
key = r'Sixteen byte key' # Keep this real secret
def encode(role, plaintext):
'''Encode the message, prefix with the role specifier'''
iv = Random.new().read(AES.block_size)
cipher = AES.new(key, AES.MODE_CFB, iv)
msg = iv + cipher.encrypt(plaintext)
msg = msg.encode('hex')
msg = role + '-' + msg
return msg
def decode(msg):
'''Decode message, return role and plaintext'''
role, msg = msg.split('-', 1)
msg = msg.decode('hex')
iv = msg[:AES.block_size]
cipher = AES.new(key, AES.MODE_CFB, iv)
plaintext = cipher.decrypt(msg[AES.block_size:])
return role, plaintext
您应该查看 pyCrypto 的 2.7-alpha 版本,其中包括经过身份验证的模式,例如 GCM、EAX、SIV。密文身份验证很重要,因为可能会在您的系统中使用填充 oracle 攻击来解密任何密文。