第二部分:如何使Ruby AES-256-CBC和PHP MCRYPT_RIJNDAEL_128一起发挥作用 [英] Part II: How to make Ruby AES-256-CBC and PHP MCRYPT_RIJNDAEL_128 play well together

查看:83
本文介绍了第二部分:如何使Ruby AES-256-CBC和PHP MCRYPT_RIJNDAEL_128一起发挥作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题是我最后一个问题的延续,关于

This question is a continuation of my last one, regarding How to make Ruby AES-256-CBC and PHP MCRYPT_RIJNDAEL_128 play well together. I've got that working now, but I'm still struggling to go the other direction. The PHP generated cryptogram appears to have all the information that was provided, but I cannot get the Ruby code to decrypt it without error.

这是我用来生成密码的PHP代码:

Here's the PHP code I'm using to generate the cryptogram:

$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中解密的尝试:

Then here's the attempt to decrypt in 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

真正令人沮丧的是,有可能从该加密字符串中获取整个明文.重复上述操作,但在密码中添加一个废话:

What's really frustrating about this is that it's possible to get the entire cleartext out of that encrypted string. Repeating the above, but adding a nonsense pad to the cryptogram:

  >> 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代码优雅地处理最后一个块.

In my actual use case the cleartext is structured (a JSON string, since you ask), so I feel comfortable a this point that I could tell use this scheme and detect poorly encrypted input without performing the cipher.final. However, I can't tolerate this sort of kludge in my code, so I'd like to understand how to make the ruby code handle the final block gracefully.

推荐答案

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

The problem is that mcrypt isn't padding the last block, whereas Ruby's OpenSSL binding uses the default OpenSSL padding method, which is PKCS padding. I can't really improve on the description from the OpenSSL documentation:

PKCS填充通过添加n个填充来工作 值n的字节总计 数据长度 块大小的倍数.填充为 总是添加,所以如果数据已经 块大小n的倍数将 等于块大小.例如,如果 块大小是8和11个字节是 进行加密,然后填充5个填充字节 值5将被添加.

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的明文末尾手动添加适当的填充.为此,请在加密前将$cleartext通过PHP端的此pkcs5_pad函数传递(将16作为块大小传递).

You'll need to manually add proper padding to the end of the cleartext in PHP before encrypting. To do that, pass your $cleartext through this pkcs5_pad function on the PHP side before you encrypt it (passing 16 as the blocksize).

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

如果您也选择其他方式(使用Ruby加密并使用mcrypt解密),则必须在解密后剥离填充字节.

If you also go the other way (encrypt in Ruby and decrypt with mcrypt), you'll have to strip off the padding bytes after decrypting.

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

Side note: The reason you have to add padding even if the cleartext is already a multiple of the blocksize (a whole block of padding), is so that when you are decrypting you know that the last byte of the last block is always the amount of padding added. Otherwise, you couldn't tell the difference between cleartext with a single padding byte and a cleartext with no padding bytes that just happened to end in the value 0x01.

这篇关于第二部分:如何使Ruby AES-256-CBC和PHP MCRYPT_RIJNDAEL_128一起发挥作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆