BouncyCastle实现AES256 ECB解密报last block incomplete异常
问题背景
在C#环境中使用Bouncy Castle库实现AES 256 ECB模式加解密功能时,加密流程可正常执行并输出密文,但对密文执行解密操作时会抛出异常:Org.BouncyCastle.Crypto.DataLengthException: last block incomplete in decryption,解密流程中断,无法得到正确明文。
涉及的加解密实现代码如下:
public byte[] encrypt(byte[] skey, byte[] data) { PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher( new AesEngine(), new Pkcs7Padding()); cipher.Init(true, new KeyParameter(skey)); int outputSize = cipher.GetOutputSize(data.Length); byte[] tempOP = new byte[outputSize]; int processLen = cipher.ProcessBytes(data, 0, data.Length, tempOP, 0); int outputLen = cipher.DoFinal(tempOP, processLen); byte[] result = new byte[processLen + outputLen]; Array.Copy(tempOP, 0, result, 0, result.Length); return result; } public byte[] decrypt(byte[] skey, byte[] data) { PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher( new AesEngine(), new Pkcs7Padding()); cipher.Init(false, new KeyParameter(skey)); int outputSize = cipher.GetOutputSize(data.Length); byte[] tempOP = new byte[outputSize]; int processLen = cipher.ProcessBytes(data, 0, data.Length, tempOP, 0); int outputLen = cipher.DoFinal(tempOP, processLen); byte[] result = new byte[processLen + outputLen]; Array.Copy(tempOP, 0, result, 0, result.Length); return result; }
故障原因
给出的加解密核心逻辑本身没有语法错误,触发该异常的核心原因是传入解密方法的密文不符合AES块加密的输入要求,常见场景包括:
- AES块大小固定为16字节,搭配PKCS7填充时,合法密文的总长度必须是16的整数倍。如果密文在加密输出后、传入解密方法前被截断、篡改,会导致长度不满足要求,触发最后一块不完整的异常。
- 密文转码错误:这是最高发的诱因。如果加密得到密文字节后,直接使用
Encoding.UTF8、Encoding.ASCII等文本编码将密文转为字符串存储/传输,再转回字节数组时,文本编码会将密文中的非法字符序列替换、丢弃,最终得到的字节数组长度不再是16的整数倍,且内容损坏。 - 密钥不匹配:AES-256要求密钥长度固定为32字节,如果加密和解密使用的密钥字节内容不一致、长度不符合要求,也会在最终块校验阶段抛出该异常。
修复方案
- 密文转码必须使用二进制安全的Base64编码,禁止直接用文本编码处理密文字节:
- 加密后转可传输字符串:
string cipherStr = Convert.ToBase64String(加密得到的密文字节数组); - 解密前从字符串还原密文:
byte[] cipherBytes = Convert.FromBase64String(待解密的密文字符串);
- 加密后转可传输字符串:
- 在解密方法入口增加密文合法性校验,提前拦截损坏的输入:
public byte[] decrypt(byte[] skey, byte[] data) { // 新增校验逻辑 if (data == null || data.Length == 0 || data.Length % 16 != 0) { throw new ArgumentException("密文损坏,长度不符合AES块要求"); } if (skey == null || skey.Length != 32) { throw new ArgumentException("AES-256密钥长度必须为32字节"); } PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher( new AesEngine(), new Pkcs7Padding()); cipher.Init(false, new KeyParameter(skey)); int outputSize = cipher.GetOutputSize(data.Length); byte[] tempOP = new byte[outputSize]; int processLen = cipher.ProcessBytes(data, 0, data.Length, tempOP, 0); int outputLen = cipher.DoFinal(tempOP, processLen); byte[] result = new byte[processLen + outputLen]; Array.Copy(tempOP, 0, result, 0, result.Length); return result; }
- 校验加解密两端的密钥:确认加密、解密传入的
skey字节数组内容完全一致,长度固定为32字节,没有在传递过程中被修改。
内容的提问来源于stack exchange,提问作者harshil shah
相关产品推荐
相关产品推荐

