Using bcrypt-ruby in Rails

Joe McPartland
3 min readNov 18, 2022

--

What is bcrypt?

bcrypt is a password-hashing function based on the Blowfish cipher. It was designed by Niels Provos and David Mazières and is the default password hash algorithm for OpenBSD. bcrypt incorporates a salt to protect against rainbow-table attacks. bcrypt-ruby is the Ruby implementation of bcrypt.

bcrypt Versions

The latest ruby gems available are:

  1. 3.1.18 — May 16, 2022 java (69.5 KB)
  2. 3.1.18 — May 16, 2022 (54.5 KB)
  3. 3.1.17 — March 14, 2022 java (69.5 KB)
  4. 3.1.17 — March 14, 2022 (54.5 KB)
  5. 3.1.16 — September 03, 2020 java (68.5 KB)
  6. 3.1.12 — May 16, 2018 (43.5 KB)

Development Dependencies :

How to install the bcrypt gem

gem install bcrypt

How bcrypt works

To see how the BCrypt class works, type the following into IRB. Remember if you create the same password as below, the hash will be different because of salting. Salting is when some random data is added to the password before it is hashed. This makes it more difficult / time consuming for hackers using Rainbow tables. To find out more about Rainbow tables, check out this wikipedia article.

require 'bcrypt'
=> true
pw1 = BCrypt::Password.create("mypassword")
=> "$2a$12$5scgl6wb3P7eeaOniiendeHX4N1JMoRFSQ6AF9gEB.vii/pWk.LJi"

The hash is split between the salt and the checksum. You can view each of them with the following commands.

pw1.salt
=> "$2a$12$5scgl6wb3P7eeaOniiende"
pw1.checksum
=> "HX4N1JMoRFSQ6AF9gEB.vii/pWk.LJi"

When using encryption, it is important to understand what the cost factor is. Cost factor is basically the amount of time the processor takes to create the hash. In some situations you may need to lower the cost factor to conserve processor utilization. bcrypt allows you to change the cost factor depending on your needs.

BCrypt::Engine.cost = 8
=> 8
pw2 = BCrypt::Password.create("mypassword")
=> "$2a$08$uTUc7IHwjUrV7mCmNcb9OexGzgTOsLDunrZp04yd.DKEd2W37UUmG"
pw2.cost
=> 8

The default cost value for bcrypt is 12. Lower numbers decrease processor utilization.

Configuring Ruby on Rails to use bcrypt

This configuration uses Rails version ≥ 3. Create a User model with the following schema. It is important to create the password_digest columns in your database for bcrypt to work.

create_table “users”, do |t|
t.string “username”
t.string “password_digest”
end

Create a User model and add has_secure_password to the top of the User class. When using ActiveRecord, ActiveModel::SecurePassword is automatically included.

class User < ApplicationRecord
has_secure_password
end

The following examples use the methods that are available after adding has_secure_passwordto the User model.

user = User.new(username: 'joe', password: '', password_confirmation: 'nomatch')
user.save
# => false, password required

user.password = 'mUc3m00RsqyRe'
user.save
# => false, confirmation doesn't match

user.password_confirmation = 'mUc3m00RsqyRe'
user.save
# => true

user.recovery_password = "42password"
user.recovery_password_digest
# =>”"$2a$04$iOfhwahFymCs5weB3BNH/uXkTG65HR.qpW.bNhEjFP3ftli3o5DQC"

user.save
# => true

user.authenticate('notright')
# => false

user.authenticate('mUc3m00RsqyRe')
# => user

user.authenticate_recovery_password('42password')
# => user

User.find_by(name: 'joe')&.authenticate('notright')
# => false

User.find_by(name: 'joe')&.authenticate('mUc3m00RsqyRe')
# => user

Create a user account

To create a user account, add the following to the users_controller.rb file.

class UsersController < ApplicationController

def create
user = User.create(params[:user, :password, :password_confirmation])
end

end

It’s a good idea to use sessions when working with user accounts in Ruby on Rails. Sessions enable your application to maintain user-specific state. This allows users to authenticate once and remain signed in for future requests until you log out. To know more about sessions and cookies see: https://guides.rubyonrails.org/security.html

For more information on using has_secure_password in Ruby on Rails, check out the following document. Also, check out the the rubydocs.info on bcrypt here.

--

--