You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP OpenSSL加密数据在C# .NET中解密结果异常排查

排查步骤与解决方法

因为反向(C#加密→PHP解密)正常,说明C#加密逻辑和PHP解密逻辑兼容,问题肯定出在PHP加密逻辑与C#解密逻辑的细节不匹配,以下是最可能的排查点:

1. 密钥的字节处理是否一致

AES-256要求密钥为32字节(256位),这是高频踩坑点:

  • 若PHP传入的密钥短于32字节,openssl_encrypt会自动通过EVP_BytesToKey算法推导32字节密钥;但C#的Aes类默认不会做这个推导,只会直接将字符串转成字节数组后补零到32字节,导致两边密钥完全不一致。
  • 反向操作正常的原因是:PHP解密时同样用EVP_BytesToKey处理短密钥,而C#加密时用补零后的密钥,仅当短密钥推导结果与补零字节数组偶然一致时才会正常,这是极小概率事件。

验证与修复:
先确认PHP中密钥的字节长度:

$key = "your-key-here";
echo strlen($key); // 需输出32

若长度不符,可选择:

  • 直接将密钥改为32字节的字符串;
  • 两边统一用哈希生成32字节密钥:
    • PHP:
      $key = hash('sha256', $original_key, true);
      
    • C#:
      using (SHA256 sha256 = SHA256.Create())
      {
          byte[] keyBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(originalKey));
      }
      

2. 加密后的数据编码/解码是否正确

PHP的openssl_encrypt默认输出Base64编码字符串(第四个参数为0时),手动处理原始字节易出错:

  • 错误示例:PHP用OPENSSL_RAW_DATA输出原始字节后转十六进制,但C#用Encoding.UTF8.GetBytes(hexStr)转字节数组(正确做法是将十六进制字符串直接转字节数组);
  • 另一个错误:PHP输出的Base64字符串包含换行符(如chunk_split处理过),C#解码时未去除换行符,导致字节数组错误。

验证与修复:
对比两边密文的字节长度:

  • PHP:
    $ciphertext = openssl_encrypt($plaintext, 'AES-256-CBC', $key, 0, $iv);
    echo strlen(base64_decode($ciphertext));
    
  • C#:
    byte[] cipherBytes = Convert.FromBase64String(ciphertext);
    Console.WriteLine(cipherBytes.Length);
    

若长度一致则编码无问题;若不一致,检查Base64字符串是否被篡改(如空格替换+、丢失末尾=)。

若用十六进制传递密文,C#需用正确的解码方法:

public static byte[] HexStringToByteArray(string hex)
{
    int length = hex.Length;
    byte[] bytes = new byte[length / 2];
    for (int i = 0; i < length; i += 2)
    {
        bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
    }
    return bytes;
}

3. IV的字节数组是否完全匹配

AES-CBC的IV必须是16字节(块大小),两边的IV字节数组必须完全一致:

  • 常见错误:PHP将IV转成UTF-8字符串传递,C#用ASCII编码转字节数组;或PHP用bin2hex转IV,C#解码出错。

验证与修复:
对比两边IV的十六进制表示:

  • PHP:
    echo bin2hex($iv);
    
  • C#:
    Console.WriteLine(BitConverter.ToString(iv).Replace("-", ""));
    

若不一致,调整编码方式(统一用UTF-8),或统一用Base64/十六进制传递IV。

4. 填充方式是否一致

AES-CBC必须使用填充,默认都是PKCS7,但若手动修改过填充方式会导致解密内容错误:

  • 若PHP使用OPENSSL_ZERO_PADDING,需手动将明文补零到块大小倍数,同时C#解密时设置PaddingMode.Zeros;
  • 反向操作正常说明C#加密的填充方式与PHP解密一致,只需确保PHP加密的填充设置与C#解密匹配。

修复示例:
若PHP用零填充:

$blockSize = openssl_cipher_iv_length('AES-256-CBC');
$padding = $blockSize - (strlen($plaintext) % $blockSize);
$plaintext_padded = $plaintext . str_repeat("\x00", $padding);
$ciphertext = openssl_encrypt($plaintext_padded, 'AES-256-CBC', $key, OPENSSL_ZERO_PADDING, $iv);

对应的C#解密代码:

aes.Padding = PaddingMode.Zeros;

5. 明文/解密后的字符串编码是否一致

若明文包含非ASCII字符(如中文),两边字符串编码必须一致:

  • PHP默认用UTF-8处理字符串,C#解密后需用UTF-8读取,而非默认的Encoding.Default或ASCII:
using (StreamReader srDecrypt = new StreamReader(csDecrypt, Encoding.UTF8))
{
    string plaintext = srDecrypt.ReadToEnd();
}

内容的提问来源于stack exchange,提问作者anon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 08:45:30