PHP DES Encryption compatible with Delphi - encryption function - php

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

Related

convert mcrypt algorithm to openssl PHP (MCRYPT_TripleDES, MCRYPT_MODE_CBC)

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);

how is the encryption method using CryptoJS using the correct php function

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.

Triple DES Encryption of String To 8 byte hex

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

PHP function to decrypt a VB.NET RijndaelManaged class encryption

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));
}

encode by php and decode by js

because of gfw(great firewall) in our country , I have to encode content within http transfer (https is better , but its a second choice).
my way is use base64 encode by php and decode by js , then show in an iframe. but there's some problem in FF.
is there any better way to show base64 encoded string in browser , or another way to encode/decode ?
Try Something this:
function get_rnd_iv($iv_len)
{
$iv = '';
while ($iv_len-- > 0) {
$iv .= chr(mt_rand() & 0xff);
}
return $iv;
}
function md5_encrypt($string_value, $salt_key, $iv_len = 16)
{
$string_value .= "\x13";
$n = strlen($string_value);
if ($n % 16) $string_value .= str_repeat("\0", 16 - ($n % 16));
$i = 0;
$enc_text = get_rnd_iv($iv_len);
$iv = substr($salt_key ^ $enc_text, 0, 512);
while ($i < $n) {
$block = substr($string_value, $i, 8) ^ pack('H*', md5($iv));
$enc_text .= $block;
$iv = substr($block . $iv, 0, 512) ^ $salt_key;
$i += 16;
}
return urlencode(base64_encode($enc_text));
}
function md5_decrypt($enc_text, $salt_key, $iv_len = 16)
{
$enc_text = urldecode(base64_decode($enc_text));
$n = strlen($enc_text);
$i = $iv_len;
$string_value = '';
$iv = substr($salt_key ^ substr($enc_text, 0, $iv_len), 0, 512);
while ($i < $n) {
$block = substr($enc_text, $i, 8);
$string_value .= $block ^ pack('H*', md5($iv));
$iv = substr($block . $iv, 0, 512) ^ $salt_key;
$i += 16;
}
return preg_replace('/\\x13\\x00*$/', '', $string_value);
}
You could just set the innerHTML property of the body of the page...
As long as the encoded string that the JS is producing is valid HTML for the whole body, it should work fine, and then you don't have to do anything messy with iframes or whatever.

Categories