Ruby中的Rijndael AES-128加密解密

我想在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)."
"; echo "Length: ".strlen($data_encrypted)."
"; ?>

我得到了我想要的输出:

 0D5835AFEBEE04C6DC2421538DB7C38A1283970EB31F21A47D2E3CC623D29EF0461279C7ACF93B031BE2B69CE45C9339554957F29EF609F019EEC975983A03B537622D7E0F196BE148F1C7CBB88E602A 

如何让我的Ruby代码生成相同的输出?

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

PKCS填充通过添加n个值为n的填充字节来工作,以使数据的总长度为块大小的倍数。 总是添加填充,因此如果数据已经是块大小的倍数,则n将等于块大小。 例如,如果块大小为8并且要加密11个字节,则将添加5个值为5的填充字节。 在加密之前,您需要在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中结束。

 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