gpt4 book ai didi

c# - 将PHP解密AES-256-CBC移植到C#

转载 作者:太空宇宙 更新时间:2023-11-03 22:37:52 27 4
gpt4 key购买 nike

我有以下 PHP 解密例程,它运行完美,需要帮助将其转换为 C#。我尝试了很多方法,但都没有用。我已经设法匹配 c# 和 php 之间的散列函数输出。也匹配从 base64 转换到 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";

the problem is that the key hash is a 64 bytes which is invalid for the AES-256 but i am not sure how it's working in php and how the openssl_decrypt php function is dealing with the keys.

我也尝试通过 key 散列的 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;
}

非常感谢任何帮助或想法。

最佳答案

openssl_decrypt 只需要算法所需的 key 字节数。由于您的算法是“AES-256-CBC”,因此使用 32 个字节(256 位),因为 AES-256 被定义为具有 256 位 key (和 14 轮,而不是 10 或 12 轮)的 AES。

PHP 执行此操作的方法是在 key 太小的情况下向右侧添加 00 值的字节,或者 - 就像您的情况一样 - 通过简单地忽略第 32 个字节之后的字节。对于任何类型的密码库来说,这都不是一个好的行为方式,尤其是对于像 PHP 这样的高级语言,但 OpenSSL 包装器库无论如何都会这样做。

因此,您必须从十六进制编码的 key 中提取前 32 个字节,并将其用作 C# 中的 key 才能兼容。使用不同的哈希函数当然是行不通的,MD5 和 SHA-256 完全不兼容(按设计)。当然,您现在还剩下 16 个十六进制编码字节,这意味着您正在使用带有 128 位 key 的 AES-256,从而使您拥有 128 位安全性。是的,您需要在 C# 中使用 PKCS#7 填充。


请注意,将 CBC 与静态 IV 一起使用是不安全的。将 CBC 模式用于传输模式安全性并不安全。使用 SHA-256 或任何对密码或 key 进行熵很小的普通散列是不安全的。将 key 存储在字符串中通常是不安全的。

让加密货币工作已经够难了;确保它的安全要困难得多,并且首先需要了解您到底在做什么。您需要从针对特定用例的良好协议(protocol)开始(这已经跳过了几个步骤)。

关于c# - 将PHP解密AES-256-CBC移植到C#,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54058037/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com