第二次解密时,AES解密失败

时间:2015-10-30 09:36:49

标签: python encryption pycrypto

我有一个可逆编码的实现:

# 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)

1 个答案:

答案 0 :(得分:2)

错误消息提供了有关正在发生的事情的重要线索。如您所见,解密消息的前16个字节不同,但接下来的16个字节是相同的。当密钥正确时会发生这种情况,但IV不是。

问题似乎是pyCrypto在加密/解密后没有重置密码的状态,而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攻击来解密任何密文。