第二部分:如何使Ruby AES-256-CBC和PHP MCRYPT_RIJNDAEL_128一起玩起来

这个问题是我最后一个问题的延续,关于 How to make Ruby AES-256-CBC and PHP MCRYPT_RIJNDAEL_128 play well together.我现在有工作,但我仍然在努力去走另一个方向. PHP生成的密码似乎具有提供的所有信息,但是我无法获取Ruby代码来解密它,没有错误.

以下是我用于生成密码的PHP代码

$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代码优雅地处理最终的块.

解决方法

问题是mcrypt没有填充最后一个块,而Ruby的OpenSSL绑定使用认的OpenSSL填充方法,即PKCS填充.我从OpenSSL文档中的描述不能真正改进:

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.

相关文章

validates:conclusion,:presence=>true,:inclusion=>{...
一、redis集群搭建redis3.0以前,提供了Sentinel工具来监控各...
分享一下我老师大神的人工智能教程。零基础!通俗易懂!风趣...
上一篇博文 ruby传参之引用类型 里边定义了一个方法名 mo...
一编程与编程语言 什么是编程语言? 能够被计算机所识别的表...
Ruby类和对象Ruby是一种完美的面向对象编程语言。面向对象编...