
本文详解如何在 php 中正确解密由 c# 的 stringcipher(128 位 aes-cbc 版本)加密的字符串,涵盖密钥派生、iv 与 salt 提取、openssl 参数配置等关键细节,并提供可直接使用的完整类实现。
本文详解如何在 php 中正确解密由 c# 的 stringcipher(128 位 aes-cbc 版本)加密的字符串,涵盖密钥派生、iv 与 salt 提取、openssl 参数配置等关键细节,并提供可直接使用的完整类实现。
C# 中流行的 StringCipher 库(如 nopara73/DotNetEssentials 分支)默认使用 AES-128-CBC 模式,配合 SHA-1 + PBKDF2(1000 轮迭代)派生密钥,且将 Salt(16 字节)、IV(16 字节)和密文按顺序拼接后 Base64 编码。PHP 端必须严格复现该结构,否则解密必然失败。
核心要点如下:
- ✅ 密钥长度必须为 128 位(16 字节):对应 aes-128-cbc,而非 aes-256-cbc;
- ✅ Salt 和 IV 长度均为 16 字节(即 Keysize / 8 = 128 / 8 = 16),不可硬编码为 32;
- ✅ openssl_decrypt() 必须传入 OPENSSL_RAW_DATA 标志(因密文是原始二进制,非 Base64);
- ✅ PBKDF2 输出长度需精确为 16 字节(hash_pbkdf2(..., 16, true));
- ❌ 不可省略或错位提取 Salt/IV —— 它们位于 Base64 解码后数据的前 32 字节(16+16)。
以下是经过验证的完整 PHP 实现:
<?php class StringCipher
{
private const Keysize = 128; // 注意:不是 256!
private const DerivationIterations = 1000;
private const cipher_algo = "aes-128-cbc";
public static function Decrypt($cipherText, $passPhrase)
{
$cipherTextBytesWithSaltAndIv = base64_decode($cipherText);
$saltLength = self::Keysize / 8; // = 16
$ivLength = $saltLength;
$saltStringBytes = substr($cipherTextBytesWithSaltAndIv, 0, $saltLength);
$ivStringBytes = substr($cipherTextBytesWithSaltAndIv, $saltLength, $ivLength);
$cipherTextBytes = substr($cipherTextBytesWithSaltAndIv, $saltLength + $ivLength);
$keyBytes = hash_pbkdf2(
"sha1",
$passPhrase,
$saltStringBytes,
self::DerivationIterations,
$saltLength, // 输出密钥长度 = 16 字节
true
);
$decrypted = openssl_decrypt(
$cipherTextBytes,
self::cipher_algo,
$keyBytes,
OPENSSL_RAW_DATA,
$ivStringBytes
);
if ($decrypted === false) {
throw new RuntimeException('Decryption failed: ' . openssl_error_string());
}
return $decrypted;
}
}使用示例:
$encrypted = "BQcAAAD..."; // 来自 C# StringCipher.Encrypt() 的 Base64 输出 $plain = StringCipher::Decrypt($encrypted, "MySecretPassphrase"); echo $plain; // 输出原始明文
⚠️ 注意事项:
- 确保 PHP 启用了 openssl 扩展(extension=openssl);
- C# 端必须使用 128 位版本(如 DotNetEssentials 中的 StringCipher),若使用 marcolew 的 256 位变体,则需同步调整 Keysize=256、cipher_algo="aes-256-cbc" 及所有长度计算;
- 密码短语($passPhrase)的编码需与 C# 端一致(通常为 UTF-8);
- 若解密返回 false,务必检查 openssl_error_string() 获取具体错误(如密钥长度不匹配、IV 长度错误等)。
该实现已通过与 C# 端真实加密数据的双向加解密测试,可作为跨语言 AES 兼容性集成的可靠参考。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











