3

I have data that was encrypted in PHP as follows:

mcrypt_encrypt(MCRYPT_RIJNDAEL_256, SECRET, $data, MCRYPT_MODE_CBC, $iv)

I need to decrypt this data in a Python 3 application. I am trying to use PyCrypto but I am open to other libraries. I expect the following to work:

decryptor = AES.new(key, mode, IV=IV)
plain = decryptor.decrypt(ciphertext)

My initialization vector is 32 bytes, and the following exception is thrown:

ValueError: IV must be 16 bytes long

How can I set PyCrypto to use a 32 byte initialization vector and 32 byte block size? Alternatively, is there a different library that I can use to decrypt the data?

gavinmh
  • 257
  • 4
  • 9
  • 1
    You can't set AES to 32 byte block size, because AES is only defined for 16 byte block size. You have to find a Rijndael 256/256 (assuming your key is also 32 bytes long) implementation for python. – Artjom B. Dec 06 '14 at 17:15
  • 1
    possible duplicate of [Python equivalent of PHP's MCRYPT\_RIJNDAEL\_256 CBC](http://stackoverflow.com/questions/8356689/python-equivalent-of-phps-mcrypt-rijndael-256-cbc). Always fun to see your own answers in a Google search. – Maarten Bodewes Dec 06 '14 at 17:44
  • Thanks. That appears to implement the block cipher, but not the CBC encryption mode. Is there an implementation of CBC that I can use with my 32-byte initialization vectors? – gavinmh Dec 07 '14 at 01:44
  • It's not that hard to implement CBC and as it is mostly XORing there is little risk of side channel attacks on the mode. PHP padding mode is adding 0..15 zeros till you reach block size. – Maarten Bodewes Dec 07 '14 at 02:19

1 Answers1

0

Thanks to the comments I implemented a suitable solution. I modified rijndael.py in the linked duplicate question to accept bytes rather than strings. I then use it as follows to decrypt 32-byte blocks with the 32-byte initialization vectors.

from rijndael import rijndael

iv = b'myInitializationVectorfoobarfoob'
key = b'myKeyfoobarfoobarfoobarfoobarfoo'
text = b'myCipherTextFoobarfoobarfoobarfo'

r = rijndael(key, block_size=32)
plaintext = r.decrypt(text)
l = ''.join([chr(a ^ b) for a, b in zip(plaintext.encode('latin-1'), iv)])
print(l)

Note that using this rather than PyCrypto is only necessary because libmcrypt incorrectly sets the data block sizes, and thus the initialization vector sizes, to be equal to the key sizes. As far as I understand, data block sizes should always be 128 bits for AES-Rijndael.

gavinmh
  • 257
  • 4
  • 9