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

PHP与C#实现AES-128-CBC加密解密兼容问题解决

PHP与C# AES-128-CBC加密兼容问题解决

问题背景与代码

PHP加密代码

$cipher = "AES-128-CBC";
$key = openssl_digest("OfVb3CjsZhnX81ZzjfAHuIiMtKEUyrt6", 'SHA256', TRUE);
$ivlen = openssl_cipher_iv_length($cipher);
$iv = openssl_random_pseudo_bytes($ivlen);
$ciphertext_raw = openssl_encrypt("wsUser", $cipher, $key, OPENSSL_RAW_DATA, $iv);
$hmac = hash_hmac('sha256', $ciphertext_raw, $key, true);
$result = base64_encode($iv . $hmac . $ciphertext_raw);
// $result value will decode by http_build_query
// $request_query["Key"] = $result;
// $last_query = http_build_query($request_query);

初始转换的C#代码

var cipher = "AES-128-CBC-----";
var key = SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes("OfVb3CjsZhnX81ZzjfAHuIiMtKEUyrt6"));            
var ivlen = cipher.Length;
byte[] iv = new byte[16]; Random rnd = new Random();
rnd.NextBytes(iv);
var aes = Aes.Create("AesManaged");

// 初始代码未添加以下密钥截取逻辑
//C# 4.5 
//byte[] m = new byte[16];
//Array.Copy(key, 0, m, 0, 16);
//aes.Key =  m;
//C# 8.0
//aes.Key = key[0..16];
aes.IV = iv;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
var encryptor = aes.CreateEncryptor(aes.Key,iv);
var ciphertextRaw = encryptor.TransformFinalBlock(Encoding.UTF8.GetBytes(txtwsuser.Text), 0, txtwsuser.Text.Length); // 明文为"wsUser"
var hmac = new HMACSHA256(key).ComputeHash(ciphertextRaw);
string cw = Convert.ToBase64String(iv.Concat(hmac).Concat(ciphertextRaw).ToArray());
textBox1.Text =  HttpUtility.UrlEncode(cw).Replace("%3d", "%3D"); // 调试用代码

PHP解密代码

$encrypted_value = urldecode("data_from_client"); // 可填入textBox1.Text的值
$cipher = "AES-128-CBC";
$key = openssl_digest(wsKey, 'SHA256', TRUE);
$cw = base64_decode($encrypted_value);
$ivlen = openssl_cipher_iv_length($cipher);
$iv = substr($cw, 0, $ivlen);
$hmac = substr($cw, $ivlen, $sha2len=32);
$cw3 = substr($cw, $ivlen+$sha2len);
$calcmac = hash_hmac('SHA256', $cw3, $key, true);
$result = openssl_decrypt($cw3, $cipher, $key, OPENSSL_RAW_DATA, $iv);

问题现象

  • PHP解密器能正常解密自身生成的加密值,但无法解密C#生成的内容
  • 已确认双方密钥和HMAC哈希值一致
  • C#生成的加密值:sCn1%2bY2Kx9RzIiDIsWL1xWRxecMO%2bkPhIdkBfXbV6uD7%2by75f3EvwpyP4e3CHLDjBZ7U0CrVDsK4MdBUn25K0Q%3D%3D
  • PHP生成的加密值(可正常解密):%2FUMZJmd2LfIJzJntETKcgo%2F7VDaBV8U9iLY%2Bopq2Up5%2BrtOLRMxR%2B3OzbzgLEx0ZZErjZFP8oOtMmnZ%2FEX1dxA%3D%3D

解决方案

在C#代码中添加密钥截取逻辑,仅取SHA256生成的32字节密钥的前16字节作为AES-128的密钥:

修改后的C#密钥处理代码

// C# 4.5 版本写法
byte[] m = new byte[16];
Array.Copy(key, 0, m, 0, 16);
aes.Key = m;

// C# 8.0+ 版本写法
aes.Key = key[0..16];

原因说明

AES-128要求密钥长度为16字节:

  • PHP中openssl_encrypt使用AES-128-CBC模式时,会自动截取32字节SHA256哈希的前16字节作为密钥
  • C#中若直接将32字节哈希赋值给aes.Key,会被识别为AES-256密钥,导致加密模式不匹配,最终PHP解密失败
    手动截取前16字节后,双方使用的密钥长度一致,加密逻辑匹配,即可解决兼容性问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 15:15:38