I have the following encryption function in my application:
public static String encrypt(String key, String value) {
try {
IvParameterSpec iv = new IvParameterSpec(key.substring(0, 16).getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = cipher.doFinal(value.getBytes("UTF-8"));
return Base64.encodeBase64String(encrypted);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
And in PHP the encrypted message is decoded using openssl_decrypt()
with AES-128-CBC
set as the method of encryption.
However the decryption always fails the response I get from the server is that it cannot recognize the encryption method.
I have no control over the server so I cannot change anything on that end only in my Java app.
I have tried different modes like AES/CBC/NoPadding
but I get an exception
Input Length Not Multiple of 16 bytes
Now I know there is nothing wrong with the encryption because I am able to encrypt and decrypt in my java app when using AES/CBC/PKCS5Padding
it just fails when post to the server.
Key is a md5 hash.
This is a sample of the data I need to encrypt:
{
"merchant_id": "EXX-00000001",
"user_id": "000000000001",
"code": "000200",
"details": {
"acc_no": "1234691007924321",
"exp": "07/19",
"name": "MICHAEL XXXXXX",
"type": "VIS"
}
}
Only the "details" value is supposed to be encrypted. The code is supposed to be a md5 hash. The resulting hash is then to be used as a key for the AES encryption. The IV is supposed to be the first 16 chars of the hash. When the encryption is done the result should be encoded in base64 and sent to the server.
In PHP, Encryption and Decryption of a string is possible using one of the Cryptography Extensions called OpenSSL function for encrypt and decrypt. openssl_encrypt() Function: The openssl_encrypt() function is used to encrypt the data. Parameters: $data: It holds the string or data which need to be encrypted.
Secret key encryption (or symmetric encryption as it's also known) uses a single key to both encrypt and decrypt data. In the past PHP relied on mcrypt and openssl for secret key encryption. PHP 7.2 introduced Sodium, which is more modern and widely considered more secure.
Only those who have the special key can decrypt it. AES uses symmetric key encryption, which involves the use of only one secret key to cipher and decipher information.
Trying to reverse this, I got an error of
java.security.InvalidKeyException: Illegal key size
at line
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
To make it work, I changed the SecretKeySpec
byte array from key.getBytes("UTF-8")
to key.substring(0, 16).getBytes("UTF-8")
and used it like this:
String md5Key= "e510a13edeea112b57683d724d5d70a6";
String detailsData = "{\n" +
" \"acc_no\": \"1234691007924321\",\n" +
" \"exp\": \"07/19\",\n" +
" \"name\": \"MICHAEL XXXXXX\",\n" +
" \"type\": \"VIS\"\n" +
" }";
System.out.println(encrypt(md5Key, detailsData));
I got an output like this:
iufp4Rl+x/yTO7hSQBH7uU63sXAyzxgLequ3+JkFYZFz3PWwhxDC87TEC+bZ4rirgZVasrkLE1ehWWRGFV42Z29vAok+TMdwOvOettELUD3g8W2F40OyjMg4ItYkiZM+2W6Q2zf6t4sLzM6/AYqmAy1dKjPJcCQaFcnqK6mUFcM=
To decrypt that in PHP, I used the following code that uses the first 16 chars of key
to use it as a key
and iv
initializer like this:
$enc_data = 'iufp4Rl+x/yTO7hSQBH7uU63sXAyzxgLequ3+JkFYZFz3PWwhxDC87TEC+bZ4rirgZVasrkLE1ehWWRGFV42Z29vAok+TMdwOvOettELUD3g8W2F40OyjMg4ItYkiZM+2W6Q2zf6t4sLzM6/AYqmAy1dKjPJcCQaFcnqK6mUFcM=';
$key = 'e510a13edeea112b57683d724d5d70a6';
$key16 = substr($key, 0, 16);
$key16Hex = unpack('H*', $key16);
print openssl_decrypt($enc_data, "AES-128-CBC", $key16, 0, hex2bin($key16Hex[1]));
And of course I got the wanted JSON data I encrypted with Java:
{
"acc_no": "1234691007924321",
"exp": "07/19",
"name": "MICHAEL XXXXXX",
"type": "VIS"
}
It's strange you do not get an error at this line:
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
because I do using JDK 1.8 with:
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With