草庐IT

php - 第二部分 : How to make Ruby AES-256-CBC and PHP MCRYPT_RIJNDAEL_128 play well together

coder 2023-12-31 原文

这个问题是我上一个问题的延续,关于 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​​ 代码优雅地处理最后一个 block 。

最佳答案

问题是 mcrypt 没有填充最后一个 block ,而 Ruby 的 OpenSSL 绑定(bind)使用默认的 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 作为 block 大小)。

function pkcs5_pad ($text, $blocksize)
{
    $pad = $blocksize - (strlen($text) % $blocksize);
    return $text . str_repeat(chr($pad), $pad);
}

如果您也采用其他方式(在 Ruby 中加密并使用 mcrypt 解密),则必须在解密后去除填充字节。

旁注:即使明文已经是 block 大小的倍数(一整 block 填充),您也必须添加填充的原因是,当您解密时,您知道最后一个 block 的最后一个字节总是添加的填充量。否则,您无法区分具有单个填充字节的明文和没有恰好以值 0x01 结尾的填充字节的明文。

关于php - 第二部分 : How to make Ruby AES-256-CBC and PHP MCRYPT_RIJNDAEL_128 play well together,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1864700/

有关php - 第二部分 : How to make Ruby AES-256-CBC and PHP MCRYPT_RIJNDAEL_128 play well together的更多相关文章

随机推荐