分组密码算法中需要将明文按指定大小进行分组,由于明文并非指定大小的整数倍,因此在明文的最后一个分组需要将其填充至加密算法所要求的分组大小后进行加密。
常见的填充模式有:
1. NoPadding
不填充,在此填充下原始数据必须是分组大小的整数倍,非整数倍时无法使用该模式。
2. PKCS5Padding / PKCS7Padding
PKCS7Padding是当下各大加密算法都遵循的填充算法,且OpenSSL加密算法默认填充算法就是 PKCS7。
填充至符合块大小的整数倍,填充值为填充数量数。
假设每个区块大小为 blockSize:
-
已对齐,填充一个长度为 blockSize 且每个字节均为 blockSize 的数据。
-
未对齐,需要补充的字节个数为 n,则填充一个长度为 n 且每个字节均为 n 的数据。
PKCS7PADDING 的块大小可以为 1~255 中任意值, PKCS5PADDING 是 PKCS7PADDING 的子集,块大小只能为固定值 8。
假设:块大小为8 ,则PKCS7PADDING 和 PKCS5PADDING 是一样的。
填充示例
原始:FF FF FF FF FF FF FF FF FF
填充:FF FF FF FF FF FF FF FF FF 07 07 07 07 07 07 07
原始:FF FF FF FF FF FF FF FF
填充:FF FF FF FF FF FF FF FF 08 08 08 08 08 08 08 08
原文为整数倍也需要填充。
早期的PKCS#5 (一般指v2.0以及更早版本见rfc2898)确实只给出了block size等于8byte的情况,但要注意这些版本的PKCS#5也并没有用于AES,只是给出DES和RC2的加密标准(见RFC2898 6.1),AES的加密标准,如OpenSSL中的实现,都是用的PKCS#7,也是PKCS#5基础上的后继。
2017年提出的PKCS#5 v2.1(见rfc8018)才开始把AES/TDES/RC5也加进来,其中规定了AES用的是CMS(见rfc5652),即PKCS#7基础上做了一些修改的后续版本。
AES内容块大小为16byte,在不同的长度下需填充的字节个数可以为1到16个,对应的填充值为0x01到0x10。 也就是说在AES加密算法中,pkcs#5和pkcs#7是没有区别的。PKCS#5 只能padding 8byte这个说法也是错的。
其实现算法如下:
#include <memory.h>
#include <string.h>
#include <stdio.h>
#define BLOCK_SIZE 16 //8
int pkcs7_padding(unsigned char *pSrcData, int iSrcDataLen, unsigned char *pDstData, int *iDstDataLen)
{
int remainder = iSrcDataLen % BLOCK_SIZE;
int padding = BLOCK_SIZE - remainder;
*iDstDataLen = iSrcDataLen + padding;
memcpy(pDstData, pSrcData, iSrcDataLen);
memset(pDstData+ iSrcDataLen, padding, padding);
return 0;
}
int pkcs7_strip(unsigned char *pSrcData, int iSrcDataLen, unsigned char *pDstData, int *iDstDataLen)
{
int padding = pSrcData[iSrcDataLen - 1];
int iLen = iSrcDataLen - padding;
memcpy(pDstData, pSrcData, iLen);
*iDstDataLen = iLen;
return 0;
}
3. ISO10126Padding
填充至符合块大小的整数倍,填充值最后一个字节为填充的数量数,其他字节随机处理。
原始:FF FF FF FF FF FF FF FF FF
填充:FF FF FF FF FF FF FF FF FF 3F 7A B4 09 14 36 07
4. ISO7816-4Padding
填充至符合块大小的整数倍,填充值第一个字节为 0x80,其他字节填 0。
原始:FF FF FF FF FF FF FF FF FF
填充:FF FF FF FF FF FF FF FF FF 80 00 00 00 00 00 00
5. ZeroBytePadding
填充至符合块大小的整数倍,填充值为 0。
原始:FF FF FF FF FF FF FF FF FF
填充:FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00
6. X923Padding【ANSI X.923】
填充至符合块大小的整数倍,填充值最后一个字节为填充的数量数,其他字节填 0。
原始:FF FF FF FF FF FF FF FF FF
填充:FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 07
7. TBCPadding(Trailing-Bit-Compliment)
填充至符合块大小的整数倍,原文最后一位为“1”时填充 0x00,最后一位为“0”时填充“0xFF”。
原始:FF FF FF FF FF FF FF FF FF
填充:FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00
原始:FF FF FF FF FF FF FF FF F0
填充:FF FF FF FF FF FF FF FF F0 FF FF FF FF FF FF FF
8. PKCS1Padding
该填充模式是 RSA 加密中使用的,详见 RFC 2313。RSA 加密时,需要将原文填充至密钥大小,填充的格式为:00 + BT + PS + 00 + D
。
-
00 为固定字节
-
BT 为处理模式。公钥操作时为 02,私钥操作为 00 或 01
-
PS 为填充字节,填充数量为 k - 3 - D,k 表示密钥长度,D 表示原文长度。PS 的最小长度为 8 个字节。填充的值根据 BT 值不同而不同:
-
BT = 00 时,填充全 00
-
BT = 01 时,填充全 FF
-
BT = 02 时,随机填充,但不能为 00