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

AES解密报错:The input data is not a complete block问题求助

AES加解密错误排查与修复

核心问题分析

以下是导致你遇到System.Security.Cryptography.CryptographicException错误的核心问题:

  • 加密结果直接转UTF8字符串导致数据损坏:加密后的字节数组是二进制数据,并非合法的UTF8编码序列,直接用Encoding.UTF8.GetString(crypted)转换会导致部分字节丢失或被篡改,解密时输入的字节数组长度或内容不符合AES要求,触发"输入数据不是完整块"的错误。
  • 解密时重新生成IV:CBC模式下,AES的加密和解密必须使用同一个初始化向量(IV),你当前解密代码中调用aes.GenerateIV()生成新的IV,与加密时的IV不匹配,这不仅会导致解密失败,也会引发数据块相关的异常。

修复方案

  1. 用Base64编码传输加密结果:将加密后的字节数组转为Base64字符串,而非直接转UTF8,Base64是专门用于二进制数据的文本编码,能保证数据完整无损。
  2. 传递并复用加密时的IV:加密时需要把生成的IV和密文一起保存/传输,解密时使用同一个IV进行解密。通常的做法是将IV前缀到密文字节数组前,或者与密文分开存储。

修正后的完整代码

加密方法

private static string CreateRequestVerificationToken()
{
    var key = System.Configuration.ConfigurationManager.AppSettings["EncryptionKey"];
    // 验证密钥长度:128位AES要求密钥是16字节(UTF8下的16个字符)
    if (Encoding.UTF8.GetBytes(key).Length != 16)
    {
        throw new ArgumentException("EncryptionKey must be 16 UTF8 characters for 128-bit AES");
    }

    var unprotectedData = string.Format("{0}|{1}", "A", "B");
    var src = Encoding.UTF8.GetBytes(unprotectedData);

    using (var aes = Aes.Create())
    {
        aes.BlockSize = 128;
        aes.KeySize = 128;
        aes.Key = Encoding.UTF8.GetBytes(key);
        aes.Mode = CipherMode.CBC;
        aes.Padding = PaddingMode.Zeros;
        aes.GenerateIV(); // 生成随机IV

        using (ICryptoTransform encrypt = aes.CreateEncryptor(aes.Key, aes.IV))
        {
            var crypted = encrypt.TransformFinalBlock(src, 0, src.Length);
            
            // 将IV和密文合并:IV在前(16字节),密文在后
            var combinedBytes = new byte[aes.IV.Length + crypted.Length];
            Buffer.BlockCopy(aes.IV, 0, combinedBytes, 0, aes.IV.Length);
            Buffer.BlockCopy(crypted, 0, combinedBytes, aes.IV.Length, crypted.Length);
            
            // 转为Base64字符串返回
            return Convert.ToBase64String(combinedBytes);
        }
    }   
}

解密方法

private static string DecryptData(string encryptedToken)
{
    var key = System.Configuration.ConfigurationManager.AppSettings["EncryptionKey"];
    if (Encoding.UTF8.GetBytes(key).Length != 16)
    {
        throw new ArgumentException("EncryptionKey must be 16 UTF8 characters for 128-bit AES");
    }

    // 将Base64字符串转回字节数组
    var combinedBytes = Convert.FromBase64String(encryptedToken);
    var ivLength = 16; // 128位AES的IV固定是16字节
    
    // 分离IV和密文
    var iv = new byte[ivLength];
    var protectedData = new byte[combinedBytes.Length - ivLength];
    Buffer.BlockCopy(combinedBytes, 0, iv, 0, ivLength);
    Buffer.BlockCopy(combinedBytes, ivLength, protectedData, 0, protectedData.Length);

    using var aes = Aes.Create();
    aes.BlockSize = 128;
    aes.KeySize = 128;
    aes.Key = Encoding.UTF8.GetBytes(key);
    aes.Mode = CipherMode.CBC;
    aes.Padding = PaddingMode.Zeros;
    aes.IV = iv; // 使用加密时的IV,不再生成新的

    using ICryptoTransform decrypt = aes.CreateDecryptor(aes.Key, aes.IV);
    byte[] decryptedText = decrypt.TransformFinalBlock(protectedData, 0, protectedData.Length);

    // 去掉PaddingMode.Zeros添加的末尾零字节,转为字符串
    return Encoding.UTF8.GetString(decryptedText).TrimEnd('\0');
}

额外注意事项

  • 密钥验证:128位AES要求密钥长度为16字节(UTF8编码下的16个字符),如果你的密钥长度不符,需要调整密钥或者改用256位AES(密钥32字节)。
  • Padding选择:PaddingMode.Zeros可能会导致原始数据末尾有零的情况丢失,建议优先使用PaddingMode.PKCS7(AES的标准填充方式),这样解密时能自动移除填充字节,无需手动处理。
  • Aes实现选择:Aes.Create()会返回当前平台最优的AES实现,推荐优先使用,而AesCryptoServiceProvider是Windows特定的实现。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 15:16:02