I have the following Java code which was shared by one of an integration partner for their API encryption
import java.nio.ByteBuffer;
import java.sec
In the Java encrypt
-method the (randomly generated) salt- and IV-bytes are copied together with the encryption-bytes in a single byte-array which becomes base64-encoded and which is returned then. In contrast, the PHP encrypt
-method returns a hex-representation of the encryption bytes only. Thus, the information concerning the salt and IV get lost and decryption is no longer possible (unless salt and IV are reconstructed in other ways). In order to prevent this, you have to change the PHP encrypt
-method as follows:
public function encrypt($data = '', $key = NULL) {
if($key != NULL && $data != ""){
$method = "AES-256-CBC";
$key1 = mb_convert_encoding($key, "UTF-8"); //Encoding to UTF-8
//Randomly generate IV and salt
$salt1 = random_bytes (20);
$IVbytes = random_bytes (16);
//SecretKeyFactory Instance of PBKDF2WithHmacSHA1 Java Equivalent
$hash = openssl_pbkdf2($key1,$salt1,'256','65556', 'sha1');
// Encrypt
$encrypted = openssl_encrypt($data, $method, $hash, OPENSSL_RAW_DATA, $IVbytes);
// Concatenate salt, IV and encrypted text and base64-encode the result
$result = base64_encode($salt1.$IVbytes.$encrypted);
return $result;
}else{
return "String to encrypt, Key is required.";
}
}
Now, the parameter $result
is a base64-encoded string containing the salt, IV and the encryption. By the way, the parameters $salt1
and $IVbytes
are also randomly generated now (analogous to the Java encrypt
-method). Morover the iteration count used for the key generation has been changed from 65536 to 65556 (analogous to the Java encrypt
-method). Note: Generally, the encrypted text isn't reproducible (even in the case of the same plain text, and the same key/password) due to the random nature of salt and IV.
The Java decrypt
-method decodes the base64-encoded string and then determines the three portions i.e. salt-, IV- and encryption-bytes which are necessary for decryption. The PHP decrypt
-method has to be supplemented with these functionalities:
public function decrypt($data="", $key = NULL) {
if($key != NULL && $data != ""){
$method = "AES-256-CBC";
$key1 = mb_convert_encoding($key, "UTF-8");//Encoding to UTF-8
// Base64-decode data
$dataDecoded = base64_decode($data);
// Derive salt, IV and encrypted text from decoded data
$salt1 = substr($dataDecoded,0,20);
$IVbytes = substr($dataDecoded,20,16);
$dataEncrypted = substr($dataDecoded,36);
// SecretKeyFactory Instance of PBKDF2WithHmacSHA1 Java Equivalent
$hash = openssl_pbkdf2($key1,$salt1,'256','65556', 'sha1');
// Decrypt
$decrypted = openssl_decrypt($dataEncrypted, $method, $hash, OPENSSL_RAW_DATA, $IVbytes);
return $decrypted;
}else{
return "Encrypted String to decrypt, Key is required.";
}
}
Now, the parameter $dataDecoded
contains the decoded base64-encoded string from which salt- ($salt1
), IV- ($IVbytes
) and encryption-
($dataEncrypted
) bytes are derived. Morover the iteration count used for the key generation has been changed from 65536 to 65556 (analogous to the Java decrypt
-method).
Test case 1: Encrypt and Decrypt with PHP
$atomAES = new AtomAES();
$encrypt = $atomAES->encrypt("This is a text...This is a text...This is a text...", "This is the password");
echo $encrypt;
$decrypt = $atomAES->decrypt($encrypt, "This is the password");
echo $decrypt;
with the result for $encrypt
(which is in general different for each encryption due to the random nature of salt and IV):
6n4V9wqgsQq87HOYNRZmddnncSNyjFZZb8nSSAi681+hs+jwzDVQCugcg108iTMZLlmBB2KQ4iist+SuboFH0bnJxW6+rmZK07CiZ1Ip+8XOv6UuJPjVPxXTIny5p3QptpBGpw==
and for $decrypt
:
This is a text...This is a text...This is a text...
Test case 2: Encrypt with Java, Decrypt with PHP
encryptedText = AES256.encrypt("This is a text...This is a text...This is a text...","This is the password");
System.out.println(encryptedText);
with the result for encryptedText
(which is in general different for each encryption due to the random nature of salt and IV):
qfR76lc04eYAPjjqYiE1wXoraD9bI7ql41gSV/hsT/BLoJe0i0GgJnud7IXOHdcCljgtyFkXB95XibSyr/CazoMhwPeK6xsgPbQkr7ljSg8H1i17c8iWpEXBQPm0nij9qQNJ8A==
and
$decrypt = $atomAES->decrypt("qfR76lc04eYAPjjqYiE1wXoraD9bI7ql41gSV/hsT/BLoJe0i0GgJnud7IXOHdcCljgtyFkXB95XibSyr/CazoMhwPeK6xsgPbQkr7ljSg8H1i17c8iWpEXBQPm0nij9qQNJ8A==", "This is the password");
echo $decrypt;
with the result for $decrypt
:
This is a text...This is a text...This is a text...
Test case 3: Encrypt with Java, Decrypt with PHP
encryptedText = AES256.encrypt("This is a sample text","NEWENCTEST");
System.out.println(encryptedText);
1HO8iuSZf41RzP/gUleEJY3zhtLJVwFMnhZiphnoG0m9ss+g93Sj5SqQg0D7OsgSvUZCeX2Ck5QPpFrPxM0FE/yFE5s=
and
$decrypt = $atomAES->decrypt("1HO8iuSZf41RzP/gUleEJY3zhtLJVwFMnhZiphnoG0m9ss+g93Sj5SqQg0D7OsgSvUZCeX2Ck5QPpFrPxM0FE/yFE5s=", "NEWENCTEST");
echo $decrypt;
with the result for $decrypt
:
This is a sample text