public
Description: acts_as_authenticated Ruby on Rails authentication system
Home | Edit | New

Reversible Encrypted Passwords

(this is a bad idea, never do it)
This is a simple method to get strong (NOPE) reversible encrypted passwords with Acts as Authenticated. It uses SHA1 by default, meaning a password reset is not an option without generating a completely new password. This uses the DES encryption scheme and the user’s salt as the private key:

First, require the necessary libraries:

require ‘openssl’
require ‘base64’

Now, you’ll need to overwrite some of the model’s default encrypt methods:

class User < ActiveRecord::Base

  1. Encrypts some data with the salt.
    def self.encrypt(password, salt)
    enc = OpenSSL::Cipher::Cipher.new(‘DES-EDE3-CBC’)
    enc.encrypt(salt)
    data = enc.update(password)
    Base64.encode64(data << enc.final)
    end
  1. getter method to decrypt password
    def password
    unless @password
    enc = OpenSSL::Cipher::Cipher.new(‘DES-EDE3-CBC’)
    enc.decrypt(salt)
    text = enc.update(Base64.decode64(crypted_password))
    @password = (text << enc.final)
    end
    @password
    rescue
    nil
    end
    end

for activate and 2-way reversible encryption bug see:

http://wiki.rubyonrails.org/rails/pages/Acts_as_authenticated

Bad Idea

Reversibly encrypted passwords are just as bad as not encrypting/hashing at all. They are both a legal liability and a security vulnerability. They are a security vulnerability because the decryption key is stored along side the encrypted value. If an attacker gains access to your database, all passwords will have been exposed. They are a legal liability because anyone within your organization can easily decrypt the passwords and potentially access your users’ other accounts (if they choose bad passwords). You may be held liable for storing your user’s passwords with such an easily recoverable mechanism.

Base64 quirk: adam from 6 bar 8 dot com

calling ‘Base64.encode64’ will return a string with a trailing ’\n’. This is fine if you encrypt a user password, the compare that with the crypted_password, but if you use it for anything else, such as account activation, the encoded string that comes in will not contain a ’\n’, and the activation will fail.
I changed it to:

Base64.encode64(data << enc.final).strip

that works and it is (surprisingly) still decoded correctly. Response:This is not surprising. Whitespace in base64 encoding is only used for formatting. Thus, whitespace is actually ignored when the decoding is performed.

The call to enc.update will fail if the argument is empty, as happens when authenticate is called with an empty password (e.g., because a login form was submitted without entering one).

I changed authenticated thus:

def authenticated?(password) !password.empty? && crypted_password == encrypt(password) end

to prevent this. —Roger Rohrbach

DES and Base64 blow the crypted_password length up to 66 characters including two ’\n’. The last ’\n’ can be strip as in the example above. So make sure that you use 65 characters in your db column.

Last edited by gundestrup, Fri Oct 24 03:39:59 -0700 2008
Home | Edit | New
Versions: