让我们来看看。 PKCS#7在RFC 5652(加密消息语法)中描述。
填充方案本身在6.3. Content-encryption Process中给出。它基本上说:根据需要附加许多字节来填充给定的块大小(但至少有一个),并且它们中的每一个应该具有作为值的填充长度。
因此,查看最后一个解密的字节,我们知道要剥离多少字节。 (也可以检查它们都具有相同的值。)
我现在可以给你一个PHP函数来做,但我的PHP有点生锈。所以要么自己做(然后随意编辑我的答案添加),或者看看user-contributed notes到mcrypt文档 – 其中一些是关于填充和提供PKCS#7填充的实现。
function encrypt($str, $key)
{
$block = mcrypt_get_block_size('des', 'ecb');
这得到所使用算法的块大小。在你的情况下,你会使用aes或rijndael_128而不是des,我想(我没有测试它)。 (相反,您可以简单地选择16进行AES,而不是调用该功能。)
$pad = $block - (strlen($str) % $block);
这将计算填充大小。 strlen($str)是数据的长度(以字节为单位),%$ block给出了模块$ block的余数,即最后一个块中的数据字节数。 $ block – …因此给出填充最后一个块所需的字节数(现在是1和$ block之间的数字,包括1)。
$str .= str_repeat(chr($pad), $pad);
str_repeat产生一个由相同字符串的重复组成的字符串,这里重复填充$ pad的character given by $ pad,$ pad时间,即长度为$ pad的字符串。
$ str。= …将此填充字符串附加到原始数据。
return mcrypt_encrypt(MCRYPT_DES, $key, $str, MCRYPT_MODE_ECB);
这里是加密本身。使用MCRYPT_RIJNDAEL_128而不是MCRYPT_DES。
}
现在的另一个方向:
function decrypt($str, $key)
{
$str = mcrypt_decrypt(MCRYPT_DES, $key, $str, MCRYPT_MODE_ECB);
解密。 (您当然会更改算法,如上所述)。 $ str现在是解密的字符串,包括填充。
$block = mcrypt_get_block_size('des', 'ecb');
这又是块大小。 (往上看。)
$pad = ord($str[($len = strlen($str)) - 1]);
这看起来有点奇怪。更好地写它在多个步骤:
$len = strlen($str);
$pad = ord($str[$len-1]);
$ len现在是填充字符串的长度,$ str [$ len – 1]是此字符串的最后一个字符。 ord将其转换为数字。因此,$ pad是我们以前用作填充的填充值的数字,这是填充长度。
return substr($str, 0, strlen($str) - $pad);
所以现在我们从字符串中截取最后的$ pad字节。 (而不是strlen($ str),我们也可以在这里写$ len:substr($ str,0,$ len – $ pad))。
}
?>
请注意,除了使用substr($ str,$ len – $ pad)之外,还可以编写substr($ str, – $ pad),因为PHP中的substr函数具有负操作数/参数的特殊处理,以计数从字符串的末尾。 (我不知道这是否比首先获得长度并且手动计算索引的效率更高或更低)。
如前所述,在rossum的评论中注意到,而不是简单地剥离像这样完成的填充,你应该检查它是否正确 – 即查看substr($ str,$ len – $ pad),并检查它的全部字节是chr($ pad)。这可以作为对腐败的轻微检查(尽管如果使用链接模式而不是ECB,此检查更有效,而不是替代真正的MAC)。
(还是告诉你的客户,他们应该考虑改变一个比ECB更安全的模式。)