I must match an encrypted JSON object from Java to PHP but I failed to do so. Tried almost all solutions on stackoverflow, still no luck.
DOC says field must be obtained through AES encryption of the JSON representation of all the fields the merchant wants to send. Encryption algorithm must be AES/CBC/PKCS5Padding and must use as encrypting key the one provided. The initialization vector to be used for data encryption must be 16 bytes length equal to 0. Encrypted byte array must encoded to base64.
{"addrMatch":"N"} should convert to q8zzcOYHKggpSFXdmdZdObe2R/1EWnFgco2FJzjhtJQ=
I have the following code:
import java.security.InvalidAlgorithmParameterException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
public class Utility {
public static String encode3DSdata(String APISecretMerchant, String JSONobject) throws Throwable {
// Initialization vector
byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
// AES Key from the API merchant key
byte[] key = APISecretMerchant.substring(0, 16).getBytes();
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
byte[] toEncrypt = JSONobject.getBytes("UTF-8");
// Encrypt
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] encrypted = cipher.doFinal(toEncrypt);
// Convert to base64
return DatatypeConverter.printBase64Binary(encrypted);
}
}
Here is my code on PHP without luck:
function pkcs5pad($text,$blocksize) {
$pad = $blocksize - (strlen($text) % $blocksize);
return $text.str_repeat(chr($pad), $pad);
}
function encrypt($data, $key)
{
$json = iconv('utf-8', 'utf-8//IGNORE', json_encode($data,JSON_UNESCAPED_SLASHES));
$padded=pkcs5pad($json,16);
$encrypted = openssl_encrypt($padded, 'AES-128-CBC', $key, OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING, self::iv);
return base64_encode($encrypted);
}
const iv = '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0'; // also tried as "0000000000000000"
$key='c-MCjRx4X-pD-Lux';
$data=['addrMatch'=>'N'];
echo encrypt($data,$key);
I produce : Bpo0neCnY+dFrdISLYcefU8sqhX/4HSr5Io+zUe4sro=
Any help would be appreciated.
There are two issues within your PHP code.
First: There is a fixed IV with 16 x#d 00 - use it this way:
$iv = "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0";
Second: use the OPENSSL-built in padding (it's named PKCS7 but it's similar to Java's PKCS5
output:
encrypt: q8zzcOYHKggpSFXdmdZdObe2R/1EWnFgco2FJzjhtJQ=
expected:q8zzcOYHKggpSFXdmdZdObe2R/1EWnFgco2FJzjhtJQ=
Security warning: the code is unsecure as it uses fixed key + initialization vector.
code:
<?php
function encrypt($data, $key)
{
$iv = "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0";
$json = iconv('utf-8', 'utf-8//IGNORE', json_encode($data,JSON_UNESCAPED_SLASHES));
$encrypted = openssl_encrypt($json, 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv);
return base64_encode($encrypted);
}
$key='c-MCjRx4X-pD-Lux';
$data=['addrMatch'=>'N'];
echo 'encrypt: ' . encrypt($data,$key) . PHP_EOL;
echo 'expected:' . 'q8zzcOYHKggpSFXdmdZdObe2R/1EWnFgco2FJzjhtJQ=' . PHP_EOL;
?>