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
Related
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 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);
}
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));
}
I am trying to create the encrypt PHP algorithm from this thread:
how to sync encryption between delphi and php using dcpcrypt (see shunty's reply)
Here is what I have so far:
function encrypt($str, $key)
{
$keysize = mcrypt_get_key_size(MCRYPT_DES, MCRYPT_MODE_CBC);
$ivbytes = array(72, 163, 99, 62, 219, 111, 163, 114);
$iv = implode(array_map("chr", $ivbytes));
$pad = ord($str[strlen($str) - 1]);
$enc = substr($str, 0, strlen($str) - $pad);
$enc = base64_encode($str);
$k = mhash(MHASH_SHA1, $key);
//return substr($dec, 0, strlen($dec) - $pad);
$dec = mcrypt_encrypt(MCRYPT_DES, substr($k, 0, $keysize), $enc, MCRYPT_MODE_CBC, $iv);
return $dec;
}
I'm not sure what I'm doing wrong but testing it with this:
echo encrypt("this is a test", "test");
Gives the output: =ž«RCdrçb˜hý’¯á·OÊ
when it should give: WRaG/8xlxqqcTAJ5UAk4DA==
Can anyone help me out in explaining where I am going wrong, would really appreciate the help I can get.
EDIT:
function encrypt_SO($str, $key)
{
$keysize = mcrypt_get_key_size(MCRYPT_DES, MCRYPT_MODE_CBC);
$ivbytes = array(72, 163, 99, 62, 219, 111, 163, 114);
$iv = implode(array_map("chr", $ivbytes));
$pad = ord($str[strlen($str) - 1]);
$enc = substr($str, 0, strlen($str) - $pad);
$k = mhash(MHASH_SHA1, $key);
//return substr($dec, 0, strlen($dec) - $pad);
$dec = mcrypt_encrypt(MCRYPT_DES, substr($k, 0, $keysize), $enc, MCRYPT_MODE_CBC, $iv);
return base64_encode($dec);
}
Moved the encoding to the end.
EDIT 2: Solution thanks to everyone's helpful posts:
function encrypt_SO($str, $key)
{
$keysize = mcrypt_get_key_size(MCRYPT_DES, MCRYPT_MODE_CBC);
$ivbytes = array(72, 163, 99, 62, 219, 111, 163, 114);
$iv = implode(array_map("chr", $ivbytes));
$k = mhash(MHASH_SHA1, $key);
$blocksize = mcrypt_get_block_size(MCRYPT_DES, MCRYPT_MODE_CBC);
$padsize = $blocksize - (strlen($str) % $blocksize);
$str .= str_repeat(chr($padsize), $padsize);
return base64_encode(mcrypt_encrypt(MCRYPT_DES, substr($k, 0, $keysize), $str, MCRYPT_MODE_CBC, $iv));
}
To answer your comment above:
Encrypt:
Get keysize and blocksize
Get IV - this should really be something random and properly generated but to work with DCPcrypt without specifying an IV manually you need to use the one provided.
Hash the key
Add the padding - you've got this bit wrong. For this example you need something like:
$blocksize = mcrypt_get_block_size(MCRYPT_DES, MCRYPT_MODE_CBC);
$padsize = $blocksize - (strlen($str) % $blocksize);
$str .= str_repeat(chr($padsize), $padsize);
Encrypt
Base64 encode
Decrypt:
Get keysize
Get IV - as above (must be the same as the one used to encrypt but, again, should really be properly cryptographically generated).
Hash the key
Base64 decode
Decrypt
Remove the padding