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

AES解密Android客户端加密数据时出现填充无效错误

AES跨平台解密填充错误问题排查

Android加密逻辑

Android端加密代码如下:

object AESHelper {
    fun encrypt(data: String, sharedSecret: ByteArray): String {
        val cipher = Cipher.getInstance("AES/CBC/PKCS7Padding")
        val secretKeySpec = SecretKeySpec(sharedSecret, "AES")
        val iv = ByteArray(16) // Zero IV
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, IvParameterSpec(iv))
        val encryptedBytes = cipher.doFinal(Base64.decode(data, Base64.NO_WRAP))
        return Base64.encodeToString(encryptedBytes, Base64.NO_WRAP).trim()
    }
}

核心配置:

  • AES-CBC模式
  • PKCS7填充
  • 16字节全零初始化向量(IV)
  • IV未附加到密文头部

C#解密逻辑

当前C#端解密代码:

public static string Decrypt(string cipherText, byte[] sharedSecret)
{
    using var aes = new AesCryptoServiceProvider { Key = sharedSecret };
    var cipherBytes = Convert.FromBase64String(cipherText);

    var iv = new byte[aes.BlockSize / 8];
    var encryptedBytes = new byte[cipherBytes.Length - iv.Length];
    Buffer.BlockCopy(cipherBytes, 0, iv, 0, iv.Length);
    Buffer.BlockCopy(cipherBytes, iv.Length, encryptedBytes, 0, encryptedBytes.Length);

    aes.IV = iv;

    using var decryptor = aes.CreateDecryptor();
    var decryptedBytes = decryptor.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
    return Encoding.UTF8.GetString(decryptedBytes);
}

问题现象

解密Android端生成的密文时,抛出异常:

System.Security.Cryptography.CryptographicException: Padding is invalid and cannot be removed.
at Internal.Cryptography.UniversalCryptoDecryptor.DepadBlock(Byte[] block, Int32 offset, Int32 count)
at Internal.Cryptography.UniversalCryptoDecryptor.UncheckedTransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)
at Internal.Cryptography.UniversalCryptoTransform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)
at MyNamespace.Decrypt(String cipherText, Byte[] sharedSecret)

已尝试操作

已修改C#逻辑,改用16字节全零IV,不再从密文中提取IV,且确认Android端未将IV附加到密文。

疑问

  1. 为何使用零IV后仍出现填充无效错误?
  2. C#解密逻辑还需修改哪些部分以匹配Android客户端的加密逻辑?
  3. 还有哪些调试步骤可以采取?

问题解答

1. 零IV后仍报错的核心原因

代码存在两个关键不匹配点:

  • 加密前的Base64处理逻辑相反:Android端是先把明文data做Base64解码,再加密;而C#端解密后直接转UTF8,没有做对应的Base64编码还原,导致字节流完全错误,触发填充校验失败。
  • 密文截取错误:原C#代码错误地从密文中截取了IV长度的字节,导致实际解密的密文缺失了前16字节,这也是填充错误的直接原因之一。

2. C#解密逻辑的修正点

需要调整两个核心步骤:

  • 直接使用全零IV,不再从密文中截取
  • 解密后的字节流需要做Base64编码,再转UTF8(逆向匹配Android端的加密前处理)

修正后的C#代码:

public static string Decrypt(string cipherText, byte[] sharedSecret)
{
    using var aes = Aes.Create();
    aes.Key = sharedSecret;
    aes.IV = new byte[16]; // 全零IV,和Android端完全一致
    aes.Mode = CipherMode.CBC;
    aes.Padding = PaddingMode.PKCS7; // 显式指定填充模式,避免依赖默认值

    var cipherBytes = Convert.FromBase64String(cipherText);
    
    using var decryptor = aes.CreateDecryptor();
    var decryptedBytes = decryptor.TransformFinalBlock(cipherBytes, 0, cipherBytes.Length);
    
    // 关键:Android端加密前是Base64解码明文,解密后需Base64编码还原原始字符串
    return Convert.ToBase64String(decryptedBytes);
}

3. 调试步骤建议

  • 字节流对比校验:
    1. Android端输出加密前的Base64.decode(data, Base64.NO_WRAP)字节数组,保存为二进制文件
    2. C#端解密后输出decryptedBytes字节数组,保存为二进制文件
    3. 对比两个文件的字节是否完全一致,验证解密是否正确
  • 密钥一致性验证:
    • 两端分别打印sharedSecret的Base64字符串,确认密钥完全相同(避免编码或传输过程中出现字节丢失)
  • 密文一致性验证:
    • Android端直接输出加密后的Base64字符串,C#端用这个字符串测试解密,排除传输过程中的截断、编码转换问题
  • 参数显式校验:
    • 在C#代码中显式指定所有加密参数(Mode、Padding、IV),避免因环境差异导致默认值变化

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 02:42:45