Rijndael AES-128 Ruby加密解密


Rijndael AES-128 encryption decryption in Ruby

我想在ruby中使用rijndael aes128进行加密。我有这个代码:

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函数:

<?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代码产生相同的输出?

require 'openssl'
cleartext = '2~1~000024~0910~20130723092446~T~00002000~USD~F~375019001012120~0~0~00000000000~'
key = 'abcdef0123456789abcdef0123456789'
iv = '0000000000000000'
cipher = OpenSSL::Cipher::Cipher.new("aes-128-cbc")
cipher.encrypt
cipher.padding = 0
cipher.key = [key].pack('H*')
cipher.iv = [iv].pack('H*')
encrypted = cipher.update(cleartext)
encrypted << cipher.final
puts encrypted.unpack('H*').first.upcase

输出:

0D5835AFEBEE04C6DC2421538DB7C38A1283970EB31F21A47D2E3CC623D29EF0461279C7ACF93B031BE2B69CE45C9339554957F29EF609F019EEC975983A03B537622D7E0F196BE148F1C7CBB88E602A

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

PKCS填充的工作原理是添加n个值为n的填充字节,使数据的总长度是块大小的倍数。总是添加填充,因此如果数据已经是块大小的倍数,则n将等于块大小。例如,如果块大小是8并且11个字节要被加密,则将添加值为5的5个填充字节。在加密之前,您需要在PHP中的明文末尾手动添加适当的填充。要做到这一点,请在加密$cleartext(将16作为块大小传递)之前,通过PHP端的这个pkcs5_pad函数传递$cleartext。

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

如果你也走另一条路(用Ruby加密,用mcrypt解密),你必须在解密后去掉填充字节。

补充说明:即使明文已经是块大小的倍数(一整块填充),也必须添加填充,这样当你解密时,你就知道最后一块的最后一个字节总是添加的填充量。否则,您无法区分只有一个填充字节的明文和刚好以值0x01结束的没有填充字节的cleartext之间的区别。