我正在尝试将 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";
}