Reputation: 119
I am trying to use PBKDF2WithHmacSHA512 in PHP with OpenSSL. But I am not able to create same string as Java created encrypted string. Data which I am trying to encrypt is Atom Insta Pay. With the below mentioned java code I am getting vneGN6vnDJ3Z4wj4u3+z1g== but in PHP I am getting JQubY9xCf+g9yASdNkq7cQ== which is totally different.
// Java code
import java.util.logging.Logger;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
public class myEncryption {
static Logger log = Logger.getLogger(myEncryption.class.getName());
private static int pswdIterations = 65536;
private static int keySize = 256;
private static final byte[] ivBytes = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
public static String encrypt(String plainText, String key) {
try {
byte[] saltBytes = key.getBytes("UTF-8");
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
PBEKeySpec spec = new PBEKeySpec(key.toCharArray(), saltBytes, pswdIterations, keySize);
SecretKey secretKey = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
IvParameterSpec localIvParameterSpec = new IvParameterSpec(ivBytes);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(1, secret, localIvParameterSpec);
byte[] encryptedTextBytes = cipher.doFinal(plainText.getBytes("UTF-8"));
return byteToHex(encryptedTextBytes);
}catch (Exception e) {
log.info("Exception while encrypting data:" + e.toString());
}
return null;
}
public static String decrypt(String encryptedText, String key) {
try {
byte[] saltBytes = key.getBytes("UTF-8");
byte[] encryptedTextBytes = hex2ByteArray(encryptedText);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
PBEKeySpec spec = new PBEKeySpec(key.toCharArray(), saltBytes, pswdIterations, keySize);
SecretKey secretKey = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
IvParameterSpec localIvParameterSpec = new IvParameterSpec(ivBytes);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(2, secret, localIvParameterSpec);
byte[] decryptedTextBytes = (byte[]) null;
decryptedTextBytes = cipher.doFinal(encryptedTextBytes);
return new String(decryptedTextBytes);
}catch (Exception e) {
log.info("Exception while decrypting data:" + e.toString());
}
return null;
}
private static String byteToHex(byte[] byData) {
StringBuffer sb = new StringBuffer(byData.length * 2);
for (int i = 0; i < byData.length; ++i) {
int v = byData[i] & 0xFF;
if (v < 16)
sb.append('0');
sb.append(Integer.toHexString(v));
}
return sb.toString().toUpperCase();
}
private static byte[] hex2ByteArray(String sHexData) {
byte[] rawData = new byte[sHexData.length() / 2];
for (int i = 0; i < rawData.length; ++i) {
int index = i * 2;
int v = Integer.parseInt(sHexData.substring(index, index + 2), 16);
rawData[i] = (byte) v;
}
return rawData;
}
}
//PHP code
$method = "AES-256-CBC";
$salt = 'A4476C2062FFA58980DC8F79EB6A799E';
$key = 'A4476C2062FFA58980DC8F79EB6A799E';
$data = 'Demo String';
//Converting Array to bytes
$iv = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
$chars = array_map("chr", $iv);
$IVbytes = join($chars);
$salt1 = mb_convert_encoding($salt, "UTF-8"); //Encoding to UTF-8
$key1 = mb_convert_encoding($key, "UTF-8"); //Encoding to UTF-8
//SecretKeyFactory Instance of PBKDF2WithHmacSHA512 Java Equivalent
$hash = openssl_pbkdf2($key1,$salt1,'256','65536', 'sha512');
$encrypted = openssl_encrypt($data, $method, $hash, OPENSSL_RAW_DATA, $IVbytes);
echo base64_encode($encrypted);
Upvotes: 1
Views: 1049
Reputation: 6414
The PHP-solution is much "easier" as the Java-side and can consume the key and salt as direct input (without converting them).
As you like to compare base64-encoded ciphertexts the sample code returns the base64-encoded ciphertext and not the hex string as the Java-prog is giving out.
This is the output with equal results:
expected: JQubY9xCf+g9yASdNkq7cQ==
encrypted: JQubY9xCf+g9yASdNkq7cQ==
Security warning: your code is using static salt and iv that makes the encryption unsecure (I hope it's just for demonstration).
This is the code:
<?php
//PHP code
$method = "AES-256-CBC";
$salt = 'A4476C2062FFA58980DC8F79EB6A799E';
$key = 'A4476C2062FFA58980DC8F79EB6A799E';
$data = 'Atom Insta Pay';
//Converting Array to bytes
$iv = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
$chars = array_map("chr", $iv);
$IVbytes = join($chars);
$hash = openssl_pbkdf2($key,$salt,32,65536, 'sha512');
$encrypted = openssl_encrypt($data, $method, $hash, OPENSSL_RAW_DATA, $IVbytes);
echo 'expected: JQubY9xCf+g9yASdNkq7cQ==' . PHP_EOL;
echo 'encrypted: ' . base64_encode($encrypted);
?>
Upvotes: 2