I encrypt in Python this way:
from Crypto.Cipher import AES
from base64 import b64decode, b64encode
BLOCK_SIZE = 16
pad = lambda s: s + (BLOCK_SIZE - len(s.encode()) % BLOCK_SIZE) * chr(BLOCK_SIZE - len(s.encode()) % BLOCK_SIZE)
unpad = lambda s: s[:-ord(s[len(s) - 1:])]
class AESCipher:
def __init__(self, key: str, iv: str):
self.key = key
self.iv = iv
def encrypt(self, text):
text = pad(text).encode()
cipher = AES.new(key=self.key.encode(), mode=AES.MODE_CBC, iv=self.iv.encode())
encrypted_text = cipher.encrypt(text)
enc = b64encode(encrypted_text).decode('utf-8')
return enc
def decrypt(self, encrypted_text):
encrypted_text = b64decode(encrypted_text)
cipher = AES.new(key=self.key.encode(), mode=AES.MODE_CBC, iv=self.iv.encode())
decrypted_text = cipher.decrypt(encrypted_text)
return unpad(decrypted_text).decode('utf-8')
key = '12345hg5bnlg4mtae678900cdy7ta4vy'
iv = '12345hg5bnlg4mtae678900cdy7ta4vy'[:16]
json = '{"email":"[email protected]","password":"secret","firstName":"test","lastName":"test"}'
# Encrypt
cipher = AESCipher(key, iv)
enc = cipher.encrypt(json)
print(enc)
And I need to decrypt in PHP this way:
function encrypt($data, $key) {
$encryptedData = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_ZERO_PADDING, substr($key, 0, 16));
return base64_encode($encryptedData);
}
function decrypt($encryptedData, $key) {
$decryptedData = openssl_decrypt(base64_decode($encryptedData), 'AES-256-CBC', $key, OPENSSL_ZERO_PADDING, substr($key, 0, 16));
return $decryptedData;
}
Unfortunately, I get the empty result on decryption. Could you tell where is my bug? I don’t get any error, so it is difficult to understand where the problem is.
Thanks
2
Answers
Errors:
IV Size Issue:
The IV (Initialization Vector) must be exactly
16 bytes
forAES-256-CBC
. If the IV size is incorrect, the encryption/decryption process will fail.Padding Issue:
Using
OPENSSL_ZERO_PADDING
requires the data to be a multiple of the block size (16 bytes). If not, the function may fail or produce incorrect results. By default,openssl_encrypt
andopenssl_decrypt
handle padding correctly without specifying it.Solution:
Usage:
Running your Python code gives the following (Base64 encoded) ciphertext:
To decrypt this with the PHP code:
OPENSSL_ZERO_PADDING
option)OPENSSL_RAW_DATA
option)The following (fixed) PHP code successfully decrypts the ciphertext:
Since the reuse of key/IV pairs is a vulnerability, it is more secure to generate a random IV during encryption. The IV is not secret and is passed to the decrypting side together with the ciphertext (usually concatenated). Also note that PyCryptodome supports padding, see Crypto.Util.padding, so there is no need for a custom implementation.