I encrypted a string in Kotlin using the following code
private fun encrypt(context: Context, strToEncrypt: String, encryptKey : String): ByteArray {
val plainText = strToEncrypt.toByteArray(Charsets.UTF_8)
val key = generateKey(encryptKey)
val cipher = Cipher.getInstance("AES_256/CBC/PKCS5PADDING")
cipher.init(Cipher.ENCRYPT_MODE, key)
val cipherText = cipher.doFinal(plainText)
return cipherText
}
private fun generateKey(password: String): SecretKeySpec {
val digest: MessageDigest = MessageDigest.getInstance("SHA-256")
val bytes = password.toByteArray()
digest.update(bytes, 0, bytes.size)
val key = digest.digest()
val secretKeySpec = SecretKeySpec(key, "AES")
return secretKeySpec
}
and I use it like this:
encrypt(requireContext(), "test_string", "password")
Now I need to decrypt the generated string in PHP (receiving string via GET). I have something like this:
function decryptString($encryptedString, $cipher, $key, $initVector) {
// decrypt and return string
return openssl_decrypt($encryptedString, $cipher, $key, 0, $initVector);
}
if (isset($_GET["plain_text"])) {
// define cipher algorithm
$cipher = "aes-256-cbc";
// generate initialization vector
$iv_size = openssl_cipher_iv_length($cipher);
$iv = openssl_random_pseudo_bytes($iv_size);
echo decryptString($_GET["plain_text"], $cipher, "password", $iv);
}
But the result is empty. I guess this is because in PHP I can use a string as key for decription (the $key
parameter in the openssl_decrypt()
procedure) defined by me, while in Kotlin (damned Android is always overly complicated for no reason), you are forced to use a SecretKeySpec
parameter as key, so I cannot pass an hardcoded string as key.
I'm not an encryption expert, so forgive me for the dumb question.
The Kotlin code automatically generates a random IV, which you must fetch and pass together with the ciphertext. It is common to concatenate both, e.g. iv|ciphertext. You can use Base64 to generate a string from the byte array:
private fun encrypt(strToEncrypt: String, encryptKey : String): String {
val plainText = strToEncrypt.toByteArray(Charsets.UTF_8)
val key = generateKey(encryptKey)
val cipher = Cipher.getInstance("AES_256/CBC/PKCS5PADDING")
cipher.init(Cipher.ENCRYPT_MODE, key)
val cipherText = cipher.iv + cipher.doFinal(plainText) // get IV and concatenate with ciphertext
return Base64.getEncoder().encodeToString(cipherText) // Base64 encode data
}
On the PHP side, the IV must be stripped off from the ciphertext. In addition, the key must be derived with SHA256 as in the Kotlin code (by the way, it is better to use PBKDF2 or more modern KDFs):
$ivCt = base64_decode('p5ONPQVga2KWX5nM1mHI04uXRYCqFXUTYgsiIurQdfF+qidI5YOOjhn2s9g/DYuq'); // sample data from Kotlin code
$iv = substr($ivCt, 0, 16); // strip IV off
$ct = substr($ivCt, 16);
$pwd = 'your password';
$key = hash('sha256', $pwd, true); // derive key with SHA256
$dt = openssl_decrypt($ct, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv); // disable default Base64 with OPENSSL_RAW_DATA
print($dt . PHP_EOL); // Take me to your leader