1

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

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/>";
  ?>

I got my desired output:

0D5835AFEBEE04C6DC2421538DB7C38A1283970EB31F21A47D2E3CC623D29EF0461279C7ACF93B031BE2B69CE45C9339554957F29EF609F019EEC975983A03B537622D7E0F196BE148F1C7CBB88E602A

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

Wayne Conrad
  • 103,207
  • 26
  • 155
  • 191
Deepak Kumar Jha
  • 462
  • 6
  • 15
  • There is so much things that can go wrong and since PHP and Ruby are enemies how are you expecting people to inspect your problem ? Try to browse both manuals or check some questions on SO (on the right bar), maybe [this](http://stackoverflow.com/questions/1862710/how-to-make-ruby-aes-256-cbc-and-php-mcrypt-rijndael-128-play-well-together) one will give you some insight at what may be wrong ... – HamZa Aug 22 '13 at 08:14

2 Answers2

5
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

Output:

0D5835AFEBEE04C6DC2421538DB7C38A1283970EB31F21A47D2E3CC623D29EF0461279C7ACF93B031BE2B69CE45C9339554957F29EF609F019EEC975983A03B537622D7E0F196BE148F1C7CBB88E602A
Patrick Oscity
  • 53,604
  • 17
  • 144
  • 168
  • this is my complete code that give the same o/p as i written above check this ."; echo "Length: ".strlen($data_encrypted)."
    "; ?>
    – Deepak Kumar Jha Aug 22 '13 at 13:01
  • This code is very different from the one you posted above! How are we supposed to guess all that surrounding code? When you post lots of code, please just edit your answer instead of putting it into a comment. – Patrick Oscity Aug 22 '13 at 13:57
  • Your code throws a warning: `mcrypt_encrypt(): The IV parameter must be as long as the blocksize`. Both the key and the IV must be twice as long! – Patrick Oscity Aug 22 '13 at 14:05
  • I know PHP code giving warning but that is not an issue. If you konw how to convert that code in ruby or if u can correct the above ruby code or if you can detect the area where i making mistake in ruby code then answer please – Deepak Kumar Jha Aug 22 '13 at 14:29
  • You cannot convert that code to ruby with the short key because ruby will throw an error and exit! – Patrick Oscity Aug 22 '13 at 14:33
  • above ruby code giving o/p but that is not same as the o/p of php code. if it throw an exception then how it giving output.... – Deepak Kumar Jha Aug 22 '13 at 14:38
  • Now i have the solution. I will not explain my answer because i am tired of editing it all the time because the question changes. Good luck. – Patrick Oscity Aug 22 '13 at 14:38
  • Btw Ruby threw this error with 256 mode: `OpenSSL::Cipher::CipherError: iv length too short` and `OpenSSL::Cipher::CipherError: key length too short`. But it will not exit (i was wrong). It will just use a zero key and iv. – Patrick Oscity Aug 22 '13 at 14:54
  • @DeepakKumarJha please never ever post code in comments, update your question instead. – Maarten Bodewes Aug 23 '13 at 12:21
  • What's with all the accepting and unaccepting? Are you not yet happy with the answer? Then please explain what's missing. – Patrick Oscity Aug 26 '13 at 12:20
  • I have a same issue some one can help http://stackoverflow.com/questions/25940754/status-detail-3045-the-currency-field-is-missing – Ramesh Somalagari Sep 20 '14 at 07:40
4

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 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);
}

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.

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.

Nil'z
  • 7,487
  • 1
  • 18
  • 28