新闻  |   论坛  |   博客  |   在线研讨会
数据填充规则之PKCS7
电子禅石 | 2022-03-09 16:46:53    阅读:14774   发布文章

数据填充规则之PKCS7

安全芯片本身支持各种标准的加密算法,用户可以使用相应的算法完成数据的加解密、签名验签等功能来完善自己产品的安全性。在数据加解密应用中,数据填充又是其中重要的组成部分。数据填充通常有两个作用一是按要求将数据补足到要就的块长度来满足加密算法的应用需求;二是通过增加填充数据来进一步提高密文的安全性。本次主要介绍分组对称算法中常用的PKCS7。

PKCS7是当下各大加密算法都遵循的填充算法,且 OpenSSL 加密算法默认填充算法就是 PKCS7。PKCS7Padding的填充方式为当数据长度不足数据块长度时,缺几位补几个几,eg.对于AES128算法其数据块为16Byte(数据长度需要为16Byte的倍数),如果数据为”00112233445566778899AA”一共11个Byte,缺了5位,采用PKCS7Padding方式填充之后的数据为“00112233445566778899AA0505050505”。

特别注意的一点是如果是数据刚好满足数据块长度也要在元数据后在按PKCS7规则填充一个数据块数据,这样做的目的是为了区分有效数据和补齐数据。仍以AES128为例:如果数据为”00112233445566778899AABBCCDDEEFF”一共16个符合数据块规则采用PKCS7Padding方式填充之后的数据为

“00112233445566778899AABBCCDDEEFF10101010101010101010101010101010”


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。

*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
属于自己的技术积累分享,成为嵌入式系统研发高手。
推荐文章
最近访客