将PHP解密AES-256-CBC移植到C#
我有下面的PHP解密例程,它工作完美,需要帮助将其转换为c。我尝试过很多方法,但都不管用。 我已经设法在c#和php之间匹配哈希函数输出。 还匹配了从和到base64的转换输出 PHP代码:将PHP解密AES-256-CBC移植到C#,c#,php,encryption,C#,Php,Encryption,我有下面的PHP解密例程,它工作完美,需要帮助将其转换为c。我尝试过很多方法,但都不管用。 我已经设法在c#和php之间匹配哈希函数输出。 还匹配了从和到base64的转换输出 PHP代码: function decrypt($encrypted_txt, $secret_key, $secret_iv) { $encrypt_method = "AES-256-CBC"; // hash $key = hash('sha256', $secret_key); // iv - encrypt m
function decrypt($encrypted_txt, $secret_key, $secret_iv)
{
$encrypt_method = "AES-256-CBC";
// hash
$key = hash('sha256', $secret_key);
// iv - encrypt method AES-256-CBC expects 16 bytes - else you will get a warning
$iv = substr(hash('sha256', $secret_iv), 0, 16);
$output = openssl_decrypt(base64_decode($encrypted_txt), $encrypt_method, $key, 0, $iv);
return $output;
}
问题是密钥散列是64字节,对于AES-256无效,但我不确定它在php中如何工作,以及openssl_decrypt php函数如何处理密钥
我还试图传递密钥散列的MD5,但也未能解密
byte[] asciiBytes = ASCIIEncoding.ASCII.GetBytes(keyhash);
byte[] hashedBytes = MD5CryptoServiceProvider.Create().ComputeHash(asciiBytes);
string keymd5 = BitConverter.ToString(hashedBytes).Replace("-", "").ToLower(); //To match with PHP MD5 output
C#散列函数:
static string sha256(string randomString)
{
var crypt = new System.Security.Cryptography.SHA256Managed();
var hash = new System.Text.StringBuilder();
byte[] crypto = crypt.ComputeHash(Encoding.UTF8.GetBytes(randomString));
foreach (byte theByte in crypto)
{
hash.Append(theByte.ToString("x2"));
}
return hash.ToString();
}
C#解密例程:
static string DecryptStringFromBytesAes(byte[] cipherText, byte[] key, byte[] iv)
{
// Check arguments.
if (cipherText == null || cipherText.Length <= 0)
throw new ArgumentNullException("cipherText");
if (key == null || key.Length <= 0)
throw new ArgumentNullException("key");
if (iv == null || iv.Length <= 0)
throw new ArgumentNullException("iv");
// Declare the RijndaelManaged object
// used to decrypt the data.
RijndaelManaged aesAlg = null;
// Declare the string used to hold
// the decrypted text.
string plaintext;
// Create a RijndaelManaged object
// with the specified key and IV.
aesAlg = new RijndaelManaged { Mode = CipherMode.CBC, Padding = PaddingMode.None, KeySize = 256, BlockSize = 128, Key = key, IV = iv };
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
srDecrypt.Close();
}
}
}
return plaintext;
}
静态字符串解密StringFromByteSAES(字节[]密文,字节[]密钥,字节[]iv)
{
//检查参数。
if(cipherText==null | | cipherText.Lengthopenssl_decrypt
只需要算法所需的密钥字节数。由于您的算法是“AES-256-CBC”,它使用32个字节(256位),因为AES-256被定义为具有256位密钥的AES(和14轮,而不是10或12轮)
PHP实现这一点的方法要么是在右边添加00
值字节,以防密钥太小,要么像您的情况一样,简单地忽略第32个字节之后的字节。这对于任何类型的加密库来说都不是一种好方法,特别是对于像PHP这样的高级语言,但OpenSSL包装库可以做到这一点对
因此,您必须从十六进制编码的密钥中提取前32个字节,并将其用作C#中的密钥以实现兼容。使用不同的哈希函数当然行不通,MD5和SHA-256完全不兼容(按设计)当然,您现在还剩下16个十六进制编码字节,这意味着您使用的是带有128位密钥的AES-256,这样您就有了128位的安全性。是的,您需要在C中使用PKCS#7填充
请注意,将CBC与静态IV一起使用是不安全的。将CBC模式用于传输模式安全性是不安全的。对密码或密钥使用SHA-256或任何具有较小熵的普通哈希是不安全的。将密钥存储在字符串中通常是不安全的
让加密工作起来已经够难了;让它安全起来要困难得多,首先需要了解你在做什么。你需要为你的特定用例制定一个好的协议(这已经跳过了几个步骤).为什么您认为密钥是64字节?我觉得它像32字节。请注意,十六进制编码每字节使用两个字符,因此如果您将32字节的密钥编码为十六进制,则会产生64个字符的字符串。但是,您的填充是不正确的。openssl\u decrypt
默认情况下使用PKCS#7-填充,但在C中,您完全禁用了填充。Y您需要设置Padding=PaddingMode.PKCS7
。
static string DecryptStringFromBytesAes(byte[] cipherText, byte[] key, byte[] iv)
{
// Check arguments.
if (cipherText == null || cipherText.Length <= 0)
throw new ArgumentNullException("cipherText");
if (key == null || key.Length <= 0)
throw new ArgumentNullException("key");
if (iv == null || iv.Length <= 0)
throw new ArgumentNullException("iv");
// Declare the RijndaelManaged object
// used to decrypt the data.
RijndaelManaged aesAlg = null;
// Declare the string used to hold
// the decrypted text.
string plaintext;
// Create a RijndaelManaged object
// with the specified key and IV.
aesAlg = new RijndaelManaged { Mode = CipherMode.CBC, Padding = PaddingMode.None, KeySize = 256, BlockSize = 128, Key = key, IV = iv };
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
srDecrypt.Close();
}
}
}
return plaintext;
}