pythonphpencryptionaes

Decrpyt AES-CCM Python vs. PHP


I'm trying to decrypt a text which I'm getting from a smart device. It works in Python, but doesn't work in PHP. I'm just getting an empty answer from openssl_decrypt, there is no error or warning nor any error in openssl_error_string(). I need to do it in PHP. I've already read this answer https://stackoverflow.com/a/61797909, but I'm still not able to fix my PHP-script. Because I'm getting the data from a device, I'm not able to change the length of the nonce, if that should be a problem (it's 13 bytes).

A modified AES-CCM version of this example https://www.geeksforgeeks.org/how-to-encrypt-and-decrypt-a-php-string/ works, so it doesn't seem to be a problem with my PHP-installation.

The working python-script (don't worry, key and nonce will be changed):

from __future__ import annotations

import binascii
import base64

from cryptography.hazmat.primitives.ciphers.aead import AESCCM

def decrypt_payload(
    payload: bytes, mic: bytes, key: bytes, nonce: bytes
) -> dict[str, float] | None:
    cipher = AESCCM(key, tag_length=4)
    try:
        data = cipher.decrypt(nonce, payload + mic, None)
        print("Decryption succeeded, decrypted data:", data.hex())
    except ValueError as error:
        print()
        print("Decryption failed:", error)
        return None

# =============================
# main()
# =============================
def main() -> None:
    payload = bytes(bytearray.fromhex("73ad3f07fe89"))
    mic = bytes(bytearray.fromhex("d8c82d06"))
    key = bytes(bytearray.fromhex("D77B34645356FB1333BAD6357B38CCCF"))
    nonce = bytes(bytearray.fromhex("7cc6b66242d3e3fc4512ac1267"))
    decrypt_payload(payload=payload, mic=mic, key=key, nonce=nonce)

if __name__ == "__main__":
    main()

The not working PHP-code:

<?php
$cipher = 'aes-256-ccm';
$payload = hex2bin("73ad3f07fe89");
$mic = hex2bin("d8c82d06");
$key = hex2bin("D77B34645356FB1333BAD6357B38CCCF");
$nonce = hex2bin("7cc6b66242d3e3fc4512ac1267");
if (in_array($cipher, openssl_get_cipher_methods())){
    $decrypted = openssl_decrypt($payload, $cipher, $key, OPENSSL_RAW_DATA, $nonce, $mic);
    echo "Error: " . openssl_error_string();
    echo $decrypted;
}
?>

Thanks in advance for any hint!


Solution

  • Tested using PHP-generated values:

    No issues decrypting to the string "this is a test" in PHP. The 13 byte IV is therefore not an issue. However, Python fails with an "InvalidTag" error with these test values.

    Upon further testing, the issue seems to be the key length. Your key is only 128-bit; when using AES-256, this should be a 256-bit key. Python's key padding is apparently different from PHP's.