AES-256-CBC Python decrypt data encrypted with PHP openssl_encry

ghz 7months ago ⋅ 52 views

AES-256-CBC Python decrypt data encrypted with PHP openssl_encrypt. Full Example

Our PHP is encrypting in such a way that I can not decrypt using Python.

PHP global

$cipherType = 'AES-256-CBC';
$secretKey = '12345678-abcd-abcd-abcd-123456789012';

PHP encrypt (comment show the $response [encrypted])

$value = "Joe";
$iv = random_bytes(16);
$cipherText = openssl_encrypt($value, $cipherType, $secretKey, OPENSSL_RAW_DATA, $iv);
$response = base64_encode(utf8_encode($iv . $cipherText));
//f8KxT07CgsKaJMK6HcK1w51xXcK6HW3DqcKFw6TCjShbw7PDv8KTQyfCvcOxZXrDnw==

PHP decrypt (comment show the $response [decrypted])

$value='f8KxT07CgsKaJMK6HcK1w51xXcK6HW3DqcKFw6TCjShbw7PDv8KTQyfCvcOxZXrDnw=='
$cipherData = utf8_decode(base64_decode($value));
$iv = mb_substr($cipherData, 0, 16, '8bit');
$cipherText = mb_substr($cipherData, 16, null, '8bit');
$response = openssl_decrypt($cipherText, $cipherType, $secretKey, OPENSSL_RAW_DATA, $iv);
//Joe

I tried to decrypt with Python

from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes

IV_LENGTH=16
secret_key = '12345678abcdabcdabcd123456789012'.encode('utf-8')
cipher_data = 'f8KxT07CgsKaJMK6HcK1w51xXcK6HW3DqcKFw6TCjShbw7PDv8KTQyfCvcOxZXrDnw=='
decoded = base64.b64decode(cipher_data)
iv = decoded[:IV_LENGTH]
cipher_text = decoded[IV_LENGTH:]
decrypt_cipher = AES.new(secret_key, AES.MODE_CBC, iv)
plain_text = decrypt_cipher.decrypt(cipher_text) #ValueError: Data must be padded to 16 byte boundary in CBC mode
plain_text.decode('utf-8')

output:

print('iv {}'.format(iv)) #iv b'\x7f\xc2\xb1ON\xc2\x82\xc2\x9a$\xc2\xba\x1d\xc2\xb5\xc3'
print('cipher_text {}'.format(cipher_text)) #cipher_text b"\x9dq]\xc2\xba\x1dm\xc3\xa9\xc2\x85\xc3\xa4\xc2\x8d([\xc3\xb3\xc3\xbf\xc2\x93C'\xc2\xbd\xc3\xb1ez\xc3\x9f"
ValueError: Data must be padded to 16 byte boundary in CBC mode

Notes:

I do not have the opportunity to modify the PHP encryption.

I am guessing PHP was removing the - from the $secretKey, python didn't allow them and throw error such as: ValueError: Incorrect AES key length (36 bytes)

What am I missing in my python in order to decrypt?

Could the problem be that I have not padded the data in PHP and PHP is just more permissive? Or could it be the openssl_encrypt in PHP is padding it under the hood and I need to pad/unppad in my python decrypt?

Answers

It appears that your Python decryption code is not working because it is not handling padding correctly. PHP's openssl_encrypt function automatically applies padding, but Python's Crypto.Cipher.AES module expects data to be padded manually.

To decrypt the data in Python, you need to ensure that you properly handle PKCS#7 padding. Here's how you can modify your Python code to include padding:

from Crypto.Cipher import AES
import base64

# Padding function for PKCS#7
def pkcs7_pad(data):
    pad_length = AES.block_size - (len(data) % AES.block_size)
    return data + bytes([pad_length] * pad_length)

IV_LENGTH = 16
SECRET_KEY = b'12345678abcdabcdabcd123456789012'
cipher_data = 'f8KxT07CgsKaJMK6HcK1w51xXcK6HW3DqcKFw6TCjShbw7PDv8KTQyfCvcOxZXrDnw=='

decoded = base64.b64decode(cipher_data)
iv = decoded[:IV_LENGTH]
cipher_text = decoded[IV_LENGTH:]

decrypt_cipher = AES.new(SECRET_KEY, AES.MODE_CBC, iv)
padded_plain_text = decrypt_cipher.decrypt(cipher_text)

# Remove padding
pad_length = padded_plain_text[-1]
plain_text = padded_plain_text[:-pad_length]

print('Decrypted plain text:', plain_text.decode('utf-8'))

In this modified version of your Python code, I've added a pkcs7_pad function to pad the data before encryption. After decryption, the padding is removed to obtain the original plaintext. This should allow you to decrypt the data correctly.