PKCS#7 填充(PKCS#7 Padding)是分组密码中最常用的一种字节填充方式 ,目的是把任意长度 的明文补齐到分组大小的整数倍 (通常 8 或 16 字节)。
核心规则一句话:
每个填充字节的值 = 需要填充的字节数
一、算法步骤(以 16-byte 分组为例)
- 计算缺多少字节:
padLen = blockSize - (dataLen % blockSize)
若数据刚好整除,则额外补一整组(16 字节)。 - 在尾部追加
padLen个字节,每个字节值都是padLen(1~16)。 - 解密后,读取最后一个字节的数值即可知道真实数据长度,把填充剪掉即可。
二、实例
| 原始数据 | 缺字节 | 填充后(HEX) |
|---|---|---|
01 02 03 04 05(5 B) |
11 | 01 02 03 04 05 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B |
00 01 ... 0F(16 B) |
16 | 00 01 ... 0F 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 |
三、与其他填充区别
- PKCS#5 填充:只定义 8-byte 分组,算法与 PKCS#7 完全一致;后来 PKCS#7 把块大小推广到 1~255,因此**>8 字节分组时叫 PKCS#7**。
- ZeroPadding:全补 0x00,无法区分原始末尾 0 还是填充。
- ISO10126:填充字节除最后一个外随机,最后一字节为长度(已淘汰)。
- ANSI X.923:填充字节全 0,最后一字节为长度。
四、代码片段(Java,AES-128-CBC)
java
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); // 块大小 16,即 PKCS#7
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
byte[] out = cipher.doFinal(plain);
五、常见陷阱
- 解密后一定要去掉填充 ,否则末尾会多出一串
0x0n。 - 填充本身不抗篡改,需配合 MAC(如 HMAC)或 AEAD(如 GCM)。
- 块大小只能是 1~255;AES 固定 16 字节,3DES 固定 8 字节。
一句话记住
PKCS#7 填充 = 缺 N 字节就补 N 个 0xN,解密后读最后一字节即可知道真实长度。