PHP AES-128-CTR加密结果的C#(BouncyCastle)解密乱码问题
问题:C#结合BouncyCastle解密PHP AES-128-CTR加密结果乱码
问题背景
尝试用C#结合BouncyCastle解密PHP生成的AES-128-CTR加密结果,PHP端解密代码可正常运行,但C#解密结果为乱码,怀疑问题出在Base64转换或字节数组的Take/Skip操作环节。
PHP加密代码
<?php $plaintext = 'The quick brown fox jumps over the lazy dog'; $cipher = "AES-128-CTR"; $key = "F5UgsDQddWGdgjdd"; $iv = openssl_random_pseudo_bytes(16); $ciphertext = openssl_encrypt( $plaintext, $cipher, $key, 0, $iv ); $ciphertext = base64_encode($iv.$ciphertext); echo $ciphertext."\n"; ?>
PHP解密代码(正常运行)
<?php $cipher = "AES-128-CTR"; $key = "F5UgsDQddWGdgjdd"; $ciphertext = base64_decode( $_POST['ciphertext'] ); $iv = substr($ciphertext, 0, 16); $content = substr($ciphertext, 16); $text = openssl_decrypt( $content, $cipher, $key, 0, $iv ); echo $text."\n"; ?>
问题C#解密代码
public string Test(string cipherTextStr) { var cipherText = Convert.FromBase64String(cipherTextStr); var iv = cipherText.Take(16).ToArray(); var content = cipherText.Skip(16).ToArray(); byte[] keyBytes = Encoding.UTF8.GetBytes("F5UgsDQddWGdgjdd"); IBufferedCipher cipher = CipherUtilities.GetCipher("AES/CTR/NoPadding"); cipher.Init(false, new ParametersWithIV(ParameterUtilities.CreateKeyParameter("AES", keyBytes), iv)); byte[] decryptedBytes = cipher.DoFinal(content); return Encoding.UTF8.GetString(decryptedBytes); }
问题分析与解决方案
核心问题
问题并非出在Take/Skip或Base64整体解码,而是PHP的openssl_encrypt默认返回Base64编码的密文,你的代码又额外对IV + 该Base64密文做了一次base64_encode。这导致最终传输的密文是「IV字节 + Base64密文字符串」再整体Base64编码的结果。而C#代码中直接将拆分出的content字节流当作原始加密字节解密,实际上content是Base64字符串的字节,需要先解码为原始加密字节才能正确解密。
修正后的C#代码
public string Test(string cipherTextStr) { var cipherText = Convert.FromBase64String(cipherTextStr); var iv = cipherText.Take(16).ToArray(); // 将拆分出的content字节转为字符串,再Base64解码得到原始加密字节 var contentBase64Str = Encoding.UTF8.GetString(cipherText.Skip(16).ToArray()); var contentBytes = Convert.FromBase64String(contentBase64Str); byte[] keyBytes = Encoding.UTF8.GetBytes("F5UgsDQddWGdgjdd"); IBufferedCipher cipher = CipherUtilities.GetCipher("AES/CTR/NoPadding"); cipher.Init(false, new ParametersWithIV(ParameterUtilities.CreateKeyParameter("AES", keyBytes), iv)); byte[] decryptedBytes = cipher.DoFinal(contentBytes); return Encoding.UTF8.GetString(decryptedBytes); }
验证逻辑
- 整体Base64解码:将输入的密文字符串转为字节数组,拆分出前16字节作为IV。
- 二次Base64解码:将拆分后的剩余字节转为UTF-8字符串(即PHP中
openssl_encrypt返回的Base64密文),再解码为原始加密字节流。 - 解密:使用AES-CTR模式解密原始加密字节流,得到明文。
内容的提问来源于stack exchange,提问作者yqit
相关产品推荐
相关产品推荐

