I am encrypting data successfully in python and sending the url safe data to PHP. When I try to decrypt the data with the openssl_decrypt
PHP method it returns false
. I have been reading for 2 days know searching for a solution with none of them solving my problem [there are 2 similar questions on this forum, but they did not help, Q1, Q2 ].
The encryption uses python3.8 and package PyCryptodome:
from Crypto.Cipher import AES
import base64
import hashlib
import os
import secrets
BLOCK = 16
PADDING = '~'
iv = secrets.token_urlsafe(16)
secretKey = secrets.token_urlsafe(32) # 32 bytes is used as AES 256 expects 256 bits
encoding = 'latin-1'
s = 'very secret data' # secret to be encrypted
k = hashlib.sha256(secretKey.encode(encoding)).hexdigest()[:32].encode(encoding) # key hashed and encoded
pad = s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * PADDING
cipher = AES.new(key=k, mode=AES.MODE_CBC, IV=hashlib.sha256(iv.encode(encoding)).hexdigest()[:16].encode(encoding)) # cipher object
encrypted_secret = base64.urlsafe_b64encode(cipher.encrypt(pad.encode(encoding)))
print("Key: ", secretKey, "\n", "IV:",iv, "\n", "Encrypted:", encrypted_secret.decode(encoding))
Outputs[0]:
Key: cdLTCHW95FjHF6ESu2Rkm-90AUbzDBv71HrdshsEx3k
IV: b16ezD5O05EDNovsqLExUg
Encrypted: RJqA3-n6d7hmKgj7biiwUKD0SjRjm__4f42P06R-qO8=
*I decode the encrypted secret result because it is sent as a json encoded object and json`s encoder complains about byte objects in its midst.
Decrypting in PHP is less code (for tests I copy key and iv over, but the iv is newly created every time and the secret key is stored on different server):
$key = 'cdLTCHW95FjHF6ESu2Rkm-90AUbzDBv71HrdshsEx3k';
$iv = 'b16ezD5O05EDNovsqLExUg';
$method = "AES-256-CBC";
$blocksize = 16;
$padwith = '~';
$decoded_secret = 'RJqA3-n6d7hmKgj7biiwUKD0SjRjm__4f42P06R-qO8='; // secret is sent as string
$hashKey = substr(hash('sha256', $key), 0, 32);
$iv_len = openssl_cipher_iv_length($method);
$iv_hash = substr(hash('sha256', $iv), 0, $iv_len); // cipher expects an IV of precisely 16 bytes, padding with \\0
$decrypted_secret = openssl_decrypt($decoded_secret, $method, $hashKey, OPENSSL_RAW_DATA, $iv_hash);
$what = rtrim($decrypted_secret, $padwith);
var_dump($decrypted_secret, $what);
Outputs[1]: bool(false) string(0) ""
I have tried setting utf-8
as encoding in python, decoding the encrypted string with base64
in php, changing block size to 32, not using hashlib
on python side, but none of the changes gave the expected decrypted result.
Can someone please give me a clue to solve this problem?