$cleartext = "Who's the clever boy?"; $key = base64_decode("6sEwMG/aKdBk5Fa2rR6vVw==\n"); $iv = base64_decode("vCkaypm5tPmtP3TF7aWrug=="); $cryptogram = mcrypt_encrypt(MCRYPT_RIJNDAEL_128,$key,$cleartext,MCRYPT_MODE_CBC,$iv); $result = base64_encode($cryptogram); print "\n'$result'\n"; RESULT 'JM0OxMINPTnF1vwXdI3XdKI0KlVx210CvpJllFja+GM='
那么这里是尝试在Ruby中解密:
>> cipher = OpenSSL::Cipher::Cipher.new('aes-128-cbc') >> cipher.key = Base64.decode64("6sEwMG/aKdBk5Fa2rR6vVw==\n") >> cipher.iv = Base64.decode64("vCkaypm5tPmtP3TF7aWrug==") >> cryptogram = Base64.decode64('JM0OxMINPTnF1vwXdI3XdKI0KlVx210CvpJllFja+GM=') >> cleartext = cipher.update(cryptogram) => "Who's the clever" >> cleartext << cipher.final OpenSSL::Cipher::CipherError: bad decrypt from (irb):100:in `final' from (irb):100
真正令人沮丧的是,可以从加密字符串中获取整个明文.重复上述,但添加一个废话垫到密码:
>> cleartext = cipher.update(cryptogram + 'pad') => "Who's the clever boy?\000\000\000\000\000\000\000\000\000\000\000" >> cleartext << cipher.final OpenSSL::Cipher::CipherError: bad decrypt from (irb):119:in `final' from (irb):119
在我的实际使用情况下,明文是结构化的(一个JSON字符串,因为你问),所以我觉得很舒服,我可以告诉使用这个方案,并检测不好的加密输入,而不执行cipher.final.但是,我不能容忍这种在我的代码中的这种类型,所以我想了解如何使ruby代码优雅地处理最终的块.
解决方法
PKCS padding works by adding n padding
bytes of value n to make the total
length of the data a
multiple of the block size. Padding is
always added so if the data is already
a multiple of the block size n will
equal the block size. For example if
the block size is 8 and 11 bytes are
to be encrypted then 5 padding bytes
of value 5 will be added.
在加密之前,您需要手动将适当的填充添加到PHP中的明文末尾.要做到这一点,在加密之前通过PHP侧的pkcs5_pad函数传递$cleartext(通过16作为块大小).
function pkcs5_pad ($text,$blocksize) { $pad = $blocksize - (strlen($text) % $blocksize); return $text . str_repeat(chr($pad),$pad); }
如果您还以另一种方式(在Ruby中加密并使用mcrypt进行解密),则必须在解密之后删除填充字节.
旁注:即使明文已经是块大小(整个填充块)的倍数,你必须添加填充的原因是,当您解密时,您知道最后一个块的最后一个字节总是数量的填充.否则,你无法区分明文与单个填充字节和明文之间的差异,没有填充字节刚刚结束的值0x01.