Search code examples
pythonlaravelencryptionopensslaes

Encode in Laravel, decode in Python


I'm using Laravel's encryptString method to encrypt some data on my website. This uses OpenSSL's 256-bit AES-CBC encryption without any serialization. I'm now trying to decrypt that data in Python but I keep getting errors about key length and can't seem to figure out why.

Example data to decrypt: eyJpdiI6ImdxY0VcLzFodmpISFV4allSWmJDdEpRPT0iLCJ2YWx1ZSI6IkxXd0ZJaUd2bTUweW5pNm0wUjQwOFM2N1wvWEs5SlYrNB4xNlR7Qkh1U3FvPSIsIm1hYyI6Ijc5ZWM0YTYxYjljZGFiNzgwNjY2NDU1ZmQ5Yjc1ZmJlOGU4NzBkMjQzMzA3MmVhYzE3NzY4ZmU1MWIyMjZlOTQifQ==

Example Key to use for decryption (from laravel .env):
base64:/AZejP0lh3McL/+Vy5yZcADdTcR65qnx5Jqinuw7raK=

I changed those values around so actually decrypting with those values won't give any real data, just figured it'd be good for example. I then try to decrypt this data in Python 3.7 with:

import base64
from Crypto.Cipher import AES

def decrypt(enc, key):
    IV = 16 * '\x00'
    decobj = AES.new(key, AES.MODE_CBC, IV)
    data = decobj.decrypt(base64.b64decode(enc))
    print(str(data.decode()))

if __name__ == "__main__":
    key = b"/AZejP0lh3McL/+Vy5yZcADdTcR65qnx5Jqinuw7raK="
    decrypt("eyJpdiI6ImdxY0VcLzFodmpISFV4allSWmJDdEpRPT0iLCJ2YWx1ZSI6IkxXd0ZJaUd2bTUweW5pNm0wUjQwOFM2N1wvWEs5SlYrNB4xNlR7Qkh1U3FvPSIsIm1hYyI6Ijc5ZWM0YTYxYjljZGFiNzgwNjY2NDU1ZmQ5Yjc1ZmJlOGU4NzBkMjQzMzA3MmVhYzE3NzY4ZmU1MWIyMjZlOTQifQ==", key)

And it seems like this should work, but when I run it I get the error: ValueError: Incorrect AES key length (60 bytes) so I'm not sure what I'm doing wrong. I've tried padding/unpadding the data/key but that doesn't seem to change anything. I'm wondering if I'm getting the wrong key to use for decryption from Laravel, but from what I could tell in the linked documentation, it should just be the APP_KEY in my .env file.

If anyone could help me or point me in the right direction, that would be amazing!

This question is unique to other similar questions because I'm trying to figure out primarily if I'm getting the correct AES key from Laravel, I don't actually overly need help decrypting, I just think I'm grabbing the wrong key from Laravel.

EDIT: New code that seems like it works:

import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad

def decrypt(enc, key):
    IV = 16 * '\x00'.encode()
    decobj = AES.new(key, AES.MODE_CBC, IV)
    data = decobj.decrypt(pad(base64.b64decode(enc), 16))
    print(base64.b64decode(data))

if __name__ == "__main__":
    key = base64.b64decode(b"/AZejP0lh3McL/+Vy5yZcADdTcR65qnx5Jqinuw7raK=")
    decrypt("eyJpdiI6ImdxY0VcLzFodmpISFV4allSWmJDdEpRPT0iLCJ2YWx1ZSI6IkxXd0ZJaUd2bTUweW5pNm0wUjQwOFM2N1wvWEs5SlYrNB4xNlR7Qkh1U3FvPSIsIm1hYyI6Ijc5ZWM0YTYxYjljZGFiNzgwNjY2NDU1ZmQ5Yjc1ZmJlOGU4NzBkMjQzMzA3MmVhYzE3NzY4ZmU1MWIyMjZlOTQifQ==", key)

The print statement now prints some bytes, but when I run .decode() on it I get the error: UnicodeDecodeError: 'utf-8' codec can't decode byte 0xfa in position 0: invalid start byte and can't seem to figure out what I need to do to make it be able to be printed as a string.


Solution

  • Question: ...trying to decrypt that data in Python but I keep getting errors about key length

    I can use your key, in the code of the linked answer, after doing .b64decode(....
    The example code .encode(... and decode(... works as expecte.
    Conclusion: There is nothing wrong, with your Key!

    key = b"/AZejP0lh3McL/+Vy5yZcADdTcR65qnx5Jqinuw7raK="
    key = base64.b64decode(key)
    

    But with your code, I got TypeError, related to the IV parameter:

      expect_byte_string(iv)
    File "/usr/local/lib/python3.4/dist-packages/Crypto/Util/_raw_api.py", line 172, in expect_byte_string
      TypeError: Only byte strings can be passed to C code
    

    Fixed with IV = 16 * '\x00'.encode(), results in ValueError, related to enc:

      data = decobj.decrypt(base64.b64decode(enc))
    File "/usr/local/lib/python3.4/dist-packages/Crypto/Cipher/_mode_cbc.py", line 209, in decrypt
      ValueError: Error 3 while decrypting in CBC mode
    

    This leads to github issues:10

    Error 3 means "ERR_NOT_ENOUGH_DATA"

    According to the linked GitHub page, you have to reread the documentation, about padding data while you are encoding.


    Working example from GitHub:

    import base64
    from Crypto.Cipher import AES
    from Crypto.Util.Padding import pad, unpad
    
    key = b"/AZejP0lh3McL/+Vy5yZcADdTcR65qnx5Jqinuw7raK="
    key = base64.b64decode(key)
    
    BLOCK_SIZE = 32
    encryption_suite = AES.new(key, AES.MODE_CBC, b'This is an IV...')
    cipher_text = encryption_suite.encrypt(pad(b'A really secret message...', BLOCK_SIZE))
    
    decryption_suite = AES.new(key, AES.MODE_CBC, b'This is an IV...')
    print(unpad(decryption_suite.decrypt(cipher_text), BLOCK_SIZE).decode())
    >>> A really secret message...
    

    Tested with Python: 3.4.2