Reputation: 852
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
Upvotes: 1
Views: 137
Reputation: 49131
Running your Python code gives the following (Base64 encoded) ciphertext:
r9Ufy4dnw2Yr0apRe1q0N0eiE+2VEOUbO35CeLQbJia1x8IM66nzweFdnJ32gpQTsZ33As6XjBZUU3bjpZrwyndeTP1ln8890qSyqlmlXOwiYnDHe5Zjg9Ws1F+zR0nl
To decrypt this with the PHP code:
OPENSSL_ZERO_PADDING
option)OPENSSL_RAW_DATA
option)The following (fixed) PHP code successfully decrypts the ciphertext:
$key = '12345hg5bnlg4mtae678900cdy7ta4vy';
$ciphertext = 'r9Ufy4dnw2Yr0apRe1q0N0eiE+2VEOUbO35CeLQbJia1x8IM66nzweFdnJ32gpQTsZ33As6XjBZUU3bjpZrwyndeTP1ln8890qSyqlmlXOwiYnDHe5Zjg9Ws1F+zR0nl';
function decrypt($encryptedData, $key) {
$decryptedData = openssl_decrypt($encryptedData, 'AES-256-CBC', $key, 0, substr($key, 0, 16)); // 1. don't disable padding, 2. remove the explicit Base64 decoding
return $decryptedData;
}
print(decrypt($ciphertext, $key)); // {"email":"[email protected]","password":"secret","firstName":"test","lastName":"test"}
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.
Upvotes: 2
Reputation: 7662
Errors:
IV Size Issue:
The IV (Initialization Vector) must be exactly 16 bytes
for AES-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
and openssl_decrypt
handle padding correctly without specifying it.
Solution:
function encrypt($data, $key) {
$iv = substr($key, 0, 16); // Use a proper IV
$encryptedData = openssl_encrypt($data, 'AES-256-CBC', $key, 0, $iv);
return base64_encode($encryptedData);
}
function decrypt($encryptedData, $key) {
$iv = substr($key, 0, 16); // Use the same IV as in encrypt
$decryptedData = openssl_decrypt(base64_decode($encryptedData), 'AES-256-CBC', $key, 0, $iv);
return $decryptedData;
}
Usage:
$data = "Hello, World!";
$key = "12345678901234567890123456789012"; // 32-byte key for AES-256
$encrypted = encrypt($data, $key);
echo "Encrypted: " . $encrypted . "\n";
$decrypted = decrypt($encrypted, $key);
echo "Decrypted: " . $decrypted . "\n";
Upvotes: 0