Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bcrypt encryption different every time with same input

Tags:

go

Using golang.org/x/crypto/bcrypt and GORM (http://gorm.io/docs/) I'm trying to encrypt a password. The problem is that every encryption of it is different every time, so it can never match the one in the database.

var result []string

password := []byte(data.Password)
encryptedPassword, err := bcrypt.GenerateFromPassword(password, bcrypt.DefaultCost) // different every time

db.Where(&User{Username: strings.ToLower(data.Username)}).First(&user).Pluck("password", &result)
encryptionErr := bcrypt.CompareHashAndPassword(encryptedPassword, []byte(result[0]))

if encryptionErr == nil { // passwords match! }

I have confirmed that the input is the same every time and that the password given from the database is correct.

What am I doing wrong here?

like image 826
Jeffrey Anderson Avatar asked Aug 31 '18 18:08

Jeffrey Anderson


People also ask

Does bcrypt generate different hashes?

Bcrypt uses adaptive hash algorithm to store password which is a one-way hash of the password. BCrypt internally generates a random salt while encoding passwords and store that salt along with the encrypted password. Hence it is obvious to get different encoded results for the same string.

Does bcrypt hash the same password different?

Again, a new hash is created each time the function is run, regardless of the password being the same.

Why is bcrypt hash different every time?

A BCrypt hash includes salt and as a result this algorithm returns different hashes for the same input.

Is bcrypt hash always the same?

The hash itself is a series of letters and numbers that will always be the same length. For example, a 10 character input and a 40 character input might be stored as 16 character hashes. It's important to note that this process can lead to multiple strings generating identical hashes.


1 Answers

The problem is that every encryption of it is different every time, so it can never match the one in the database.

This is normal bcrypt behavior.

bcrypt returns a different hash each time because it incorporates a different random value into the hash. This is known as a "salt". It prevents people from attacking your hashed passwords with a "rainbow table", a pre-generated table mapping password hashes back to their passwords. The salt means that instead of there being one hash for a password, there's 2^16 of them. Too many to store.

The salt is stored as part of the hashed password. So bcrypt.CompareHashAndPassword(encryptedPassword, plainPassword) can encrypt plainPassword using the same salt as encryptedPassword and compare them.

See this answer for more information and Dustin Boswell's excellent Storing User Passwords Securely: hashing, salting, and Bcrypt.

What am I doing wrong here?

You're trying to compare the generated hashed password with the stored hashed password. At least I certainly hope it's the hashed password that's stored in the database.

What you want instead is to compare the stored hashed password with the plain password the user entered.

// Normally this comes from user input and is *never* stored
plainPassword := "supersekret"

// The encrypted password is stored in the database
db.Where(&User{Username: strings.ToLower(data.Username)}).First(&user).Pluck("password", &result)
encryptedPassword := []byte(result[0])

// Check if the stored encrypted password matches "supersekret"
encryptionErr := bcrypt.CompareHashAndPassword(encryptedPassword, plainPassword)
if encryptionErr == nil {
    fmt.Println("Greetings Professor Falken")
} else {
    fmt.Println(encryptionErr)
}
like image 82
Schwern Avatar answered Nov 05 '22 22:11

Schwern