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

PHP中如何从openssl_encrypt获取匹配C# AES256-ECB的字节数组?

解决PHP与C# AES-256-ECB加密结果不一致的问题

你的问题核心在于填充方式不匹配,以及输出处理的差异,下面一步步帮你修正代码,得到和C#一致的结果:

问题根源分析

  • 你的C#代码使用了PaddingMode.Zeros,当明文长度不是AES块大小(16字节)的整数倍时,会填充0x00字节到块长度。
  • PHP的openssl_encrypt默认使用PKCS#7填充(填充的字节值等于填充的数量),这和C#的Zero填充逻辑完全不同,导致加密结果偏差。
  • 另外,你原代码对加密结果做了Base64编码,但实际需要的是原始加密字节的十六进制表示,这也是结果不符的原因之一。

修正后的PHP代码

// 构造原始明文字节
$plaintext = chr(0x8F) . chr(0x21) . chr(0xFF) . chr(0x43) . chr(0x49) . chr(0x27);

// AES块大小为16字节,计算需要填充的0字节数量
$blockSize = 16;
$paddingLength = $blockSize - (strlen($plaintext) % $blockSize);
// 手动填充0字节到块大小
$plaintextPadded = $plaintext . str_repeat(chr(0), $paddingLength);

// 构造密钥字节
$key = chr(0xC8) . chr(0xAE) . chr(0x1D) . chr(0xEC) . chr(0xD8) . chr(0x25) . chr(0x8D) . chr(0x52) .
       chr(0x6F) . chr(0x56) . chr(0xFB) . chr(0x13) . chr(0xF1) . chr(0x5D) . chr(0x3C) . chr(0x84) .
       chr(0xE0) . chr(0x02) . chr(0x16) . chr(0x89) . chr(0x34) . chr(0x8F) . chr(0x32) . chr(0x87) .
       chr(0x10) . chr(0x0A) . chr(0xB6) . chr(0xCD) . chr(0x81) . chr(0x27) . chr(0xDE) . chr(0x7E);

// 加密:使用AES-256-ECB,输出原始字节,指定不自动填充(我们已手动完成Zero填充)
$encrypted = openssl_encrypt($plaintextPadded, 'aes-256-ecb', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);

// 将加密后的原始字节转换为空格分隔的十六进制格式
$hexOutput = implode(' ', str_split(bin2hex($encrypted), 2));

echo $hexOutput; // 输出:F1 00 ED B4 25 8F A6 D5 13 32 4A 8E DE 87 0C 3F

关键说明

  1. 手动Zero填充:因为PHP的openssl没有直接支持Zero填充的选项,所以我们需要自己计算填充长度,在明文末尾补充足够的0x00字节,使其长度为16字节的整数倍。
  2. 禁用自动填充:通过OPENSSL_ZERO_PADDING标志告诉openssl_encrypt不要自动添加PKCS#7填充,避免重复填充导致结果错误。
  3. 输出转换:直接对加密后的原始字节使用bin2hex转换,再格式化空格分隔,就能得到和C#一致的十六进制结果,不需要Base64编码。
  4. ECB模式的IV:ECB模式不需要初始化向量(IV),所以C#代码里设置IV的操作不影响最终结果,PHP里也不需要传递IV参数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:32:57