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.
In Ruby specifically, "the bcrypt Ruby gem provides a simple wrapper for safely handling passwords." (2)
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)
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|
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.
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|
|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|
|WPA/WPA2 PMK 14|
|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)))|
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 Input: 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 Output: hash: array of Bytes (24 bytes) This will be a fixed length output
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)
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 :(")
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".
"Given a computational problem, contextual needs place certain constraints on what constitutes an acceptable solution and an acceptable computational cost." (8)
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.