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

AES加解密报错:Padding is invalid and cannot be removed问题排查

问题:ASP.NET Core AES解密抛出「Padding无效无法移除」异常

在ASP.NET Core项目中实现AES加解密时,抛出异常:

System.Security.Cryptography.CryptographicException: 'Padding is invalid and cannot be removed.'

已确认前后端均使用PKCS7填充、ECB模式,更换填充模式后仍报错,求问题原因及解决办法。


前端View代码

<form asp-controller="Permit" asp-action="Encryptori" method="post">
<div class="form-group">
    <label for="Name">Name:</label>
    <input type="text" id="Name" name="Name" value="Roberto" class="form-control" />
</div>
<div class="form-group">
    <label for="Address">Address:</label>
    <input type="text" id="Address" name="Address" value="Viale Manfredo Fanti, 4 (50137) Firenze" class="form-control" />
</div>
<br />
<button type="submit" class="btn btn-primary" onclick="encryptAndSubmit()">Encrypt and Submit</button>
<br /><br />
@ViewBag.Display
<input type="hidden" id="Key" name="Key" value="@ViewBag.Key" />
<input type="hidden" id="IV" name="IV" value="@ViewBag.IV" />
</form>

前端脚本代码

<script src="https://cdn.jsdelivr.net/npm/crypto-js@4.1.1/crypto-js.min.js"></script>
<script>
function encryptAndSubmit() {
    var name = document.getElementById("Name").value;
    var address = document.getElementById("Address").value;
    var key = "@ViewBag.Key";
    var iv = "@ViewBag.IV";

    var encryptedName = encrypt(name, key, iv);
    var encryptedAddress = encrypt(address, key, iv);

    document.getElementById("Name").value = encryptedName;
    document.getElementById("Address").value = encryptedAddress;
}

function encrypt(plainText, key, iv) {
    var keyBytes = CryptoJS.enc.Utf8.parse(key);
    var ivBytes = CryptoJS.enc.Utf8.parse(iv);
    var encrypted = CryptoJS.AES.encrypt(plainText, keyBytes, {
        iv: ivBytes,
        mode: CryptoJS.mode.ECB,
        padding: CryptoJS.pad.Pkcs7
    });

    return encrypted.toString();
}
</script>

后端Controller代码

private readonly byte[] _key;
private readonly byte[] _iv;

public PermitController()
{
    var rng = new RNGCryptoServiceProvider();

    _key = new byte[32];
    rng.GetBytes(_key);
  
    _iv = new byte[16];
    rng.GetBytes(_iv);
}

public async Task<IActionResult> Encryptori()
{
    ViewBag.Display = "";
    ViewBag.Key = Convert.ToBase64String(_key);
    ViewBag.IV = Convert.ToBase64String(_iv);
    ApplicationUser user = await _userManager.GetUserAsync(User);
    return View();
}

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Encryptori(IFormCollection collection)
{
    string TheKey = collection["Key"];
    string TheIv = collection["IV"];
    var keyBytes = Convert.FromBase64String(TheKey);
    var ivBytes = Convert.FromBase64String(TheIv);

    string encryptedName = collection["Name"];
    string encryptedAddress = collection["Address"];

    var decryptedName = Decrypt(encryptedName, TheKey, TheIv);
    var decryptedAddress = Decrypt(encryptedAddress, TheKey, TheIv);

    // Store the decrypted data in the ViewBag
    ViewBag.Display = encryptedName + "  and  " + encryptedAddress;

    ApplicationUser user = await _userManager.GetUserAsync(User);
    return View();
}

private string Decrypt(string encryptedText, string key, string iv)
{
try
{
    var keyBytes = Convert.FromBase64String(key);
    var ivBytes = Convert.FromBase64String(iv);

    using (var aes = Aes.Create())
    {
        aes.Key = keyBytes;
        aes.IV = ivBytes;
        aes.Padding = PaddingMode.PKCS7;
        aes.Mode = CipherMode.ECB;

        var decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
        using (var ms = new MemoryStream())
        {
            using (var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Write))
            {
                var encryptedBytes = Convert.FromBase64String(encryptedText);
                cs.Write(encryptedBytes, 0, encryptedBytes.Length);
            }
            ms.Position = 0;
            var decryptedBytes = new byte[ms.Length];
            ms.Read(decryptedBytes, 0, decryptedBytes.Length);
            return Encoding.UTF8.GetString(decryptedBytes);
        }
    }
}
catch (CryptographicException ex)
{
    Console.WriteLine("Decryption failed: " + ex.Message);
    return null;
}
}

问题原因

核心问题是前后端密钥的解析方式完全不一致:

  • 后端生成的密钥是32字节随机数,通过Convert.ToBase64String转成Base64字符串传给前端
  • 前端却把这个Base64字符串当成UTF-8文本,用CryptoJS.enc.Utf8.parse解析成字节数组,这和后端用Convert.FromBase64String解析出来的字节数组完全不同
  • 密钥不匹配导致解密时无法正确还原明文,最终触发填充验证失败的异常

另外,ECB模式本身不需要IV,代码里前后端都设置了IV属于冗余操作,但不是报错原因。

解决办法

1. 修正前端密钥解析方式

把前端的密钥/IV从UTF-8解析改为Base64解析,同时移除ECB模式下的IV设置(可选,更规范):

function encrypt(plainText, key, iv) {
    // 改用Base64解析密钥,和后端保持一致
    var keyBytes = CryptoJS.enc.Base64.parse(key);
    // ECB模式不需要IV,直接移除相关配置
    var encrypted = CryptoJS.AES.encrypt(plainText, keyBytes, {
        mode: CryptoJS.mode.ECB,
        padding: CryptoJS.pad.Pkcs7
    });

    return encrypted.toString();
}

2. 优化后端解密逻辑

调整解密时的流处理方式,同时移除ECB模式下的IV设置:

private string Decrypt(string encryptedText, string key, string iv)
{
    try
    {
        var keyBytes = Convert.FromBase64String(key);
        using (var aes = Aes.Create())
        {
            aes.Key = keyBytes;
            aes.Padding = PaddingMode.PKCS7;
            aes.Mode = CipherMode.ECB;

            // ECB模式不需要IV,传null即可
            var decryptor = aes.CreateDecryptor(aes.Key, null);
            // 改用Read模式的CryptoStream,简化代码
            using (var ms = new MemoryStream(Convert.FromBase64String(encryptedText)))
            using (var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
            using (var sr = new StreamReader(cs, Encoding.UTF8))
            {
                return sr.ReadToEnd();
            }
        }
    }
    catch (CryptographicException ex)
    {
        Console.WriteLine("Decryption failed: " + ex.Message);
        return null;
    }
}

3. 额外安全建议

  • ECB模式安全性极低,建议改用CBC或GCM模式(GCM自带消息认证,更安全),更换模式后要确保前后端IV处理一致,且IV需随机生成并随密文传输
  • 绝对不要通过前端隐藏域传输密钥!这会直接泄露密钥,应该由后端存储密钥,前端仅传输密文

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 13:04:54