C#使用BouncyCastle解密OpenSSL AES-128-CTR密文乱码问题
问题原因
解密得到乱码是两端加密配置不匹配导致的,共两处核心错误:
- 密钥长度不匹配:使用的算法是
AES-128-CTR,要求密钥长度严格为16字节。传入的key字符串F5UgsDQddWGdgjddJtNgg6xE3V9uwaCR经UTF8编码后为32字节,PHP OpenSSL扩展遇到密钥长度超过算法要求时,会静默截断前16字节作为实际加密密钥;但C#代码直接传入了完整32字节密钥,相当于使用AES-256参数解密,密钥完全不匹配。 - 填充模式错误:CTR属于流密码工作模式,不需要任何填充。C#代码中指定的
PKCS7PADDING是CBC/ECB等块密码模式使用的填充规则,CTR模式下使用会导致解密逻辑错误。
注:现有代码中IV长度16字节、密文base64解码的逻辑是正确的,无需修改。
修复方案
方案1:保持PHP代码不变,修正C#解密逻辑
做两处改动即可:
- 取密钥字符串前16个字符转字节数组,和PHP侧的截断逻辑对齐
- 将BouncyCastle加密算法的填充规则改为
NoPadding
修正后的C#代码如下:
public string Decrypt(string toDecrypt, string keyStr, string ivStr) { byte[] inputBytes = Convert.FromBase64String(toDecrypt); // 对齐PHP侧AES-128的密钥截断逻辑,取前16字符转字节 byte[] keyBytes = Encoding.UTF8.GetBytes(keyStr.Substring(0, 16)); byte[] iv = Encoding.UTF8.GetBytes(ivStr); // CTR为流模式,无需填充 IBufferedCipher cipher = CipherUtilities.GetCipher("AES/CTR/NoPadding"); cipher.Init(false, new ParametersWithIV(ParameterUtilities.CreateKeyParameter("AES", keyBytes), iv)); byte[] decryptedBytes = cipher.DoFinal(inputBytes); return Encoding.UTF8.GetString(decryptedBytes); }
调用后可得到正确明文:The quick brown fox jumps over the lazy dog
方案2:保留32字节密钥,修正PHP代码
如果本意是使用32字节密钥做AES-256加密,只需要将PHP侧的加密算法改为AES-256-CTR,C#侧只需要把填充规则改为NoPadding、传入完整32字节密钥即可,无需截断。
补充说明:PHP
openssl_encrypt在options参数为0时默认返回base64格式密文,现有C#代码的base64解码逻辑是正确的;如果PHP侧加了OPENSSL_RAW_DATA参数,才需要直接传入原始字节密文,不需要做base64转换。
内容的提问来源于stack exchange,提问作者yqit
相关产品推荐
相关产品推荐

