Ruby中的Rijndael AES-128加密解密

问题描述:

我想使用rijndael aes128在ruby中进行加密.我有以下代码:

I want to use rijndael aes128 for encryption in ruby. I have this code:

cipher = OpenSSL::Cipher::Cipher.new("aes-128-cbc")
cipher.encrypt
cipher.key = 'abcdef0123456789abcdef0123456789'
cipher.iv = '0000000000000000'
encrypted =   cipher.update('2~1~000024~0910~20130723092446~T~00002000~USD~F~375019001012120~0~0~00000000000~')
encrypted << cipher.final

这不起作用.但是使用此PHP函数:

which is not working. But using this PHP function:

<?php 
 function hex2bin($hex_string) 
  {
     return pack('H*', $hex_string);
  } 
 $data_to_encrypt = '2~1~000024~0910~20130723092446~T~00002000~USD~F~375019001012120~0~0~00000000000~';
  $key = 'abcdef0123456789abcdef0123456789'; 
  $iv = '0000000000000000'; 
  $key = hex2bin($key);
  $iv = hex2bin($iv); 
  $data_encrypted = bin2hex(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data_to_encrypt, MCRYPT_MODE_CBC, $iv));
  echo "Data encrypted: ".strtoupper($data_encrypted)."<br/>"; echo "Length: ".strlen($data_encrypted)."<br/>";
  ?>

我得到了想要的输出:

0D5835AFEBEE04C6DC2421538DB7C38A1283970EB31F21A47D2E3CC623D29EF0461279C7ACF93B031BE2B69CE45C9339554957F29EF609F019EEC975983A03B537622D7E0F196BE148F1C7CBB88E602A

如何获取我的Ruby代码以产生相同的输出?

How can I get my Ruby code to produce the same output?

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

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. 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.