【问题标题】:How to fix invalid key size when decrypting data in C# that was encrypted in php解密在 php 中加密的 C# 中的数据时如何修复无效的密钥大小
【发布时间】:2015-08-05 13:26:33
【问题描述】:

我正在尝试解决我在 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 字节 数组的解密器出现问题。

【问题讨论】:

  • 嗯,钥匙有多长?
  • 我相信它是散列函数的 256,但我对此并不陌生。上面的 Hash 代码来自:stackoverflow.com/a/1419092/1481280 我编辑了该代码以生成与 php 哈希匹配的 sha256 哈希。

标签: c# php encryption openssl


【解决方案1】:

密钥大小显然存在问题。 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# 中对其进行两次解码。

【讨论】:

  • 你有使用前 32 个字节的 openssl_encrypt 参考吗?
  • 没有。我在 StackOverflow 的某个地方读到过。但这通常是大多数 PHP 和 JavaScript 加密实现的情况。
  • 我尝试使用密钥的前 32 个字节。我仍然得到相同的密钥长度错误。
  • 好的,我再问一次。钥匙到底有多长?我确定您可以将长度打印到控制台。
  • Key 长度为 32,iv 长度为 16,base64 cipherData 长度为 32。当 cipherData 通过 FromBase64String() 时,它变成一个 24 字节数组。这导致了一个新错误:发生加密错误:要解密的数据长度无效。 这是因为 RijndaelManaged 想要一个 32 字节的数据数组,但只得到 24 个。我已经尝试了所有填充RijndaelManaged 中的选项,并且还尝试手动将 24 个字节填充到 32 个。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-24
  • 2014-02-21
  • 1970-01-01
  • 1970-01-01
  • 2023-01-28
相关资源
最近更新 更多