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 PBKDF2PBKDF2; 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_txtn"."<br/>"; $plain_txt = mb_convert_encoding($plain_txt, "UTF-8" , "UTF-16LE"); echo "Encoded Plain Text = $plain_txtn"."<br/>"; $encrypted_txt = encrypt_decrypt('encrypt', $plain_txt); echo "Encrypted Text = $encrypted_txtn"."<br/>"; $decrypted_txt = encrypt_decrypt('decrypt', $encrypted_txt); echo "Decrypted Text = $decrypted_txtn"."<br/>"; if( $plain_txt === $decrypted_txt ) echo "SUCCESS"."<br/>"; else echo "FAILED"."<br/>"; echo "n"."<br/>";
?>
Advertisement
Answer
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.