0

I have the following 2 values : AES key it is a Java array of bytes

64,67,-65,88,-19,-118,-16,-53,-81,-98,44,-83,82,-90,124,112,-120,42,92,67,104,23,44,8,2,-96,-106,-28,57,99,76,73

IV also a Java array of bytes

50,52,3,36,-90,81,109,-56,24,122,-3,27,-96,56,118,-60

The encryption mode is : AES/CBC/PKCS5PADDING

Now I need to use these 2 values to decrypt my cipher text using python. I am trying to use pycrypto but am open on exploring other options as well. Now because Java's array of bytes is signed and (it looks like) python (2.7) does not recognize signed array of bytes, I am having trouble doing this decryption.

I did find a bunch of SO discussions around similar topics, but most of them were generating the IV and the key, and not really using an already existing one, for eg.

So the above solutions have not worked for me, unless I did something fundamentally wrong while tweaking them for my need.

Here's one of my attempts (bits and pieces taken from the SO discussions mentioned above)

from Crypto import Random
from Crypto.Cipher import AES
import base64

key = 
[64,67,-65,88,-19,-118,-16,-53,-81,-98,44,-83,82,-90,124,112,-120,42,92,67,104,23,44,8,2,-96,-106,-28,57,99,76,73]

iv = [50,52,3,36,-90,81,109,-56,24,122,-3,27,-96,56,118,-60]

aes_key = ''.join(map(lambda x: chr(x % 256), key))
iv_data = ''.join(map(lambda x: chr(x % 256), iv))

def pad(s):
  return s + b"\0" * (AES.block_size - len(s) % AES.block_size)

def decrypt(ciphertext, key):
  ciphertext = base64.b64decode(ciphertext)
  iv = ciphertext[:AES.block_size]
  cipher = AES.new(key, AES.MODE_CBC, iv)
  plaintext = cipher.decrypt(ciphertext[AES.block_size:])
  return plaintext.rstrip(b"\0")  

And then calling decrypt() as :

decrypt('HaCiIld192v2QE3/zcuAxhpr39HRXvsHQYSJE/VT9FuWWK7envVDRaaDR6gpmh0zmw09/440O7UAtVb5qBLddZH37TASWUMXAN0Idy7B0VtpgPgMHOLGJG6axWCHgieaTleFDaRKP+z7WN+4fj5RGw==', aes_key)

gives the output as :

Out[9]: '\xdd\x99\xab\x8bI\xcb\xf0?\xcd\x1c\x1eb\x109\xe8c\xc0\x105\xa6\xdb\xe4\xdb\x08\xc7\xdbHT\x08.\x10\x9e\xe1g\xfe\xd1\xc2\x92\xdbH\x8e\x9bV\xae^\r:\x98%\x8d\x06\xdf\xaf\t\xb5m\xfb\xf3Q+s"CK\xf4\xc2\xe7\xd2\xfd\xfdq\xcc)\xcf\x99&\xffj\xc4\xc1\x1a$ML\xe9\xe7(\xef\x1c\x81vx\xf56'

I tried :

a = b'\xdd\x99\xab\x8bI\xcb\xf0?\xcd`\x1c\x1eb\x109\xe8c\xc0\x105\xa6\xdb\xe4\xdb\x08\xc7\xdbHT\x08.\x10\x9e\xe1g\xfe\xd1\xc2\x92\xdbH\x8e\x9bV\xae^\r:\x98%\x8d\x06\xdf\xaf\t\xb5m\xfb\xf3Q+`s"CK\xf4\xc2\xe7\xd2\xfd\xfdq\xcc)\xcf\x99&\xffj\xc4\xc1\x1a$ML\xe9\xe7(\xef\x1c\x81vx\xf56'

a.encode("hex")

and output is :

'dd99ab8b49cbf03fcd601c1e621039e863c01035a6dbe4db08c7db4854082e109ee167fed1c292db488e9b56ae5e0d3a98258d06dfaf09b56dfbf3512b607322434bf4c2e7d2fdfd71cc29cf9926ff6ac4c11a244d4ce9e728ef1c817678f536'

which is definitely not the plain text I was expecting. So I need help figuring this out, as to how can I decrypt (using Python 2.7) an AES encrypted cipher text given the key and IV as Java array of bytes?

As per suggestions in the comments below (@MaartenBodewes thanks) I tried this :

So, I checked the base64 of the bytearray, key, in java as :

byte arr[] = new byte[] {64,67,-65,88,-19,-118,-16,-53,-81,-98,44,-83,82,-90,124,112,-120,42,92,67,104,23,44,8,2,-96,-106,-28,57,99,76,73};
String base64 = new String(Base64.encodeBase64(arr)); 

and then to achieve the same in python did some changes to python code above to do the same as : (I realized that java treats a byte array as an array of signed 2s complement data, from an excellent discussion at Java byte array contains negative numbers, and so had to accommodate for that in python)

key = [64,67,-65,88,-19,-118,-16,-53,-81,-98,44,-83,82,-90,124,112,-120,42,92,67,104,23,44,8,2,-96,-106,-28,57,99,76,73]
b64encode(bytearray([(lambda x:int((bin(x & 0xff)),2))(x) for x in key]))

and both these resulted in the same output as :

QEO/WO2K8MuvniytUqZ8cIgqXENoFywIAqCW5DljTEk=

And I thought that not that I am sure that both these keys (Java and python) are the same, the decryption should work. And hence I tried once again:

decrypt('HaCiIld192v2QE3/zcuAxhpr39HRXvsHQYSJE/VT9FuWWK7envVDRaaDR6gpmh0zmw09/440O7UAtVb5qBLddZH37TASWUMXAN0Idy7B0VtpgPgMHOLGJG6axWCHgieaTleFDaRKP+z7WN+4fj5RGw==', str(aes_key))

And I got the exact same output as earlier:

'\xdd\x99\xab\x8bI\xcb\xf0?\xcd\x1c\x1eb\x109\xe8c\xc0\x105\xa6\xdb\xe4\xdb\x08\xc7\xdbHT\x08.\x10\x9e\xe1g\xfe\xd1\xc2\x92\xdbH\x8e\x9bV\xae^\r:\x98%\x8d\x06\xdf\xaf\t\xb5m\xfb\xf3Q+s"CK\xf4\xc2\xe7\xd2\xfd\xfdq\xcc)\xcf\x99&\xffj\xc4\xc1\x1a$ML\xe9\xe7(\xef\x1c\x81vx\xf56'

10
  • 2
    There are no negative values in a byte array. They are just an interpretation of the data, mostly when the first bit is 1. So, you will have to check if the representation fits your conversion or in other word if the `% 256 properly reverts the array to right bytes. Commented Jun 26, 2017 at 8:22
  • Thanks for the suggestion. Could you please explain how exactly can I verify this ? I mean I do not really know what the right bytes would be. Commented Jun 26, 2017 at 8:40
  • 1
    You're not doing PKCS#5 (or, for AES, PKCS#7 padding) you are zero padding your plaintext in PHP. Compare the key and IV and plaintext in hexadecimals or base 64 by using a print statement or suchlike for both PHP and Java. If there are differences you know what went wrong. Note that to print hexadecimals in Java you may need extra code. Java inexplicably doesn't contain a hex encoder for byte arrays. Commented Jun 26, 2017 at 8:40
  • @qre0ct Well, you have to know how the keys and IV got exported. You did not show that above. Commented Jun 26, 2017 at 8:43
  • Sorry for the insult to Python here, I mean "Python", not "PHP". Commented Jun 26, 2017 at 9:52

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.