I am trying to decrypt data coming from ionic in PHP but it is not decrypting using openssl_decrypt()
.
In my ionic app, I was able to encrypt and also test the decryption function which works well. Below are both the encryption and decryption functions:
Encryption
encrypt(key, iv, value){
const encrypted = CryptoJS.AES.encrypt(value, key, { iv: iv });
const encryptedMessage = encrypted.toString();
return encryptedMessage;
}
Decryption
decrypt(value, keys, ivs){
const decryptedMessage = CryptoJS.AES.decrypt(value, keys, { iv: ivs
}).toString(CryptoJS.enc.Utf8);
return decryptedMessage;
}
Encrypted data with key and iv
$iv = "048eb25d7a45ff00";
$key = "feda4f2f67e7aa96";
$encrypted = "U2FsdGVkX1 kBV6Q5BQrjuOdi4WLiu4 QAnDIkzJYv5ATTkiiPVX8VcDUpMqSeIwCfyTNQOosp/9nYDY4Suu4/Lmhh2quKBU7BHGOtKwu9o=";
**To decrypt in PHP**
<?php
// Use openssl_decrypt() function to decrypt the data
$output = openssl_decrypt($encrypted, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
echo $output;
?>
How can I decrypt this?
CodePudding user response:
In the CryptoJS code, the key material is passed as string, which is why it is interpreted as password and a key derivation is applied. The key derivation function used is the OpenSSL proprietary EVP_BytesToKey()
. During encryption, CryptoJS.AES.encrypt()
does the following:
- Generate an 8 bytes salt implicitly.
- Derive a 32 bytes key and 16 bytes IV based on the salt and password using
EVP_BytesToKey()
. - Encrypt the plaintext with key and IV, ignoring any explicitly passed IV (here
048eb25d7a45ff00
)! - Convert the data to OpenSSL format (by
encrypted.toString()
): Base64 encoding of the ASCII encoding ofSalted__
, followed by the 8 bytes salt and the actual ciphertext.
Therefore, decryption must be carried out as follows:
- Separate salt and actual ciphertext.
- Derive the 32 bytes key and 16 bytes IV from salt and password using
EVP_BytesToKey()
. Note that the IV048eb25d7a45ff00
is not needed. - Decrypt the ciphertext with key and IV.
A possible implementation:
// Separate salt and actual ciphertext
$saltCiphertext = base64_decode("U2FsdGVkX1 kBV6Q5BQrjuOdi4WLiu4 QAnDIkzJYv5ATTkiiPVX8VcDUpMqSeIwCfyTNQOosp/9nYDY4Suu4/Lmhh2quKBU7BHGOtKwu9o=");
$salt = substr($saltCiphertext, 8, 8);
$ciphertext = substr($saltCiphertext, 16);
// Separate key and IV
$keyIv = EVP_BytesToKey($salt, "feda4f2f67e7aa96");
$key = substr($keyIv, 0, 32);
$iv = substr($keyIv, 32, 16);
// Decrypt using key and IV
$decrypted = openssl_decrypt($ciphertext, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
print($decrypted . PHP_EOL); // {"username":"07069605705","password":"father2242"}
// KDF EVP_BytesToKey()
function EVP_BytesToKey($salt, $password) {
$bytes = ''; $last = '';
while(strlen($bytes) < 48) {
$last = hash('md5', $last . $password . $salt, true);
$bytes.= $last;
}
return $bytes;
}
Note: EVP_BytesToKey()
is deemed insecure nowadays and should not be used. A more secure alternative is PBKDF2 which is supported by both CryptoJS and PHP.