2

I have a database filled with encrypted passwords that I need to decrypt in Ruby for a platform change. How can I port this PHP code to Ruby? Have tried to use OpenSSL in Ruby with AES_256 but getting 'Bad Decrypt' errors and also errors that my key ($salt) isn't long enough.

In the example below, $salt is a 25 character string.

This is the PHP decryption function:

function decrypt_password($text, $salt)
{
    return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256,
        $salt, base64_decode($text), MCRYPT_MODE_ECB, 
        mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB),
        MCRYPT_RAND)));
}
Kyle Johnson
  • 1,605
  • 2
  • 17
  • 26

2 Answers2

5

There is a ruby library for mcrypt as well. See below for a sample implementation:

require 'mcrypt'
require 'base64'

# base64_decode() equivalent
encrypted = Base64.decode64(text)

# preparing Mcrypt library for Rijndael cipher, 256 bits, ECB mode
cipher = Mcrypt.new(:rijndael_256, :ecb, salt, nil, :zeros)

# padding required
encrypted = encrypted.ljust((encrypted.size / 32.0).ceil * 32, "\0") 

# decrypt using Rijndael
decrypted = cipher.decrypt(encrypted).strip

Dependencies: libmcrypt

  • sudo apt-get install libmcrypt-dev (Ubuntu/Debian)
  • sudo yum install libmcrypt-devel (RHEL/CentOS/Fedora)

Gems: mcrypt

  • gem install ruby-mcrypt
TheLonelyGhost
  • 327
  • 6
  • 11
Petr
  • 3,214
  • 18
  • 21
  • Other answer was informative, but this was the one that actually answered the *exact same question* I had. Just confirmed after using ruby to ETL 300,000+ records that needed to be decrypted. Thanks! – TheLonelyGhost Oct 28 '14 at 23:17
  • @TheLonelyGhost That's a very large edit, can you explain what you did in there? And why the code had to be altered to such a large degree? – Maarten Bodewes Oct 28 '14 at 23:52
  • @owlstead I added comments explaining each line, refactored the code to exactly fit variable names given in the question for added clarity, and noted dependencies and how to install them on a few platforms. This hopefully clarified the original poster's intent. – TheLonelyGhost Oct 29 '14 at 00:27
  • OK, approved it. Thanks for the edit. Petr, this is an extensive edit, please roll back if you don't agree - it seems good to me. – Maarten Bodewes Oct 29 '14 at 00:29
  • 1
    Seems good to me. Thanks @TheLonelyGhost for changing my raw code snippet to real answer. – Petr Oct 29 '14 at 12:36
3

MCRYPT_RIJNDAEL_256 algorithm does not implement AES, it implements Rijndael using a 256 bit block size. This is not a default mode, you can find an implementation for Ruby here.

Furthermore, you seem to be using the $salt variable as a key. Keys are automatically extended to the next available key size. For 25 byte keys I presume a 256 bit (32 byte) key will be used. This is the $salt value, extended with bytes valued 00. Note that I'm presuming that each character is encoded as a single byte on your system.

As a final surprise, you may safely disregard the mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND) part of the code, as ECB mode does not use an IV, so the value it returns is fully ignored. Note that using ECB mode for strings - and therefore also passwords of course - is not secure.

You should, at the very minimum use AES CBC with a random IV. And you should consider using bcrypt instead of encryption if you don't need the value of the passwords itself.

Community
  • 1
  • 1
Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263