PKCS7
PKCS7
是当下各大加密算法都遵循的数据填充算法,且 OpenSSL
加密算法簇的默认填充算法就是 PKCS7
。AES-128
, AES-192
, AES-256
的数据块长度分别为 128/8=16bytes
, 192/8=24bytes
, 256/8=32bytes
。
其实PKCS7
理解起来非常简单,使用需填充长度的数值 paddingSize
所表示的ASCII
码 paddingChar = chr(paddingSize)
对数据进行冗余填充。
比如 AES-128
的数据块长度是 16bytes,使用PKCS7
进行填充时,填充的长度范围是 1 ~ 16。注意,当待加密数据长度为 16 的整数倍时,填充的长度反而是最大的,要填充 16 字节,为什么呢?因为 "PKCS7" 拆包时会按协议取最后一个字节所表征的数值长度作为数据填充长度,如果因真实数据长度恰好为 16 的整数倍而不进行填充,则拆包时会导致真实数据丢失。
为什么是冗余填充呢?因为即便你的数据长度符合blockSize
的整数倍时,也需要填充,填充的长度反而是最大的,要填充blockSize
个char(blockSize)
字符在数据尾部,这样牺牲了数据长度的做法是为了更为灵活透明的去解包数据,发送端和接收端不需要约定好blockSize
,接收端总能通过数据包的最后一个字符得到填充的数据长度。
当我们拿到一串PKCS7
填充的数据时,取其最后一个字符paddingChar
,此字符的ASCII
码的十进制ord(paddingChar)
即为填充的数据长度paddingSize
,读取真实数据时去掉填充长度即可substr(content, 0, -paddingSize)
。
填充示例,比如数据块blockSize
为 8
h<0x07><0x07><0x07><0x07><0x07><0x07><0x07> 7
he<0x06><0x06><0x06><0x06><0x06><0x06> 6
hel<0x05><0x05><0x05><0x05><0x05> 5
hell<0x04><0x04><0x04><0x04> 4
hello<0x03><0x03><0x03> 3
hello <0x02><0x02> 2
hello w<0x01> 1
hello wo<0x08><0x08><0x08><0x08><0x08><0x08><0x08><0x08> 8 // 数据块
hello wor<0x07><0x07><0x07><0x07><0x07><0x07><0x07> 7
hello word<0x06><0x06><0x06><0x06><0x06><0x06> 6
实现:
/**
* PKCS7填充
* @param string $content 待填充内容
* @param int $block_size 待填充内容数据块长度
*/
function pkcs7_padding($content, $block_size)
{
if (255 < $block_size || 0 >= $block_size) {
throw new \Exception("the block size pkcs7 can padding is (0 ~ 255] ");
}
// 待填充的长度
$padding_size = $block_size - (strlen($content) % $block_size);
// 待填充的字符
$padding_char = chr($padding_size);
$content .= str_repeat($padding_char, $padding_size);
return $content;
}
/**
* 移除PKCS7
* @param string $content
* @return string
*/
function pkcs7_strip($content)
{
$padding_char = substr($content, -1);
$padding_size = ord($padding_char);
$content = substr($content, 0, -$padding_size);
return $content;
}
$content = pkcs7_padding("hello", $block_size);
echo pkcs7_strip($content);
PKCS5
pkcs5
作为pkcs7
的子集算法,概念上没有什么区别,只是在blockSize
上固定为 8 bytes,即数据始终会被切割成 8 个字节的数据块,然后计算需要填充的长度。pkcs7
的填充长度blockSize
是 1~255
bytes。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。