DEV Community

DaNeil C
DaNeil C

Posted on • Updated on

BCrypt == Ruby 'magic'??

Passwords are used everyday to access our banks, check emails, use social media, play games, and even just communication over video like Zoom or Skype. Across each of these platforms they use (or should use) a function to 'hash' the password to make sure it is secure and that only the user is able to access their own data.
BCrypt is one of the methods most commonly use with Ruby on Rails applications to 'salt' and 'hash' the password so that when it is saved it is not easily readable in plain text if it is accessed unethically and to help prevent rainbow attacks.

Where did BCrypt come from?

Created in the 1990s, BCrypt was designed by The OpenBSD project and based on the Blowfish cipher, a block cipher. BCrypt is a sophisticated and secure hash algorithm used for hashing passwords in C, C++, C#, Go, Java, JavaScript, Elixir, Perl, PHP, Python, Ruby, and Node.js to name a few languages. (1)
In Ruby specifically, "the bcrypt Ruby gem provides a simple wrapper for safely handling passwords." (2)

What is a Salt?

Salting data is the process of adding some extra random data to the input of a hash algorithm to guarantee a unique output, "increase their complexity without increasing user requirements, and to mitigate password attacks like rainbow tables." (3)

Rainbow Table Attack You Say???

A rainbow table attack is a type of attacking method where the hacker tries to use a rainbow table, a precomputed lookup table used for storing password hashes, to crack the passwords stored in a database system. (4)

Name Simple Hash with collision
alice 4420d1918bbcf7686defdf9560bb5087d20076de5f77b7cb4c3b40bf46ec428b
jason 695ddccd984217fe8d79858dc485b67d66489145afa78e8b27c1451b27cc7a2b
mario cd5cb49b8b62fb8dca38ff2503798eae71bfb87b0ce3210cf0acac43a3f2883c
teresa 73fb51a0c9be7d988355706b18374e775b18707a8a03f7a61198eefc64b409e8
bob 4420d1918bbcf7686defdf9560bb5087d20076de5f77b7cb4c3b40bf46ec428b
mike 77b177de23f81d37b5b4495046b227befa4546db63cfe6fe541fc4c3cd216eb9

How does Bcrypt help prevent Rainbow Attacks?

Bcrypt helps to prevent this type of attack by
1) Slowing down the computational speed of hashing the data, thus slowing down, or thwarting completely, the ability of an attacker to preform this type of attack.
2) Allowing the each hash to have its own random salt to be hashed with the data, thus creating a truly unique output.
3) Allowing the developer to control the cost, or work, of Bcrypt. This can allow them to make it fast enough that users don't notice but slow enough to make it plausible for an attacker to guess all possible outputs for a hash.

What is a 'hash' Function?

A hash function is simply a function that takes in input value and creates an output value deterministic of the input value. It is designed act as a "one-way function". A one-way function is a mathematical operation that's easy to perform, but very difficult, and generally impossible, to reverse.

The Really interesting part to me is how many times and ways that something can be hashed... See below for a few interesting ways/combinations to hash data.

Generic hash types:
MD5 /md5($pass.$salt) /md5($salt.$pass) / md5(utf16le($pass).$salt) / md5($salt.utf16le($pass))
HMAC-MD5 (key = $pass) / HMAC-MD5 (key = $salt)
SHA1 / sha1($pass.$salt) / sha1($salt.$pass) / sha1(utf16le($pass).$salt) / sha1($salt.utf16le($pass))
HMAC-SHA1 (key = $pass) / HMAC-SHA1 (key = $salt)
MySQL323 / MySQL4.1/MySQL5
phpass, WordPress (MD5), Joomla (MD5)
phpass, phpBB3 (MD5)
md5crypt, MD5 (Unix), Cisco-IOS $1$ (MD5) 2
Juniper IVE
Domain Cached Credentials (DCC), MS Cache
SHA-256 / sha256($pass.$salt) / sha256($salt.$pass) / sha256(utf16le($pass).$salt) / sha256($salt.utf16le($pass))
HMAC-SHA256 (key = $pass) / HMAC-SHA256 (key = $salt)
descrypt, DES (Unix), Traditional DES
Apache $apr1$ MD5, md5apr1, MD5 (APR) 2
SHA-512 / sha512($pass.$salt) / sha512($salt.$pass) / sha512(utf16le($pass).$salt) / sha512($salt.utf16le($pass))
HMAC-SHA512 (key = $pass) / HMAC-SHA512 (key = $salt)
sha512crypt $6$, SHA512 (Unix) 2
Domain Cached Credentials 2 (DCC2), MS Cache 2
Cisco-PIX MD5 / Cisco-ASA MD5
Oracle H: Type (Oracle 7+), DES(Oracle)
bcrypt $2*$, Blowfish (Unix)
md5($salt.md5($pass)) / md5($salt.$pass.$salt) / md5(md5($pass).md5($salt)) / md5($salt.md5($salt.$pass)) / md5(strtoupper(md5($pass)))

What does BCrypt Hash?

Like any salted hash, BCrypt generates a salt, some random fixed byte value, and combines that with the password before the hash function creates a unique hash for each input. For example, if two users have the same password they will not have the same password hash because the random salt would make each input different.

Specifically the BCrypt algorithm is the result of encrypting the text a minimum of 64 times. In BCrypt, the usual Blowfish key setup function is replaced with an expensive key setup (EksBlowfishSetup) function. (The BCrypt algorithm depends heavily on its "Eksblowfish" key setup algorithm.)

Function bcrypt
      cost:     Number (4..31)                      num of iterations. e.g. 12 ==> 212 = 4,096 iterations
      salt:     array of Bytes (16 bytes)           random salt
      password: array of Bytes (1..72 bytes)        UTF-8 encoded password

      hash:     array of Bytes (24 bytes)           This will be a fixed length output
Enter fullscreen mode Exit fullscreen mode

As of 3.0.0 bcrypt now offers a kdf function which does bcrypt_pbkdf. This KDF is used in OpenSSH's newer encrypted private key format.

>>> import bcrypt
>>> key = bcrypt.kdf(
...     password=b'password',
...     salt=b'salt',
...     desired_key_bytes=32,
...     rounds=100)
Enter fullscreen mode Exit fullscreen mode

Adjustable Work Factor
One of bcrypt's features is an adjustable logarithmic work factor. To adjust the work factor merely pass the desired number of rounds to bcrypt.gensalt(rounds=12) which defaults to 12):

>>> import bcrypt
>>> password = b"super secret password"
>>> # Hash a password for the first time, with a certain number of rounds
>>> hashed = bcrypt.hashpw(password, bcrypt.gensalt(14))
>>> # Check that a unhashed password matches one that has previously been
>>> #   hashed
>>> if bcrypt.checkpw(password, hashed):
...     print("It Matches!")
... else:
...     print("It Does not Match :(")

Enter fullscreen mode Exit fullscreen mode

" (6)

Is BCrypt secure?

Though an attacker can know the plain-text, the cost, and the salt in the hash, Blowfish is modern Crypto system that is specifically designed to prevent 'known plain-text attacks' or 'rainbow table attacks'.
This means that any wannabe attacker can't derive the key from plain-text and it's corresponding ciphertext. Their only chance would be to try encrypting every possible password to obtain the same result or to brute force attack (try everything anyway), both of which are not "computationally feasible".

Computational Feasibility:

"Given a computational problem, contextual needs place certain constraints on what constitutes an acceptable solution and an acceptable computational cost." (8)

Take Aways...

As a developer, don't store passwords (or other sensitive data) if you don't need to and if you do need to store it, it is good practice for the data to be salted and hashed properly and not just stored in plain text.

As a user, it is the best practice to use different passwords at each site, use a password manager, use secure passwords, and/or just not sign up for so many sites that might not be secure which could expose your password or personal information.

Check out if your password if safe or its time to get a new one here.
Here is an example of one of my old passwords I used back in 2007 to about... ohhh about 2010. It has clearly gotten around, either by me or by other people that thought of it too. It is good to make secure passwords to avoid this and change passwords often to ensure they aren't out in the Internets for people to use.


Please Note that I am still learning and if something that I have stated is incorrect please let me know. I would love to learn more about what I may not understand fully.

Top comments (0)