数据损坏:错误在哪里‽

时间:2010-12-15 15:58:22

标签: python mcrypt cython python-extensions

上次修改:我已经弄明白问题是什么(请参阅下面我自己的答案),但我无法将问题标记为已回答的问题。如果有人可以回答我在下面的答案中提出的问题,也就是说,这是Cython中的错误还是Cython的预期行为,我会将 答案标记为已接受,因为这将是最有用的从这里得到的教训,恕我直言。


首先,我必须首先说我已经试图解决这个问题三天了,而我只是把头靠在墙上。从文档中我可以看出,我正在做正确的事情。显然,我不能正确地做事,因为如果我这样做,我就不会有问题(对吧?)。

无论如何,我正在为mcrypt绑定到Python。它应该适用于Python 2和Python 3(虽然它未经Python 2测试)。它可用on my site链接,因为它太大而无法包含在帖子中,并且鉴于我不知道我做错了什么我甚至无法隔离可能是什么问题代码。显示问题的脚本是also on my site。该脚本只提供100个块,只有字母“a”(无论加密算法/加密模式使用的块大小),当然应该得到一个“a”块作为往返的结果。但它(不总是)。这是一次运行的输出:

Wed Dec 15 10:35:44 EST 2010
test.py:5: McryptSecurityWarning: get_key() is not recommended
  return ''.join(['{:02x}'.format(x) for x in o.get_key()])

key: b'\x01ez\xd5\xa9\xf9\x1f)\xa0G\xd2\xf2Z\xfc{\x7fn\x02?,\x08\x1c\xc8\x03\x061X\xb5\xc9\x99\xd0\xca'
key: b'\x01ez\xd5\xa9\xf9\x1f)\xa0G\xd2\xf2Z\xfc{\x7fn\x02?,\x08\x1c\xc8\x03\x061X\xb5\xc9\x99\xd0\xca'
16
self test result: 0
enc parameters: {'salt': '6162636465666768', 'mode': 'cbc', 'algorithm': 'rijndael-128', 'iv': '61626364616263646162636461626364'}
dec parameters: {'salt': '6162636465666768', 'mode': 'cbc', 'algorithm': 'rijndael-128', 'iv': '61626364616263646162636461626364'}
enc key: 01657ad5a9f91f29a047d2f25afc7b7f6e023f2c081cc803063158b5c999d0ca
dec key: 01657ad5a9f91f29a047d2f25afc7b7f6e023f2c081cc803063158b5c999d0ca
Stats: 88 / 100 good packets (88.0%)

#5: b'aaaaaaaaaaaaaaaa' != b'\xa6\xb8\xf9\td\x8db\xf6\x00Y"ST\xc6\x9b\xe7'
#6: b'aaaaaaaaaaaaaaaa' != b'aaaaaaa1\xb3@\x8d\xff\xf9\xafpy'
#13: b'aaaaaaaaaaaaaaaa' != b'\xb9\xc8\xaf\x1f\xb8\x8c\x0b_\x15s\x9d\xecN,*w'
#14: b'aaaaaaaaaaaaaaaa' != b'aaaaaaaaaaaaa\xeb?\x13'
#49: b'aaaaaaaaaaaaaaaa' != b'_C\xf2\x15\xd5k\xe1XKIF5k\x82\xa4\xec'
#50: b'aaaaaaaaaaaaaaaa' != b'aaaaaaaaaaa+\xdf>\x01\xee'
#74: b'aaaaaaaaaaaaaaaa' != b'\x1c\xdf0\x05\xc7\x0b\xe9\x93H\xc5B\xd7\xcfj+\x03'
#75: b'aaaaaaaaaaaaaaaa' != b'aaaaaaaaaaaaw+\xed\x0f'
#79: b'aaaaaaaaaaaaaaaa' != b"\xf2\x89\x1ct\xe1\xeeBWo\xb4-\xb9\x085'\xef"
#80: b'aaaaaaaaaaaaaaaa' != b'aaaaaaaaaaa\xcc\x01n\xf0<'
#91: b'aaaaaaaaaaaaaaaa' != b'g\x02\x08\xbf\xa5\xd7\x90\xc1\x84D\xf3\x9d$a)\x06'
#92: b'aaaaaaaaaaaaaaaa' != b'aaaaaaaaaaaaaaa\x01'

奇怪的是,对于给定的(算法,模式)对,完全相同。我可以改变算法,它将导致不同的往返,但是当我不改变算法时,每次运行总是相同的。我绝对难过。此外,它总是连续两个块被破坏,你可以在上面的输出中看到:块5和6,13和14等。所以,有一个模式,但我,无论出于何种原因,无法弄清楚这种模式究竟指向了什么。

我意识到我可能在这里要求很多:我无法隔离一小段代码,并且可能需要熟悉mcrypt和Python。唉,经过三天的打击,我需要稍稍离开这个问题,所以我在这里张贴这个希望,也许在我从这个问题中休息时(a)某人我会看到我在哪里引入了一个bug,(b)当我稍后回到问题时,我将能够看到我的错误,或者(c)某人或我自己可以找到可能不是我的代码中的错误的问题但是绑定过程中的错误或库本身。

我还没做过的一件事就是尝试使用另一个版本的mcrypt库。我正在使用Cython 0.13,Python 3.1和mcrypt 2.5.8进行工作,所有这些都是由Ubuntu在Ubuntu 10.10中分发的(除了Cython,我从PyPi获得)。但我管理系统的PHP应用程序运行正常并在Ubuntu 10.10上使用mcrypt而没有数据损坏,所以我没有理由相信它是mcrypt的构建,所以只留下......好吧,我的某些地方出了问题,我想。

无论如何,我非常感谢能够提供帮助的人。我开始觉得我疯了,因为我几天不停地研究这个问题,我感觉解决方案可能就在我面前,但是我看不到它。

编辑:有人指出我应该使用memcpy而不是strncpy。我这样做了,但现在,测试脚本显示每个块都不正确。让我比以前更加困惑......这是新输出on pastebin

编辑2 :我已经回到计算机并再次查看它,我只是在各处添加打印语句以找出问题所在。 raw_encrypt.step(输入)函数中的以下代码:

    cdef char* buffer = <char*>malloc(in_len)
    print in_bin[:in_len]
    memcpy(buffer, <const_void *>in_bin, in_len)
    print "Before/after encryption"
    print buffer[:in_len]
    success = cmc.mcrypt_generic(self._mcStream, <void*>buffer, in_len)
    print buffer[:in_len]

第一个print语句显示了预期的东西,即传入的明文。但是,第二个显示完全不同的东西,它应该是相同的。似乎Cython还有一些我不完全理解的事情。

2 个答案:

答案 0 :(得分:2)

哦,我讨厌这样做(回答我自己的问题),但我找到答案:这是Cython的一个怪癖,我将不得不调查(我不知道这是否是一个预定的怪癖,或者如果它是一个bug)。

问题在于memcpy行。我将第二个参数转换为&lt; const_void *&gt;,它与pxd文件中的Cython定义匹配,但显然这使得Cython编译代码的方式与使用&lt; char *&gt;不同,后者强制Cython传递指针实际的字节而不是(我猜?)指向Python对象/变量本身的指针。

所以,而不是:

cdef char* buffer = <char*>malloc(in_len)
memcpy(buffer, <const_void *>in_bin, in_len)
success = cmc.mcrypt_generic(self._mcStream, <void*>buffer, in_len)

需要这样:

cdef char* buffer = <char*>malloc(in_len)
memcpy(buffer, <char *>in_bin, in_len)
success = cmc.mcrypt_generic(self._mcStream, <void*>buffer, in_len)

多么奇怪的怪癖。老实说,我希望任何一个演员指向相同的位置,但似乎演员也会影响行为。

答案 1 :(得分:0)

当使用错误的初始化向量(即使用不同的IV进行加密而不是解密)和Ciphermode选择的组合发生了一些有趣的事情时,我遇到了与此类似的结果。作为一个完整性检查,尝试从CBC切换到ECB。

另一种可能性是你的一个变量被随机化(使用新的基于时间的种子),而不应该是。在这种情况下,您可以通过在加密和解密步骤之间设置延迟来更频繁地导致数据损坏。