在 C# 中解密在 php 中加密的数据时如何修复无效的密钥大小

How to fix invalid key size when decrypting data in C# that was encrypted in php

我正在尝试解决我在 php 和 c# 之间遇到的加密问题。

我使用以下 php 和 openssl 操作加密了数据。

$encrypt_method = "AES-256-CBC";
$secret_key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
$secret_iv = 'XXXXXXXXXXXXXXXX';

$key = hash ('sha256', $secret_key);
$iv = substr (hash ('sha256', $secret_iv), 0, 16);

$output = openssl_encrypt ($string, $encrypt_method, $key, 0, $iv);
$output = base64_encode ($output);

我已经在 C# 中尝试了几种解密方法,但这就是我现在正在尝试的方法。

public string Encrypt_Decrypt(string action, string value) {
    string secretKey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
    string secretIV = "XXXXXXXXXXXXXXXX";

    string key = Hash(secretKey);

    string iv = Hash(secretIV).Substring(0,16);

    string retValue = "";

    if (action == "encrypt") {
        retValue = EncryptString(value, key, iv);
    }
    else if (action == "decrypt") {
        retValue = DecryptString(value, key, iv);
    }
}

// Hash to match php hash function
public static string Hash(string unhashedString) {
    return BitConverter.ToString(new SHA256CryptoServiceProvider().ComputeHash(Encoding.Default.GetBytes(unhashedString))).Replace("-", String.Empty).ToLower();
}

    public static string DecryptString(string cipherData, string keyString, string ivString) {
        byte[] key = Encoding.UTF8.GetBytes(keyString);
        Console.WriteLine(key.Length);
        byte[] iv = Encoding.UTF8.GetBytes(ivString);
        Console.WriteLine(iv.Length);
        byte[] cipherCrypt = Convert.FromBase64String(cipherData);


        for (int i = 0; i < cipherCrypt.Length; i++) {
            Console.Write(cipherCrypt[i] + " ");
        }


        try {
            RijndaelManaged crypto = new RijndaelManaged();
            crypto.Key = key;
            crypto.IV = iv;
            crypto.Mode = CipherMode.CBC;
            crypto.KeySize = 256;
            crypto.BlockSize = 128;
            crypto.Padding = PaddingMode.None;

            ICryptoTransform decryptor = crypto.CreateDecryptor(crypto.Key, crypto.IV);

            using (MemoryStream memStream = new MemoryStream(cipherCrypt)) {
                using (CryptoStream cryptoStream = new CryptoStream(memStream, decryptor, CryptoStreamMode.Read)) {
                    using (StreamReader streamReader = new StreamReader(cryptoStream)) {
                        return streamReader.ReadToEnd();
                    }
                }
            }
        }
        catch (CryptographicException e) {
            Console.WriteLine("A Cryptographic error occurred: {0}", e.Message);
            return null;
        }
    }

在为操作获取 byte[] 时,我尝试了几种不同的编码类型。

我不断收到以下错误:

指定的密钥不是该算法的有效大小。

不确定我错过了什么。感谢任何帮助。

此外,我已经通读 this 并尝试了解决方案建议推荐的内容。我得到了同样的结果错误。

更新 - 01 我在这里更新了代码以反映我更改的代码。

key长度为32,

iv长度为16,

进入"cipherData"的数据长度为32,

"cipherData"经过"FromBase64String(cipherData)"时,结果是24字节数组。这导致需要 32 字节 数组的解密器出现问题。

密钥大小明显有问题。 PHP 和 C# 之间的代码似乎匹配。问题似乎是代码在这两种情况下都是错误的。

让我们看看密钥实际有多长:

  1. 从 32 字节密钥(未编码)开始。
  2. 使用 SHA-256 散列密钥:32 字节(未编码)。
  3. 编码为十六进制(默认集成到PHP的hash()函数中):64字节.

AES 仅支持以下密钥大小:16、24 和 32 字节。 openssl_encrypt() 将仅静默使用十六进制密钥的前 32 个字节。因此,您需要使用 C# 中的前 32 个字节。

请注意,openssl_encrypt() 接受一个选项参数,表示当 OPENSSL_RAW_DATA 未设置时输出为 Base64。这意味着 PHP 输出使用 Base64 编码了两次。所以你需要用C#解码两次。