我有以下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 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;
}
secret_key= "t-3zafRa"; secret_key_hash = "d03a4d94b29e7f55c80726f1152dcebc9f03f4c698470f72083af967cf786b6b";
问题在于密钥哈希是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;
}
任何帮助或想法都将受到高度赞赏。
答案 0 :(得分:3)
openssl_decrypt
只需为密钥占用算法所需的字节数即可。由于您的算法是“ AES-256-CBC”,因此使用32字节(256位),因为AES-256被定义为具有256位密钥(并且是14轮,而不是10或12轮)的AES。
PHP执行此操作的方式是在密钥太小的情况下在右边添加00
个有价值的字节,或者(如您所愿)仅通过忽略第32个字节之后的字节。这不是表现任何类型的密码库的好方法,尤其是对于像PHP这样的高级语言而言,但是OpenSSL包装器库仍然可以做到这一点。
因此,您必须从十六进制编码的密钥中提取前32个字节,并将其用作C#中的密钥以兼容。使用不同的哈希函数当然是行不通的,MD5和SHA-256完全不兼容(根据设计)。当然,您现在还有16个十六进制编码的字节,这意味着您将使用具有128位密钥的AES-256,从而具有128位安全性。是的,您需要在C#中使用PKCS#7填充。
请注意,使用带有静态IV的CBC是不安全的。将CBC模式用于传输模式安全性并不安全。使用SHA-256或几乎没有熵的密码或密钥使用任何普通哈希是不安全的。通常,将密钥存储在字符串中并不安全。
使加密工作足够困难;确保其安全性要困难得多,并且首先需要了解您的操作。您需要从针对特定用例的良好协议开始(这已经跳过了几个步骤)。