将 VB.NET 加密/解密旧代码转换为 PHP 5.3



我正在尝试将 VB.NET 加密/解密转换为PHP。问题是我们无法更新PHP版本,服务器仅支持PHP5.3

VB.NET 示例输出链接 http://www.tattoogenda.com/LoginTest.aspx

VB.NET 输出为:Ao5ZnFYo344iWqv/Jr9euw==

PHP 输出是: NzmRRxTaXgWFIPx/SqODog== VB.NET 代码如下:

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 测试链接输出: http://www.tattoogenda.com/app-api/logintest.php

PHP代码:

<?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/>";

?>

VB 代码使用 32 字节密钥,因此在 PHP 代码中AES-256-CBC是正确的。此外,Rfc2898DeriveBytes()默认应用迭代计数 1000(SHA1 作为摘要),因此也必须在 PHP 代码中使用。由于 VB 代码派生了 32 字节密钥和 IV,32 + 16 必须在 PHP 代码中指定为 size:

$generated_key =  PBKDF2::deriveKey("sha1", $secret_key, $secret_iv, 1000, 32+16, true, false);

在返回的结果中,前 32 个字节是键,后面的 16 个字节是 IV:

$key = substr($generated_key, 0, 32);
$iv = substr($generated_key, 32, 16);

$key和 $iv直接用于openssl_encrypt()/decrypt(),即 SHA1 的显式散列将被删除用于键和 IV。

传递的明文在加密之前必须进行 UTF-16LE 编码(在encrypt_decrypt()内部或外部),例如

$string =  mb_convert_encoding($string, 'utf-16le', 'utf-8');

请注意,开始编码是第三个参数,目标编码是第二个参数。

Hello Asif的加密会根据VB代码返回1N1U0Oy81PGOm/Yqdp9sT5iyPgPFxsc8Q8mADNa8BzQ=

对于解密,该过程是类似的。

请注意,出于安全原因,盐(此处表示为$secret_iv)应为每个密钥派生随机生成。盐不是秘密的,可以与密文(通常串联)一起发送。此外,对于 PBKDF2,迭代计数 1000 通常太小。

<?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";
}

最新更新