I am using openssl_encrypt function available in PHP to get the similar result as the below java code is producing.
But it is all different. Kindly help me.
JAVA CODE
package com.atom.echallan.security.util;
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;
import com.atom.echallan.util.EChallanUtil;
public class AtomAES {
private String password = "8E41C78439831010F81F61C344B7BFC7";
private String salt = "200000054575202";
private static int pswdIterations = 65536 ;
private static int keySize = 256;
private final byte[] ivBytes = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
public AtomAES(){
super();
}
public String encrypt(String plainText, String key, String merchantTxnId) throws Exception
{
this.password = key;
// salt->200000054575202
this.salt = merchantTxnId;
return encrypt(plainText);
}
private String encrypt(String plainText) throws Exception {
byte[] saltBytes = salt.getBytes("UTF-8");
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
PBEKeySpec spec = new PBEKeySpec(
password.toCharArray(),
saltBytes,
pswdIterations,
keySize
);
SecretKey secretKey = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
//encrypt the message
IvParameterSpec localIvParameterSpec = new IvParameterSpec(ivBytes);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); //CBC
cipher.init(Cipher.ENCRYPT_MODE, secret,localIvParameterSpec);
byte[] encryptedTextBytes = cipher.doFinal(plainText.getBytes("UTF-8"));
return byteToHex(encryptedTextBytes);
}
public String decrypt(String encryptedText, String key, String merchantTxnId) throws Exception {
this.password = key;
this.salt = merchantTxnId;
return decrypt(encryptedText);
}
private String decrypt(String encryptedText) throws Exception {
byte[] saltBytes = salt.getBytes("UTF-8");
byte[] encryptedTextBytes = hex2ByteArray(encryptedText);
// Derive the key
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
PBEKeySpec spec = new PBEKeySpec(
password.toCharArray(),
saltBytes,
pswdIterations,
keySize
);
SecretKey secretKey = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
// Decrypt the message
IvParameterSpec localIvParameterSpec = new IvParameterSpec(ivBytes);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");//CBC
cipher.init(Cipher.DECRYPT_MODE, secret,localIvParameterSpec);
byte[] decryptedTextBytes = null;
decryptedTextBytes = cipher.doFinal(encryptedTextBytes);
return new String(decryptedTextBytes);
}
//Converts byte array to hexadecimal String
private 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();
}
//Converts hexadecimal String to array of byte
private 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;
}
public static void main(String[] args)throws Exception{
AtomAES aes = new AtomAES();
String data = "mmp_txn=355106|mer_txn=M123|amt=100.0000|";
String encData = aes.encrypt(data, EChallanUtil.ATOM_ENCRYPTION_KEY, "178");
System.out.println("ENC DATA : " + encData);
System.out.println("DEC DATA : " + aes.decrypt(encData, EChallanUtil.ATOM_ENCRYPTION_KEY, "178"));
}
}
PHP CODE
class Encryption {
public function encrypt($data, $key = "4A8A53E16C9C34EA5E77EF9FF7B2FD04", $method = "AES-256-CBC") {
$size = openssl_cipher_iv_length($method);
$iv = substr($key, 0, 16);
// string openssl_pbkdf2 ( string $password , string $salt , int $key_length , int $iterations [, string $digest_algorithm ] )
$hash = openssl_pbkdf2($key,'178','256','65536', 'sha1');
$encrypted = openssl_encrypt($data, $method, $hash, OPENSSL_RAW_DATA, $iv);
return bin2hex($encrypted);
}
public function decrypt($data, $key, $method) {
$size = openssl_cipher_iv_length($method);
$iv = substr($key, 0, $size);
$decrypted = openssl_decrypt($data, $method, $key, false, $iv);
return $decrypted;
}
function pkcs5_pad ($text, $blocksize)
{
$pad = $blocksize - (strlen($text) % $blocksize);
return $text . str_repeat(chr($pad), $pad);
}
}
$text = 'mmp_txn=355106|mer_txn=M123|amt=100.0000|';
//
//$enc = new AESEncryption;
//$enc1 = new CbcCrypt;
$enc2 = new Encryption;
echo $enc2->encrypt($text);
JAVA Result :
ENC DATA : 4BBB37555EFFEF677CEF1B5D55843E50255F65540DF16AFB3F2A0B7B91341E54FB0432EEE2154A947DAD013E8C99822D
PHP Result : c43ba05ae04f68ae18313bc2042595fc70981e0d9421af9d232a3d17a01b5dd8dd8ce702230f6e49d918c9578f9c6944
I dont know why it is happening.
Length of the string is same but result are different.
How to get the similar result as in java?
I have solved your code by using below code Hope this may help you
public function encrypt($data, $key = "4A8A53E16C9C34EA5E77EF9FF7B2FD04", $method = "AES-256-CBC") {
$salt="178";
//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 PBKDF2WithHmacSHA1 Java Equivalent
$hash = openssl_pbkdf2($key1,$salt1,'256','65536', 'sha1');
$encrypted = openssl_encrypt($data, $method, $hash, OPENSSL_RAW_DATA, $IVbytes);
return bin2hex($encrypted);
}
Related
I am able to verify the signature by using Nodejs crypto.createVerify whereas PHP: openssl_verify always return false.
Nodejs: Getting correct result
const encryptKey = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
const crypto = require('crypto');
var data = Buffer.from(JSON.stringify(vd), "utf-8");
var password = Buffer.from(encryptKey, "utf-8");
var hashPassword = crypto.createHash('sha256').update(password).digest();
var data ='oubWLpvUHAX5Z/9fmiCx8PGTqDl0+2sCShXnTdW640q7O1MDybxmDCF0R9SvvgFygFJfGVybK0qndePkJz690Lu96TiAi648PEPfrPjmtOSBLovVjNiIvdI1i16ryJ5BdtT/lp4rWe1LTyXeiRZ8KdVoqKeg76GCQi0jfXG9wUDJgt8tc1qf+ey3jvqa5J04v/fEXhQVoKC6pFwLgvN7HLyXwpRx2UnmP6Szm37QffiVO7uo1IiY3PB0Wh/AXNMIRSKz3Qn6v2iTTDt8k/r2qADNS4c6FaxFrQlNljr7z6t9k3QCTD0gqHy9YlZAFLB1Fi7kspBmnoQpAlweMIf97MfZvE5aXQDRyP7XVlY1upFyfkItyJwVsCLG1D2+jiJfw/VUZ4m2E7GwewsvcZ86Wf4Q0yeI8Ot/im3lw4SA/EXASuj0C6PkxjCjucktyjazpY5Eq0mSHWjhlw/LPVIPIjT6SCtYJId9vxeed95wcgyRjF4IIIwr8KFT4gqHi5BMW0z2r/EPGgNP4eMpMcxCNIz63f6j4/vFmr0ddxqZsDwaUVzGflRu3NO/kkWZdALw63Y1ABV9tl7hSSQdxYegzgZQPiK2oa/RT+0QvosmjjSEvdVCzA+0upt9PM7aHpv7xSdfa8RzaswwFuI9hlj9ZS5rxWf2czNISuqxXfvvKLDlSVlg9m3uRiVVslaoxLzktArW0SBej+7Ly934A5MXQXyhxJG47AEREeduGMw+kAVcEp/OUckmQbrg76IevxydMloa+jwI48ewzgC9J+ZXngg+GNQUh8p8rU2p9JEpUPQ/D/I68quncnuyxWNuEGIh';
var signature = 'xKS+T/p56Yt417SWDpGEMSbdlSrpnudVH6F8ajMw5DorGdh/oTodNq+4rvdWYfQYC4xUTIqwDohAqVqG0smT3dcIda2NiG+sWEJC7iJu4PhDorvcF7P2iwLf942JFaGgyC4dvtmGubV/bs7Eu7bjV7i11YDQJm4kRscWAXF1JskUX89VW2IGya+YdU//aM/eBzNJx1UofGOKLK0SPAkL2E8Ua9o/dk4RZWO/cgjGCQe/KSjpoAsErk+XJLV8DNNzbsLH/3aNANVEkS4jlBLT0TWKHDTZ9ht90ISYt8xFvjcxnrhVsnlWp6di2GNazxi3hIKraCAnIcu1oA0ofp9CjQ==';
const salt = new Buffer.from([1, 2, 3, 4, 5, 6, 7, 8], "utf-8");
var nodeCrypto = crypto.pbkdf2Sync(hashPassword, salt, 1000, 48, 'sha1');
var key = nodeCrypto.slice(0, 32);
var iv = nodeCrypto.slice(32, 48);
var ciperDec = crypto.createDecipheriv('aes-256-cbc', key, iv);
var dataDec = ciperDec2.update(data,"base64","utf8");
dataDec+= ciperDec2.final("utf8");
var verifier = crypto.createVerify('RSA-SHA256');
var data = Buffer.from(dataDec2, "utf-8");
verifier.update(data);
var merchantPublicKey = '';//something
var verify = verifier.verify(merchantPublicKey, signature,'base64');
console.log("verify", verify); //return true
PHP: Returning false
$data ='oubWLpvUHAX5Z/9fmiCx8PGTqDl0+2sCShXnTdW640q7O1MDybxmDCF0R9SvvgFygFJfGVybK0qndePkJz690Lu96TiAi648PEPfrPjmtOSBLovVjNiIvdI1i16ryJ5BdtT/lp4rWe1LTyXeiRZ8KdVoqKeg76GCQi0jfXG9wUDJgt8tc1qf+ey3jvqa5J04v/fEXhQVoKC6pFwLgvN7HLyXwpRx2UnmP6Szm37QffiVO7uo1IiY3PB0Wh/AXNMIRSKz3Qn6v2iTTDt8k/r2qADNS4c6FaxFrQlNljr7z6t9k3QCTD0gqHy9YlZAFLB1Fi7kspBmnoQpAlweMIf97MfZvE5aXQDRyP7XVlY1upFyfkItyJwVsCLG1D2+jiJfw/VUZ4m2E7GwewsvcZ86Wf4Q0yeI8Ot/im3lw4SA/EXASuj0C6PkxjCjucktyjazpY5Eq0mSHWjhlw/LPVIPIjT6SCtYJId9vxeed95wcgyRjF4IIIwr8KFT4gqHi5BMW0z2r/EPGgNP4eMpMcxCNIz63f6j4/vFmr0ddxqZsDwaUVzGflRu3NO/kkWZdALw63Y1ABV9tl7hSSQdxYegzgZQPiK2oa/RT+0QvosmjjSEvdVCzA+0upt9PM7aHpv7xSdfa8RzaswwFuI9hlj9ZS5rxWf2czNISuqxXfvvKLDlSVlg9m3uRiVVslaoxLzktArW0SBej+7Ly934A5MXQXyhxJG47AEREeduGMw+kAVcEp/OUckmQbrg76IevxydMloa+jwI48ewzgC9J+ZXngg+GNQUh8p8rU2p9JEpUPQ/D/I68quncnuyxWNuEGIh';
$sign = 'xKS+T/p56Yt417SWDpGEMSbdlSrpnudVH6F8ajMw5DorGdh/oTodNq+4rvdWYfQYC4xUTIqwDohAqVqG0smT3dcIda2NiG+sWEJC7iJu4PhDorvcF7P2iwLf942JFaGgyC4dvtmGubV/bs7Eu7bjV7i11YDQJm4kRscWAXF1JskUX89VW2IGya+YdU//aM/eBzNJx1UofGOKLK0SPAkL2E8Ua9o/dk4RZWO/cgjGCQe/KSjpoAsErk+XJLV8DNNzbsLH/3aNANVEkS4jlBLT0TWKHDTZ9ht90ISYt8xFvjcxnrhVsnlWp6di2GNazxi3hIKraCAnIcu1oA0ofp9CjQ==';
$pass = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
$hashPass = hash("sha256",mb_convert_encoding($pass,"UTF-8"),true);
$salt = implode('', array_map('chr', [ 1, 2, 3, 4, 5, 6, 7, 8 ]));
$pbkdf2 = hash_pbkdf2("SHA1", $hashPass, $salt, 1000, 48,true);
$key = substr($pbkdf2, 0, 32);
$iv = substr($pbkdf2, 32, 48);
$hash = openssl_decrypt($data, 'aes-256-cbc', $key, OPENSSL_ZERO_PADDING, $iv);
$pubkeyid = openssl_get_publickey($publicKey);
$verified = openssl_verify($hash, $sign, $pubkeyid, OPENSSL_ALGO_SHA256);
echo $verified; //returning false
// Free the key.
openssl_free_key($pubkeyid);
I have got a decryption code that uses deprecated mcrypt, I need to convert this function to use openssl instead. There are many similar questions on Stackoverflow, but they did not help me.
here is the decryption function:
public function decrypt($str, $key){
//input
$str = '9ACF38C842B3522415364850EAD1909BD43FD590BE3CBD539AD5FF6C7465973ABD61E8371E03282605ED06C994DF394244B7E7DAD54A046510484FAA724330C4C95A527D7891151E7C195D4136CBD70A87D1BD1F75473CF6B45A3F2FA8231DD71FFB4150E0BF4B133ECAA5ACC82CFD74903E21BC6EECB4B33AF39B8AF0C183A64002CFC125A55685C69A13192F3A9A4FDAC860E90C3FB6D125285E9E687BEFBE05707E131FC7ABE25FE35AB114FAE8A247B8C0F3DBA8AA74396D10564B7A0617EED913ED';
$key = '10,10,10,10,10,10,10,10';
//expected output:
//'6706598320;67005551;100;00;YKB_TST_090519001330;0;0;https://setmpos.ykb.com/PosnetWebService/YKBTransactionService;posnettest.ykb.com;2225;N;0;Not authenticated;1557398383820;TL'
outputsrand((double) microtime() * 10000000);
$block = #mcrypt_get_block_size(MCRYPT_TripleDES, MCRYPT_MODE_CBC);
$td = #mcrypt_module_open(MCRYPT_TripleDES, '', MCRYPT_MODE_CBC, '');
$ks = #mcrypt_enc_get_key_size($td);
if (strlen($str) < 16 + 8) return false;
// Get IV
$iv = pack("H*", substr($str, 0, 16));
// Get Encrypted Data
$encrypted_data = pack("H*", substr($str, 16, strlen($str)-16-8));
// Get CRC
$crc = substr($str, -8);
// Check CRC
/*if (!$this->checkCrc(substr($str, 0, strlen($str)-8), $crc)) {
return "CRC is not valid! ($crc)";
}*/
// Initialize
#mcrypt_generic_init($td, substr(strtoupper(md5($key)), 0, $ks), $iv);
// Decrypt Data
$decrypted_data = #mdecrypt_generic($td, $encrypted_data);
$packing = ord($decrypted_data[strlen($decrypted_data) - 1]);
if ($packing and ($packing < $block)) {
for($P = strlen($decrypted_data) - 1; $P >= strlen($decrypted_data) - $packing; $P--) {
if (ord($decrypted_data[$P]) != $packing) {
$packing = 0;
}
}
}
return substr($decrypted_data, 0, strlen($decrypted_data) - $packing);
I tried:
$encrypted_data = pack("H*", substr($str, 16, strlen($str)-16-8));
$iv = pack("H*", substr($str, 0, 16));
/returns FALSE when sample input above given
$decrypted_data = openssl_decrypt($encrypted_data, 'des-ede3-cbc', $key, OPENSSL_RAW_DATA, $iv);
Can anybody help me please?
I missed key transformation step, doing this way worked:
$decrypted_data = openssl_decrypt($encrypted_data, 'des-ede3-cbc', substr(strtoupper(md5($key)), 0, 24), OPENSSL_RAW_DATA, $iv);
I have javascript code for encryption like this :
var myPassword = '12345*abc';
var encrypted = CryptoJS.AES.encrypt(myString, myPassword);
document.getElementById("demo1").innerHTML = encrypted;
and I have a decryption function with php like this :
function decrypt($ciphertext, $key) {
$ciphertext = base64_decode($ciphertext);
if (substr($ciphertext, 0, 8) != "Salted__") {
return false;
}
$salt = substr($ciphertext, 8, 8);
$keyAndIV = evpKDF($key, $salt);
$decryptPassword = openssl_decrypt(
substr($ciphertext, 16),
"aes-256-cbc",
$keyAndIV["key"],
OPENSSL_RAW_DATA, // base64 was already decoded
$keyAndIV["iv"]);
return $decryptPassword;
}
function evpKDF($password, $salt, $keySize = 8, $ivSize = 4, $iterations = 1, $hashAlgorithm = "md5") {
$targetKeySize = $keySize + $ivSize;
$derivedBytes = "";
$numberOfDerivedWords = 0;
$block = NULL;
$hasher = hash_init($hashAlgorithm);
while ($numberOfDerivedWords < $targetKeySize) {
if ($block != NULL) {
hash_update($hasher, $block);
}
hash_update($hasher, $password);
hash_update($hasher, $salt);
$block = hash_final($hasher, TRUE);
$hasher = hash_init($hashAlgorithm);
// Iterations
for ($i = 1; $i < $iterations; $i++) {
hash_update($hasher, $block);
$block = hash_final($hasher, TRUE);
$hasher = hash_init($hashAlgorithm);
}
$derivedBytes .= substr($block, 0, min(strlen($block), ($targetKeySize - $numberOfDerivedWords) * 4));
$numberOfDerivedWords += strlen($block)/4;
}
return array(
"key" => substr($derivedBytes, 0, $keySize * 4),
"iv" => substr($derivedBytes, $keySize * 4, $ivSize * 4)
);
}
so far it works fine, and now I want to encrypt the string with the php function, I try to use a function like the code below, but it doesn't work,
function encrypt($string, $key) {
$salt = substr($string, 8, 8);
$keyAndIV = evpKDF($key, $string);
$encryptPassword = openssl_encrypt(
$string,
"aes-256-cbc",
$keyAndIV["key"],
OPENSSL_RAW_DATA,
$keyAndIV["iv"]);
return $encryptPassword;
}
can anyone help me please, how can I fix this issue, thanks.
I have to encrypt a string to an 8 byte hex using TDES. Below are the values (modified for reference)
key = 636948778095358323114731
pin=1234
Code for encryption :
function encryptText_3des($plainText, $key) {
$key = hash("md5", $key, TRUE);
for ($x=0;$x<8;$x++) {
$key = $key.substr($key, $x, 1);
}
$padded = pkcs5_pad($plainText,mcrypt_get_block_size(MCRYPT_3DES, MCRYPT_MODE_CBC));
$encrypted = base64_encode(mcrypt_encrypt(MCRYPT_3DES, $key, $padded, MCRYPT_MODE_CBC));
return $encrypted;
}
function pkcs5_pad ($text, $blocksize) {
$pad = $blocksize - (strlen($text) % $blocksize);
return $text . str_repeat(chr($pad), $pad);
}
However when i do this :
//outputs 3des encrypted data
echo encryptText_3des($data, $encryption_key);
I get this error :
Warning: mcrypt_encrypt(): Encryption mode requires an initialization
vector of size 8
How can i get the value ?..(please i also need it as a 8 byte hex..)
Thanks
You miss initialization vector for encryption function:
function encryptText_3des($plainText, $key)
{
$key = hash("md5", $key, TRUE);
for ($x = 0; $x < 8; $x++) {
$key = $key . substr($key, $x, 1);
}
$padded = pkcs5_pad($plainText,mcrypt_get_block_size(MCRYPT_3DES, MCRYPT_MODE_CBC));
// CBC initialization vector
$iv_size = mcrypt_get_iv_size(MCRYPT_3DES, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$encrypted = base64_encode(mcrypt_encrypt(MCRYPT_3DES, $key, $padded, MCRYPT_MODE_CBC, $iv));
return $encrypted;
}
Also do not forget to save $iv string somewhere (include in encrypted string for example), because IV bytes are required for TDES decryption procedure later.
See also
I have the following Visual Basic .NET function that is used to encrypt a file. This function is from third party so I cannot alter the original code.
Dim bytes As Byte() = New UnicodeEncoding().GetBytes("12345678")
Dim fileStream1 As FileStream = New System.IO.FileStream(txtInput.Text, FileMode.Create)
Dim rijndaelManaged As RijndaelManaged = New RijndaelManaged
Dim cryptoStream1 As CryptoStream = New CryptoStream(fileStream1, rijndaelManaged.CreateEncryptor(bytes, bytes), CryptoStreamMode.Write)
Dim fileStream2 As FileStream = New System.IO.FileStream(txtOutput.Text, FileMode.Open)
Dim BytesRead As Integer
Dim buffer(4096) As Byte
Do
BytesRead = fileStream2.Read(buffer, 0, buffer.Length)
If BytesRead > 0 Then
cryptoStream1.Write(buffer, 0, BytesRead)
End If
Loop While BytesRead > 0
I need help creating a PHP to decrypt the above function. Currently I tried to decrypt using this function in PHP:
function decrypt($text) {
$key = mb_convert_encoding("12345678","utf-16");
$iv = mb_convert_encoding("12345678","utf-16");
return rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $text, MCRYPT_MODE_CBC, $iv), "\0");
}
$decrypted=decrypt(file_get_contents("tes_encrypted.xml"));
$nfile = fopen("test.xml", 'w');
fwrite($nfile, $decrypted);
fclose($nfile);
As you can see the encryption function in VB.NET use a predefined Key and IV. It also doesn't specify a padding method. The PHP function generates different result.
Finally I got the answer. Here the correct PHP code to decrypt the VB.NET encryption above:
function unpad($value)
{
$blockSize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$packing = ord($value[strlen($value) - 1]);
if($packing && $packing < $blockSize)
{
for($P = strlen($value) - 1; $P >= strlen($value) - $packing; $P--)
{
if(ord($value{$P}) != $packing)
{
$packing = 0;
}
}
}
return substr($value, 0, strlen($value) - $packing);
}
function decrypt($text) {
$key= mb_convert_encoding("12345678","ucs-2LE");
$iv= mb_convert_encoding("12345678","ucs-2LE");
return unpad(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $text, MCRYPT_MODE_CBC, $iv));
}