bcrypt for Go: Complete Guide to Password Hashing
\n\nUser data security is one of the key tasks of modern web development. Storing passwords in plain text is unacceptable, and simple hashing via MD5 or SHA-1 has long been considered insecure due to vulnerability to brute-force attacks. The bcrypt library for Go provides a reliable and time-tested adaptive password hashing algorithm that is resistant to both dictionary attacks and rainbow table attacks.
\n\nThe bcrypt algorithm was developed in 1999 by Niels Provos and David Mazières based on the Blowfish cipher. Its key feature is adaptive complexity: you can increase the number of hashing iterations, making password brute-forcing increasingly expensive as computing power grows. In the Go ecosystem, the standard library golang.org/x/crypto/bcrypt is the official extension and is maintained by the Go development team.
In this article, we will thoroughly examine all aspects of working with bcrypt in Go: from installation and basic usage to advanced techniques and common mistakes. You will learn how to properly hash passwords, compare them with hashes, choose the optimal cost, and integrate bcrypt into real applications.
\n\nInstallation
\n\nThe bcrypt library for Go is not included in the standard library but is part of the official submodule x/crypto. Installation is done with a single command:
go get golang.org/x/crypto/bcrypt\n\nAfter executing this command, a dependency will appear in your go.mod, and you will be able to import the package into your code:
import "golang.org/x/crypto/bcrypt"\n\nMake sure you have Go version 1.13 or higher installed (1.21+ recommended). If you are using modules (which is the standard in 2024), the dependency will be pulled automatically.
\n\nQuick Start: Minimal Working Example
\n\nLet's start with the simplest example: hashing a password and verifying it. This is the foundation you will use in any project.
\n\npackage main\n\nimport (\n "fmt"\n "log"\n "golang.org/x/crypto/bcrypt"\n)\n\nfunc main() {\n // Original user password\n password := []byte("mySecretPassword123!")\n\n // Hash the password with default cost (10)\n hashedPassword, err := bcrypt.GenerateFromPassword(password, bcrypt.DefaultCost)\n if err != nil {\n log.Fatal(err)\n }\n\n fmt.Printf("Password hash: %s\\n", hashedPassword)\n\n // Verify the correct password\n err = bcrypt.CompareHashAndPassword(hashedPassword, password)\n if err != nil {\n fmt.Println("Password does not match!")\n } else {\n fmt.Println("✓ Password matches!")\n }\n\n // Verify an incorrect password\n wrongPassword := []byte("wrongPassword")\n err = bcrypt.CompareHashAndPassword(hashedPassword, wrongPassword)\n if err != nil {\n fmt.Println("✗ Password does not match (as expected)")\n }\n}\n\nThis code does three things: generates a hash, verifies the correct password, and ensures the incorrect password is rejected. Note: GenerateFromPassword automatically generates a random salt and embeds it into the hash, so you will get different hashes each time for the same password.
Main Methods and Functions
\n\nThe bcrypt package provides a small but very well-designed API. Let's look at all the main functions with examples.
1. GenerateFromPassword
\nSignature: func GenerateFromPassword(password []byte, cost int) ([]byte, error)
Description: The main function for hashing a password. It takes a password as a byte slice and a cost — a logarithmic indicator of the number of iterations