I have got the Java Code from Payment Gateway for encryption of data. But My system is in PHP and I am trying to encrypt the same data in PHP. But I am getting different result. I tried all the help available but didn't got solution.
Encrypted Result can be tested by entering the encdata in https://mirror.kbzbank.com/B001/directpay.html
I believe I am missing some steps and I am not able to find what's wrong in my PHP code. Any suggestion or help would be grateful.
Java Code:
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class AesCipher {
public static final int INIT_VECTOR_LENGTH = 16;
/**
* @see <a href="https://stackoverflow.com/questions/9655181/how-to-convert-a-byte-array-to-a-hex-string-in-java">how-to-convert-a-byte-array-to-a-hex-string</a>
*/
private final static char[] hexArray = "0123456789ABCDEF".toCharArray();
/**
* Encoded/Decoded data
*/
protected String data;
/**
* Initialization vector value
*/
protected String initVector;
/**
* Error message if operation failed
*/
protected String errorMessage;
private AesCipher() {
super();
}
/**
* AesCipher constructor.
*
* @param initVector Initialization vector value
* @param data Encoded/Decoded data
* @param errorMessage Error message if operation failed
*/
private AesCipher( String initVector, String data, String errorMessage) {
super();
this.initVector = initVector;
this.data = data;
this.errorMessage = errorMessage;
}
/**
* Encrypt input text by AES-128-CBC algorithm
*
* @param secretKey 16/24/32 -characters secret password
* @param plainText Text for encryption
* @return Encoded string or NULL if error
*/
public static AesCipher encrypt(String secretKey, String plainText) {
String initVector = null;
try {
// Check secret length
if (!isKeyLengthValid(secretKey)) {
throw new Exception("Secret key's length must be 128, 192 or 256 bits");
}
byte[] l_encrypted = null;
Cipher l_encrcipher = null;
final byte[] keyBytes = new byte[16];
byte[] pwdBytes = null;
pwdBytes = secretKey.getBytes("UTF-8");
System.arraycopy(pwdBytes, 0, keyBytes, 0, pwdBytes.length);
l_encrcipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
final SecretKeySpec skeySpec = new SecretKeySpec(keyBytes, "AES");
final IvParameterSpec ivParamSpec = new IvParameterSpec(keyBytes);
l_encrcipher.init(1, skeySpec, ivParamSpec);
l_encrypted = l_encrcipher.doFinal(plainText.getBytes());
String result = Base64.getEncoder().encodeToString(l_encrypted);
result = result.replaceAll("\\r\\n","");
// Return successful encoded object
return new AesCipher(initVector, result, null);
} catch (Throwable t) {
t.printStackTrace();
// Operation failed
return new AesCipher(initVector, null, t.getMessage());
}
}
/**
* Check that secret password length is valid
*
* @param key 16/24/32 -characters secret password
* @return TRUE if valid, FALSE otherwise
*/
public static boolean isKeyLengthValid(String key) {
return key.length() == 6 || key.length() == 16 || key.length() == 24 || key.length() == 32;
}
/**
* Convert Bytes to HEX
*
* @param bytes Bytes array
* @return String with bytes values
*/
public static String bytesToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
/**
* Get encoded/decoded data
*/
public String getData() {
return data;
}
/**
* Get initialization vector value
*/
public String getInitVector() {
return initVector;
}
/**
* Get error message
*/
public String getErrorMessage() {
return errorMessage;
}
/**
* Check that operation failed
*
* @return TRUE if failed, FALSE otherwise
*/
public boolean hasError() {
return this.errorMessage != null;
}
/**
* To string return resulting data
*
* @return Encoded/decoded data
*/
public String toString() {
return getData();
}
public static void main(String[] args) {
// USAGE
String secretKey = "S%Y#N@";
String text = "fldClientCode=101|fldMerchCode=EPI0008|fldTxnCurr=MMK|fldTxnAmt=1000|fldTxnScAmt=0|fldMerchRefNbr=ACBS12345|fldSucStatFlg=N|fldFailStatFlg=N|fldDatTimeTxn=07/03/202213:01:01|checkSum=f0b04f0915619669987de294e4c1931d";
AesCipher encrypted = AesCipher.encrypt(secretKey, text);
System.out.println(encrypted.getData());
}
}
PHP Code I am trying :
<?php
/**
* AesCipher
*
* Encode/Decode text by password using AES-128-CBC algorithm
*/
class AesCipher
{
const CIPHER = 'AES-128-CBC';
const INIT_VECTOR_LENGTH = 16;
/**
* Encoded/Decoded data
*
* @var null|string
*/
protected $data;
/**
* Initialization vector value
*
* @var string
*/
protected $initVector;
/**
* Error message if operation failed
*
* @var null|string
*/
protected $errorMessage;
/**
* AesCipher constructor.
*
* @param string $initVector Initialization vector value
* @param string|null $data Encoded/Decoded data
* @param string|null $errorMessage Error message if operation failed
*/
public function __construct($initVector, $data = null, $errorMessage = null)
{
$this->initVector = $initVector;
$this->data = $data;
$this->errorMessage = $errorMessage;
}
/**
* Encrypt input text by AES-128-CBC algorithm
*
* @param string $secretKey 16/24/32 -characters secret password
* @param string $plainText Text for encryption
*
* @return self Self object instance with data or error message
*/
public static function encrypt($secretKey, $plainText)
{
try {
// Check secret length
if (!static::isKeyLengthValid($secretKey)) {
throw new \InvalidArgumentException("Secret key's length must be 128, 192 or 256 bits");
}
// Get random initialization vector
$initVector = bin2hex(openssl_random_pseudo_bytes(static::INIT_VECTOR_LENGTH / 2));
// Encrypt input text
$raw = openssl_encrypt(
$plainText,
static::CIPHER,
$secretKey,
OPENSSL_RAW_DATA,
$initVector
);
// Return base64-encoded string: initVector + encrypted result
$result = base64_encode($initVector . $raw);
if ($result === false) {
// Operation failed
return new static($initVector, null, openssl_error_string());
}
// Return successful encoded object
return new static($initVector, $result);
} catch (\Exception $e) {
// Operation failed
return new static(isset($initVector), null, $e->getMessage());
}
}
/**
* Decrypt encoded text by AES-128-CBC algorithm
*
* @param string $secretKey 16/24/32 -characters secret password
* @param string $cipherText Encrypted text
*
* @return self Self object instance with data or error message
*/
public static function decrypt($secretKey, $cipherText)
{
try {
// Check secret length
if (!static::isKeyLengthValid($secretKey)) {
throw new \InvalidArgumentException("Secret key's length must be 128, 192 or 256 bits");
}
// Get raw encoded data
$encoded = base64_decode($cipherText);
// Slice initialization vector
$initVector = substr($encoded, 0, static::INIT_VECTOR_LENGTH);
// Slice encoded data
$data = substr($encoded, static::INIT_VECTOR_LENGTH);
// Trying to get decrypted text
$decoded = openssl_decrypt(
$data,
static::CIPHER,
$secretKey,
OPENSSL_RAW_DATA,
$initVector
);
if ($decoded === false) {
// Operation failed
return new static(isset($initVector), null, openssl_error_string());
}
// Return successful decoded object
return new static($initVector, $decoded);
} catch (\Exception $e) {
// Operation failed
return new static(isset($initVector), null, $e->getMessage());
}
}
/**
* Check that secret password length is valid
*
* @param string $secretKey 16/24/32 -characters secret password
*
* @return bool
*/
public static function isKeyLengthValid($secretKey)
{
$length = strlen($secretKey);
return $length == 6 || $length == 16 || $length == 24 || $length == 32;
}
/**
* Get encoded/decoded data
*
* @return string|null
*/
public function getData()
{
return $this->data;
}
/**
* Get initialization vector value
*
* @return string|null
*/
public function getInitVector()
{
return $this->initVector;
}
/**
* Get error message
*
* @return string|null
*/
public function getErrorMessage()
{
return $this->errorMessage;
}
/**
* Check that operation failed
*
* @return bool
*/
public function hasError()
{
return $this->errorMessage !== null;
}
/**
* To string return resulting data
*
* @return null|string
*/
public function __toString()
{
return $this->getData();
}
}
// USAGE
$secretKey = 'S%Y#N@';
$text = "fldClientCode=101|fldMerchCode=EPI0008|fldTxnCurr=MMK|fldTxnAmt=1000|fldTxnScAmt=0|fldMerchRefNbr=ACBS12345|fldSucStatFlg=N|fldFailStatFlg=N|fldDatTimeTxn=07/03/202213:01:01|checkSum=f0b04f0915619669987de294e4c1931d";
$encrypted = AesCipher::encrypt($secretKey, $text);
print_r($encrypted);
$decrypted = AesCipher::decrypt($secretKey, $encrypted);
$encrypted->hasError(); // TRUE if operation failed, FALSE otherwise
$encrypted->getData(); // Encoded/Decoded result
$encrypted->getInitVector(); // Get used (random if encode) init vector
// $decrypted->* has identical methods