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

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);
}

验证逻辑

  1. 整体Base64解码:将输入的密文字符串转为字节数组,拆分出前16字节作为IV。
  2. 二次Base64解码:将拆分后的剩余字节转为UTF-8字符串(即PHP中openssl_encrypt返回的Base64密文),再解码为原始加密字节流。
  3. 解密:使用AES-CTR模式解密原始加密字节流,得到明文。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 15:50:21