How do i transform a string into an openssl_encrypt string? - php

i have to translate a string into openssl encrypt AES-256.
The agency gave me a code snippet how they translate the code in VB.net
Dim iv As Byte() = {&HDB, &H84, &H95, &HBD, &HDA, &HD5, &HD3, &HF8, &HCE, &H81, &H9C, &HA5, &HB3, &H8B, &H24, &H54} (16 Character)
the password is already a hex-code "4093f94891...."
i want to use the following function
openssl_encrypt($string, $encrypt_method, $key, $option, $iv);
$string = "my string"
$encrypt_method = "AES-256-CBC"
$key = "4093f94891...."
$option = 0
$iv = ???
How do i translate the iv as byte() ?
Dim iv As Byte() = {&HDB, &H84, &H95, &HBD, &HDA, &HD5, &HD3, &HF8,
&HCE, &H81, &H9C, &HA5, &HB3, &H8B, &H24, &H54} (16 Character) in
PHP ?

Related

Convert VB.NET Encrypt/Decript old code to PHP 5.3

I am trying to convert VB.NET Encrypt/Decrypt to PHP. The issue is we can not update the PHP version and the server supports only PHP5.3
VB.NET Sample Output Link
http://www.tattoogenda.com/LoginTest.aspx
VB.NET Output is: Ao5ZnFYo344iWqv/Jr9euw==
PHP OutPut is: NzmRRxTaXgWFIPx/SqODog==
VB.NET Code as below:
Public Shared Function Encrypt(clearText As String) As String
Dim EncryptionKey As String = "MAKV2SPBNI99212"
Dim clearBytes As Byte() = Encoding.Unicode.GetBytes(clearText)
Using encryptor As Aes = Aes.Create()
Dim pdb As New Rfc2898DeriveBytes(EncryptionKey, New Byte() {&H49, &H76, &H61, &H6E, &H20, &H4D,
&H65, &H64, &H76, &H65, &H64, &H65,
&H76})
encryptor.Key = pdb.GetBytes(32)
encryptor.IV = pdb.GetBytes(16)
Using ms As New MemoryStream()
Using cs As New CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write)
cs.Write(clearBytes, 0, clearBytes.Length)
cs.Close()
End Using
clearText = Convert.ToBase64String(ms.ToArray())
End Using
End Using
Return clearText
End Function
Public Shared Function Decrypt(cipherText As String) As String
Dim EncryptionKey As String = "MAKV2SPBNI99212"
Dim cipherBytes As Byte() = Convert.FromBase64String(cipherText)
Using encryptor As Aes = Aes.Create()
Dim pdb As New Rfc2898DeriveBytes(EncryptionKey, New Byte() {&H49, &H76, &H61, &H6E, &H20, &H4D,
&H65, &H64, &H76, &H65, &H64, &H65,
&H76})
encryptor.Key = pdb.GetBytes(32)
encryptor.IV = pdb.GetBytes(16)
Using ms As New MemoryStream()
Using cs As New CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write)
cs.Write(cipherBytes, 0, cipherBytes.Length)
cs.Close()
End Using
cipherText = Encoding.Unicode.GetString(ms.ToArray())
End Using
End Using
Return cipherText
End Function
PHP Test link Output:
http://www.tattoogenda.com/app-api/logintest.php
PHP Code:
<?php
include_once('PBKDF2.php');
use PBKDF2\PBKDF2;
function encrypt_decrypt($action, $string) {
$output = false;
$encrypt_method = "AES-256-CBC";
//$encrypt_method = "AES-128-CBC";
$secret_key = 'MAKV2SPBNI99212';
$secret_iv=chr(0x49).chr(0x76).chr(0x61).chr(0x6e).chr(0x20).chr(0x4d).chr(0x65).chr(0x64).chr(0x76).chr(0x65).chr(0x64).chr(0x65).chr(0x76);
$generated_key = PBKDF2::deriveKey("sha256", $secret_key, $secret_iv, 20000, 128, true, false);
$key = substr($generated_key, 0, 32);;
//$key = substr(hash('sha1', $secret_key), 0, 32);;
echo "key: ".$key."<br>";
$iv = substr($generated_key, 0, 16);
//$iv = substr(hash('sha1', $secret_iv), 0, 16);
echo "iv key: ".$iv."<br>";
if( $action == 'encrypt' ) {
$output = openssl_encrypt($string, $encrypt_method, $key, $options=OPENSSL_RAW_DATA,$iv );
$output = base64_encode($output);
}
else if( $action == 'decrypt' ){
$output = openssl_decrypt(base64_decode($string), $encrypt_method, $key, $options=OPENSSL_RAW_DATA, $iv);
}
return $output;
}
$plain_txt = "1234";
echo "Plain Text = $plain_txt\n"."<br/>";
$plain_txt = mb_convert_encoding($plain_txt, "UTF-8" , "UTF-16LE");
echo "Encoded Plain Text = $plain_txt\n"."<br/>";
$encrypted_txt = encrypt_decrypt('encrypt', $plain_txt);
echo "Encrypted Text = $encrypted_txt\n"."<br/>";
$decrypted_txt = encrypt_decrypt('decrypt', $encrypted_txt);
echo "Decrypted Text = $decrypted_txt\n"."<br/>";
if( $plain_txt === $decrypted_txt ) echo "SUCCESS"."<br/>";
else echo "FAILED"."<br/>";
echo "\n"."<br/>";
?>
The VB code uses a 32 bytes key so in the PHP code AES-256-CBC is correct. Also Rfc2898DeriveBytes() applies an iteration count of 1000 by default (and SHA1 as digest), which must therefore also be used in the PHP code. Since the VB code derives both, the 32 bytes key and the IV, 32 + 16 must be specified as size in the PHP code:
$generated_key = PBKDF2::deriveKey("sha1", $secret_key, $secret_iv, 1000, 32+16, true, false);
Of the returned result, the first 32 bytes are the key, the following 16 bytes are the IV:
$key = substr($generated_key, 0, 32);
$iv = substr($generated_key, 32, 16);
$key and $iv are to be used directly in openssl_encrypt()/decrypt(), i.e. the explicit hashing with SHA1 is to be removed for key and IV.
The passed plaintext must be UTF-16LE encoded before encryption (either inside or outside of encrypt_decrypt()), e.g. with
$string = mb_convert_encoding($string, 'utf-16le', 'utf-8');
Note that the start encoding is the third parameter and the destination encoding is the second parameter.
An encryption of Hello Asif returns 1N1U0Oy81PGOm/Yqdp9sT5iyPgPFxsc8Q8mADNa8BzQ= in accordance with the VB code.
For decryption, the procedure is analogous.
Note that for security reasons the salt (denoted here as $secret_iv) should be randomly generated for each key derivation. The salt is not secret and can be sent along with the ciphertext (usually concatenated). Also, an iteration count of 1000 is generally too small for PBKDF2.
<?php
$text = "hello";
$enc = MCRYPT_RIJNDAEL_128;
$mode = MCRYPT_MODE_CBC;
$iv = mcrypt_create_iv(mcrypt_get_iv_size($enc, $mode), MCRYPT_DEV_URANDOM);
$keys = array();
// smaller than 128 bit key gets padded to 128 bit
$keys[] = pack('H*', "00112233445566778899aabbccddee");
$keys[] = pack('H*', "00112233445566778899aabbccddee00");
// larger than 128 bit key gets padded to 192 bit
$keys[] = pack('H*', "00112233445566778899aabbccddeeff00");
$keys[] = pack('H*', "00112233445566778899aabbccddeeff0000000000000000");
// larger than 192 bit key gets padded to 256 bit
$keys[] = pack('H*', "00112233445566778899aabbccddeeff001122334455667700");
$keys[] = pack('H*', "00112233445566778899aabbccddeeff00112233445566770000000000000000");
// larger than 256 bit key will be truncated (with a warning)
$keys[] = pack('H*', "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00");
foreach ($keys as $key)
{ echo base64encode(mcrypt_encrypt($enc, $key, $text, $mode, $iv))."\n";
}

Decrypting in PHP encrypted in VB

I have to decrypt data in PHP that was encrypted IN VB.
When I decrypt numbers I have no problem, but when I decrypt text I only get the first 8 characters and then random.
This is the key "a1R#f7D$"
This is what I am trying to decrypt:
LwEe+sQCn63m9kjtqiy67ul5R1Ng7SZPVO4YYxQvZtUZBwNTb+Ey0qCNsrczI4jN
And I get this:
{Preinsc]hn��m�ȕ�!��^߇� $! �E&;�e^#S�)6Ui�4�
I tried with MCRYPT_RIJNDAEL_256 and ecb but none worked to me.
function decrypt($data ){
$encryption_key = "a1R#f7D$";
$data = urldecode($data);
$key = md5(utf8_encode($encryption_key), true);
//Take first 8 bytes of $key and append them to the end of $key.
$key .= substr($key, 0, 8);
$data = base64_decode($data);
$data = mcrypt_decrypt('tripledes', $key, $data, 'ecb');
$block = mcrypt_get_block_size('tripledes', 'ecb');
$len = strlen($data);
$pad = ord($data[$len-1]);
return substr($data, 0, strlen($data) - $pad);
}
This is the function that encrypted this:
Public Shared Function tryingTripleDes (ByVal value As String, ByVal key As String) As String
Dim des As New Security.Cryptography.TripleDESCryptoServiceProvider
des.IV des.IV = New Byte(7) {}
Dim pdb As New Security.Cryptography.PasswordDeriveBytes(key, New Byte(-1) {})
des.Key = pdb.CryptDeriveKey("RC2", "MD5", 128, New Byte(7) {})
Dim ms As New IO.MemoryStream((value.Length * 2) - 1)
Dim encStream As New Security.Cryptography.CryptoStream(ms, des.CreateEncryptor(), Security.Cryptography.CryptoStreamMode.Write)
Dim plainBytes As Byte() = Text.Encoding.UTF8.GetBytes(value)
encStream.Write(plainBytes, 0, plainBytes.Length)
encStream.FlushFinalBlock()
Dim encryptedBytes(CInt(ms.Length - 1)) As Byte
ms.Position = 0
ms.Read(encryptedBytes, 0, CInt(ms.Length))
encStream.Close()
Return Convert.ToBase64String(encryptedBytes)
End Function
This would typically happen if the ciphertext is CBC encrypted with an all zero byte IV. Other modes may also work, but CBC is by far the most likely. Your key and cipher are correct, otherwise you will only get garbage in return - certainly not legible text.
Note that MCRYPT_RIJNDAEL_256 is not even AES, so trying that is kind of useless, you should use MCRYPT_RIJNDAEL_128 with a correctly sized key to get AES.
I won't go into the security of CBC with a zero byte IV and deprecated cipher like 3DES. It's not a good idea, especially not for transport security.

Convert VB.NET AES encoding to PHP using openssl_decrypt

Currently I'm working on integration of external service wrote in VB.NET.
This service send me a string with some information encrypted with below function (this is a cut and past from the external service developer that send me the code)
Public Function Decode(ByVal S As String, ByVal chiave As String, ByVal iv As String) As String
Dim rjm As RijndaelManaged = New RijndaelManaged
rjm.KeySize = 128
rjm.BlockSize = 128
rjm.Key = System.Text.ASCIIEncoding.ASCII.GetBytes(chiave)
rjm.IV = System.Text.ASCIIEncoding.ASCII.GetBytes(iv)
Try
Dim input() As Byte = System.Convert.FromBase64String(S)
Dim output() As Byte = rjm.CreateDecryptor.TransformFinalBlock(input, 0, input.Length)
Return System.Text.Encoding.UTF8.GetString(output)
Catch ex As System.Exception
Return S
End Try
End Function
if I decode the string with below mcrypt function everything work as expected:
$mcrypt_cipher = MCRYPT_RIJNDAEL_128;
$mcrypt_mode = MCRYPT_MODE_CBC;
$iv= '1234567891011121';
$key = '1234567891011121';
$message= base64_decode($message);
$message = rtrim(mcrypt_decrypt($mcrypt_cipher, $key, $message, $mcrypt_mode, $iv), "\0");;
But i'm unable to obtain same result with openssl_decrypt. the function always fail with false as result, below the code:
$result = openssl_decrypt(
base64_decode($message),
'AES-128-CBC',
$key,
OPENSSL_RAW_DATA,
$iv
);
I'm pretty sure that the problem is related to some padding that i missing.. but I don't understand where the problem is exactly.
UPDATE1 -
I correct the code, both $iv and $key are strings i forgot the ' both are of 16Bytes = 128Bits

Rijndael in PHP

I am trying to encrypt a string with a key and iv with Rijndael in PHP.
I have wrote this in VB .Net and the result is the expected one:
'This is the byte Array of "1234567890ABCDEF1234567890ABCDEF". I am using this for IV
Private _key1 As Byte() = New Byte(15) {CByte(18), CByte(52), CByte(86), CByte(120), CByte(144), CByte(171), _
CByte(205), CByte(239), CByte(18), CByte(52), CByte(86), CByte(120), _
CByte(144), CByte(171), CByte(205), CByte(239)}
Public Sub Init()
Dim sKey As String = "D6850B89370BD603BD48CEAD43488639DE3ABE73D2CF7C54B0CF72D2FB06E162"
Dim resBytes As Byte() = Me.EncryData("a", sKey)
File.WriteAllBytes("C:/myFile.txt", resBytes)
End Sub
Public Function EncryData(sPath As String, sKey As String) As Byte()
Return Me.AESEncrypt(plainText, Me.Data_Hex_Asc(sKey))
End Function
Public Function Data_Hex_Asc(ByRef Data As String) As Byte()
Dim str1 As String = ""
Dim list As New List(Of Byte)()
While Data.Length > 0
Dim num As Integer = CInt(Convert.ToChar(Convert.ToUInt32(Data.Substring(0, 2), 16)))
Dim str2 As String = Convert.ToChar(Convert.ToUInt32(Data.Substring(0, 2), 16)).ToString()
list.Add(CByte(Convert.ToUInt32(Data.Substring(0, 2), 16)))
str1 += str2
Data = Data.Substring(2, Data.Length - 2)
End While
Return list.ToArray()
End Function
Public Function AESEncrypt(plainText As String, aByte As Byte()) As Byte()
Dim symmetricAlgorithm As SymmetricAlgorithm = DirectCast(Rijndael.Create(), SymmetricAlgorithm)
Dim bytes As Byte() = Encoding.UTF8.GetBytes(plainText)
symmetricAlgorithm.Key = aByte
symmetricAlgorithm.IV = Me._key1
Dim memoryStream As New MemoryStream()
Dim cryptoStream As New CryptoStream(DirectCast(memoryStream, Stream), symmetricAlgorithm.CreateEncryptor(), CryptoStreamMode.Write)
cryptoStream.Write(bytes, 0, bytes.Length)
cryptoStream.FlushFinalBlock()
Dim numArray As Byte() = memoryStream.ToArray()
cryptoStream.Close()
memoryStream.Close()
Return numArray
End Function
Now the PHP version of that:
$AES_KEY = "D6850B89370BD603BD48CEAD43488639DE3ABE73D2CF7C54B0CF72D2FB06E162";
$key = pack('H*', $AES_KEY);
$plaintext = "a"; ;
$iv = pack('H*', "1234567890ABCDEF1234567890ABCDEF");
$enc_text = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $plaintext, MCRYPT_MODE_CBC, $iv);
The result from PHP code is different from the VB's.
Any suggestions for different php approach?
VB .net implementation of Rijndael uses as default padding: PKCS7 and mode: CBC
Results: vb .net: PFΑ&\O?„\LϋAμCt php:_yJ_½%sAj«SUhA
16 chars length, both of them.

.Net and PHP Rijndael encryption not matching

At first i thought it was the padding since mcrypt uses zero padding but i changed the php to use PKCS7 and get the same exact results
Can anyone help? I think it has something to do with the padding in the php
Test output from .Net:
Key: d88f92e4fa27f6d45b49446c7fc76976
Text: Testing123
Encrypted: /DMkj7BL9Eu2LMxKhdGT+A==
Encrypted after base64 decode: ?3$??K?K?,?J???
Decrypted: Testing123
Test output from PHP:
Key: d88f92e4fa27f6d45b49446c7fc76976
Text: Testing123
Encrypted: K+ke5FNI5T6F6B/XvDF494+S8538Ze83cFz6v1FE89U=
Encrypted after base64 decode: +éäSHå>…è×¼1x÷’óüeï7p\ú¿QDóÕ
Decrypted: Testing123����������������������
PHP:
class rijndael{
var $mcrypt_cipher = MCRYPT_RIJNDAEL_256;
var $mcrypt_mode = MCRYPT_MODE_CBC;
function decrypt($pass, $encrypted)
{
$encrypted = base64_decode($encrypted);
$key = $this->getkey($pass);
$iv = $this->getiv($pass);
$decrypted = mcrypt_decrypt($this->mcrypt_cipher, $key, $encrypted, $this->mcrypt_mode, $iv);
$block = mcrypt_get_block_size($this->mcrypt_cipher, $this->mcrypt_mode);
$pad = ord($decrypted[($len = strlen($decrypted)) - 1]);
return substr($decrypted, 0, strlen($decrypted) - $pad);
}
function encrypt($pass, $decrypted)
{
$key = $this->getkey($pass);
$iv = $this->getiv($pass);
$block = mcrypt_get_block_size($this->mcrypt_cipher, $this->mcrypt_mode);
$pad = $block - (strlen($str) % $block);
$str .= str_repeat(chr($pad), $pad);
$encrypted = mcrypt_encrypt($this->mcrypt_cipher, $key, $decrypted, $this->mcrypt_mode, $iv);
return base64_encode($encrypted);
}
function getkey($passphrase)
{
$L1 = base64_encode(hash("sha256", $passphrase, true));
$L2 = $passphrase.$L1;
return hash("sha256", $L2, true);
}
function getiv($passphrase)
{
$L1 = base64_encode(md5($passphrase));
$L2 = $passphrase.$L1;
return md5($L2);
}
}
VB .Net:
Public Class RijnDael
Public Shared Function Decrypt(ByVal sData As String, ByVal sKey As String)
Dim bytData() As Byte = Encoding.UTF8.GetBytes(sData)
Return Decrypt(bytData, sKey)
End Function
Public Shared Function Decrypt(ByVal bytData As Byte(), ByVal strPass As String) As Byte()
Dim bytResult As Byte()
Using oRM As New System.Security.Cryptography.RijndaelManaged
oRM.KeySize = 256
oRM.Key = GeKey(strPass)
oRM.IV = GetIV(strPass)
oRM.Mode = CipherMode.CBC
oRM.Padding = PaddingMode.PKCS7
Using oMS As New MemoryStream(bytData)
Using oCS As New Cryptography.CryptoStream(oMS, oRM.CreateDecryptor, Security.Cryptography.CryptoStreamMode.Read)
Dim TempDecryptArr As Byte()
ReDim TempDecryptArr(bytData.Length)
Dim decryptedByteCount As Integer
decryptedByteCount = oCS.Read(TempDecryptArr, 0, bytData.Length)
'
ReDim bytResult(decryptedByteCount)
Array.Copy(TempDecryptArr, bytResult, decryptedByteCount)
'
oCS.Close()
End Using
oMS.Close()
End Using
End Using
Return bytResult
End Function
Public Shared Function Encrypt(ByVal sData As String, ByVal sKey As String)
Dim bytData() As Byte = Encoding.UTF8.GetBytes(sData)
Return Encrypt(bytData, sKey)
End Function
Public Shared Function Encrypt(ByVal bytData As Byte(), ByVal strPass As String) As Byte()
Dim bytResult As Byte()
Using oRM As New Cryptography.RijndaelManaged
oRM.KeySize = 256
oRM.Key = GeKey(strPass)
oRM.IV = GetIV(strPass)
oRM.Mode = CipherMode.CBC
oRM.Padding = PaddingMode.PKCS7
Using oMS As New MemoryStream
Using oCS As New Cryptography.CryptoStream(oMS, oRM.CreateEncryptor, Cryptography.CryptoStreamMode.Write)
oCS.Write(bytData, 0, bytData.Length)
oCS.FlushFinalBlock()
bytResult = oMS.ToArray()
oCS.Close()
End Using
oMS.Close()
End Using
End Using
Return bytResult
End Function
Private Shared Function GeKey(ByVal strPass As String) As Byte()
Dim bytResult As Byte()
'Generate a byte array of required length as the encryption key.
'A SHA256 hash of the passphrase has just the required length. It is used twice in a manner of self-salting.
Using oSHA256 As New Cryptography.SHA256Managed
Dim L1 As String = System.Convert.ToBase64String(oSHA256.ComputeHash(Encoding.UTF8.GetBytes(strPass)))
Dim L2 As String = strPass & L1
bytResult = oSHA256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(L2))
oSHA256.Clear()
End Using
Return bytResult
End Function
Private Shared Function GetIV(ByVal strPass As String) As Byte()
Dim bytResult As Byte()
'Generate a byte array of required length as the iv.
'A MD5 hash of the passphrase has just the required length. It is used twice in a manner of self-salting.
Using oMD5 As New Cryptography.MD5CryptoServiceProvider
Dim L1 As String = System.Convert.ToBase64String(oMD5.ComputeHash(Encoding.UTF8.GetBytes(strPass)))
Dim L2 As String = strPass & L1
bytResult = oMD5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(L2))
oMD5.Clear()
End Using
Return bytResult
End Function
End Class
The problems in your two pieces of code are:
Use Rijndael-128 with a key and block size of 16 bytes / 128 bit in both the .NET and the PHP code. For Rijndael-256, your code generates an IV with the wrong length. And I don't know how to use AES-256 in PHP (key length of 32 bytes / 256 bits, block size of 16 bytes / 128 bit).
Use of MD5: In the PHP code, add a second parameter true to the md5() function (in two places) so the result is binary data and not a hexadecimal string.
In the encrypt() function in your PHP code, replace the variable $str with $decrypted (in two places). $str is never assigned a value and never used, so the padding has no effect.
If you fix these problems, then both programs will return the result:
Encrypted: /DMkj7BL9Eu2LMxKhdGT+A==
I haven't tried to decrypt it.
For starters the 2 bits of code will create different initialization vectors (PHP is using sha256, and .net md5). And you're not truncating the PHP output by then first null char. There are several potential char set issues in the code too.

Categories