DEV Community

Cover image for ⚙️ Go Tools: Password Hashing with Argon2 Instead of bcrypt
Nikita Rykhlov
Nikita Rykhlov

Posted on

⚙️ Go Tools: Password Hashing with Argon2 Instead of bcrypt

Storing passwords securely is one of the most critical security tasks in modern applications. Many developers still rely on time-tested algorithms like bcrypt, but technology doesn't stand still. In this article, we'll explore Argon2 — a modern and secure password hashing algorithm that serves as an excellent alternative to bcrypt. We'll also look at how to implement it in Go (Golang).


Why Argon2?

A Quick Recap on bcrypt

bcrypt is a cryptographic algorithm specifically designed for password hashing. It resists brute-force attacks thanks to the use of "salt" and a tunable cost factor that increases computational complexity.

However, over time new threats have emerged — especially those involving specialized hardware such as GPUs and ASICs for password cracking. This is where bcrypt starts to fall short compared to more modern solutions.

What Is Argon2?

Argon2 is the winner of the Password Hashing Competition (PHC), a competition organized by the cryptographic community to find a new standard for secure password hashing. It was developed by a team of cryptographers from the University of Luxembourg: Alex Biryukov, Daniel Dinu, and Dmitry Khovratovich.

Argon2 was chosen for its resistance to various types of attacks, including:

  • Timing attacks
  • GPU/ASIC-based attacks
  • Memory-hard attacks

Argon2 offers three different modes:

  1. Argon2d — provides maximum protection against hardware attacks but is vulnerable to timing attacks.
  2. Argon2i — resistant to timing attacks but weaker against hardware-based attacks.
  3. Argon2id — a hybrid mode combining the best features of both.

For most practical purposes, Argon2id is recommended.


Why Argon2 Is Better Than bcrypt

Feature bcrypt Argon2
Protection against GPU attacks Weak Strong
Configurable memory usage No Yes
Parallelism support No Yes
Resistance to timing attacks Yes Yes

In short, Argon2 is a more flexible, modern, and secure solution.


Using Argon2 in Go

The package golang.org/x/crypto/argon2 provides a solid implementation of the Argon2 algorithm.

In this example, we'll use Argon2id (IDKey), which combines the strengths of Argon2i and Argon2d: it's resistant to side-channel attacks and protected against time-memory trade-off attacks.

Installation

go get golang.org/x/crypto/argon2
Enter fullscreen mode Exit fullscreen mode

Example Code

package main

import (
    "crypto/rand"
    "crypto/subtle"
    "fmt"
    "golang.org/x/crypto/argon2"
)

// Recommended RFC parameters for most applications
const (
    saltLength = 16       // length of salt in bytes
    keyLength  = 32       // length of derived key (e.g., for AES-256)
    time       = 1        // number of iterations
    memory     = 64 << 10 // memory cost in KiB (~64MB)
    threads    = 4        // number of parallel threads
)

func generateSalt(length int) ([]byte, error) {
    salt := make([]byte, length)
    _, err := rand.Read(salt)
    if err != nil {
        return nil, err
    }

    return salt, nil
}

func hashPassword(password string) ([]byte, []byte, error) {
    salt, err := generateSalt(saltLength)
    if err != nil {
        return nil, nil, err
    }

    hashed := argon2.IDKey([]byte(password), salt, time, memory, threads, keyLength)

    return hashed, salt, nil
}

func verifyPassword(password string, salt []byte, expectedHash []byte) bool {
    newHash := argon2.IDKey([]byte(password), salt, time, memory, threads, keyLength)

    return subtleCompare(newHash, expectedHash)
}

// Prevent timing attacks
func subtleCompare(a, b []byte) bool {
    return subtle.ConstantTimeCompare(a, b) == 1
}

func main() {
    password := "mySecureP@ssw0rd"

    // Step 1: Hash the password
    hashed, salt, err := hashPassword(password)
    if err != nil {
        panic(err)
    }

    fmt.Printf("Hashed password: %x\n", hashed)

    // Step 2: Verify correct password
    if verifyPassword(password, salt, hashed) {
        fmt.Println("✅ Password is valid")
    } else {
        fmt.Println("❌ Password is invalid")
    }

    // Step 3: Verify incorrect password
    if verifyPassword("wrongPass", salt, hashed) {
        fmt.Println("❌ Incorrect password was accepted!")
    } else {
        fmt.Println("✅ Verification rejected incorrect password")
    }
}
Enter fullscreen mode Exit fullscreen mode

🔐 Tip: Never use fixed salt values. Always generate a new random salt before each password hashing.

Recommended Parameters

Parameter Value Description
time 1 Number of passes through memory
memory 64 * 1024 Amount of memory used in KiB (~64 MB)
threads 4 Number of threads to use
keyLength 32 Length of the resulting key in bytes
saltLength 16 Random salt to prevent collisions

These values are suitable for most web applications. Adjust them based on your system's capabilities or specific requirements (e.g., mobile devices).


Conclusion

While bcrypt remains a solid choice, Argon2 offers superior protection against modern threats, particularly GPU and ASIC-based attacks. With its flexibility and efficient resource usage, it is becoming the de-facto standard for password hashing in new projects.

If you're developing in Go, integrating Argon2 is straightforward using existing libraries. Just remember to choose appropriate parameters for your application load and always store the salt and metadata correctly.


📎 Useful Links


📌 What do you think?

Have you already switched from bcrypt to Argon2 in your projects — or still sticking with the classic?

What password hashing strategy do you use in Go — and how do you manage security vs. performance?

👇 Share your thoughts and experience in the comments — I’d love to learn from you!

👍 If you enjoyed this article, don’t forget to like and share it — help others upgrade their password security the right way!


📣 Follow me and read my content on other platforms:

Check out this and other articles on my pages:

🔗 LinkedIn
📚 Medium
📘 Facebook
✈️ Telegram
🐦 X

Oh, almost forgot — my personal website.

🔔 Follow me not to miss new articles and guides on hot topics!

Top comments (0)