Search code examples
phpionic-frameworkencryption

Using openssl_decrypt() not displaying anything when trying to decrypted an encrypted data


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?


Solution

  • 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 of Salted__, 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 IV 048eb25d7a45ff00 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.