DEV Community

Rez Moss
Rez Moss

Posted on

Password Hashing and Key Derivation: Turning Secrets into Secure Gibberish, Go Crypto 8

Hey there, crypto champion! Ready to dive into the world of password hashing and key derivation? Think of these as your secret recipe for turning passwords and keys into secure, unreadable gibberish. Let's see how Go helps us whip up some cryptographic magic!

Password Hashing: Making Passwords Unreadable (Even to Us!)

First up, let's talk about password hashing. It's like putting passwords through a cryptographic blender - what comes out looks nothing like what went in, and that's exactly what we want!

Bcrypt: The Classic Password Smoothie

Bcrypt is like the classic smoothie of password hashing - tried, tested, and still delicious. Here's how to use it:

import (
    "fmt"
    "golang.org/x/crypto/bcrypt"
)

func main() {
    password := []byte("iLoveCrypto123")

    // Let's blend this password!
    hashedPassword, err := bcrypt.GenerateFromPassword(password, bcrypt.DefaultCost)
    if err != nil {
        panic("Our cryptographic blender broke!")
    }

    fmt.Printf("Our password smoothie: %x\n", hashedPassword)

    // Now, let's see if we can recognize our original password
    err = bcrypt.CompareHashAndPassword(hashedPassword, password)
    if err != nil {
        fmt.Println("Nope, that's not our password!")
    } else {
        fmt.Println("Yep, that's our password alright!")
    }
}
Enter fullscreen mode Exit fullscreen mode

Argon2: The Newer, Fancier Smoothie

Argon2 is like the newfangled smoothie with all the superfoods - it's designed to be extra resistant to modern password-cracking techniques. Here's how to use it:

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

func main() {
    password := []byte("iLoveCryptoEvenMore456")

    // First, let's add some salt to our smoothie
    salt := make([]byte, 16)
    if _, err := rand.Read(salt); err != nil {
        panic("Our salt shaker is empty!")
    }

    // Now, let's blend our password
    timeCost := uint32(1)
    memoryCost := uint32(64 * 1024)
    threads := uint8(4)
    keyLength := uint32(32)

    hash := argon2.IDKey(password, salt, timeCost, memoryCost, threads, keyLength)

    // Let's encode our smoothie and salt for storage
    encodedHash := base64.RawStdEncoding.EncodeToString(hash)
    encodedSalt := base64.RawStdEncoding.EncodeToString(salt)

    fmt.Printf("Our fancy password smoothie: %s\n", encodedHash)
    fmt.Printf("Our salt: %s\n", encodedSalt)

    // To verify, we'd need to decode the salt, reblend with the same recipe, and compare
}
Enter fullscreen mode Exit fullscreen mode

Key Derivation: Turning Passwords into Crypto Keys

Now, let's talk about key derivation. It's like turning a simple password into a complex key that can unlock our cryptographic treasures.

PBKDF2: The Classic Key Maker

PBKDF2 is like an old, reliable key-cutting machine. It takes your password and turns it into a shiny new key. Here's how:

import (
    "crypto/rand"
    "crypto/sha256"
    "encoding/base64"
    "fmt"
    "golang.org/x/crypto/pbkdf2"
)

func main() {
    password := []byte("OpenSesame123")

    // Let's add some randomness to our key-making process
    salt := make([]byte, 16)
    if _, err := rand.Read(salt); err != nil {
        panic("Our randomness generator broke!")
    }

    // Time to make our key
    iterations := 100000
    keyLength := 32
    key := pbkdf2.Key(password, salt, iterations, keyLength, sha256.New)

    // Let's encode our new key and salt
    encodedKey := base64.RawStdEncoding.EncodeToString(key)
    encodedSalt := base64.RawStdEncoding.EncodeToString(salt)

    fmt.Printf("Our shiny new key: %s\n", encodedKey)
    fmt.Printf("The salt we used: %s\n", encodedSalt)
}
Enter fullscreen mode Exit fullscreen mode

HKDF: The Key Factory

HKDF is like a magical key factory that can produce multiple keys from a single secret. It's perfect when you need several keys for different purposes. Here's how to use it:

import (
    "crypto/sha256"
    "encoding/base64"
    "fmt"
    "golang.org/x/crypto/hkdf"
    "io"
)

func main() {
    secret := []byte("MySuper
SecretValue")
    salt := []byte("SaltySalt")
    info := []byte("KeyForEncryption")

    // Let's start up our key factory
    keyFactory := hkdf.New(sha256.New, secret, salt, info)

    // Now, let's produce two 32-byte keys
    key1 := make([]byte, 32)
    key2 := make([]byte, 32)

    if _, err := io.ReadFull(keyFactory, key1); err != nil {
        panic("Our key factory had a malfunction!")
    }
    if _, err := io.ReadFull(keyFactory, key2); err != nil {
        panic("Our key factory is tired and can't make another key!")
    }

    // Let's encode our new keys
    encodedKey1 := base64.RawStdEncoding.EncodeToString(key1)
    encodedKey2 := base64.RawStdEncoding.EncodeToString(key2)

    fmt.Printf("Our first key: %s\n", encodedKey1)
    fmt.Printf("Our second key: %s\n", encodedKey2)
}
Enter fullscreen mode Exit fullscreen mode

The Golden Rules of Password Hashing and Key Derivation

Now that you're a master of turning secrets into secure gibberish, here are some golden rules to keep in mind:

  1. Use the right tool for the job: For passwords, use bcrypt or Argon2. For key derivation, use PBKDF2 or HKDF.

  2. Salt to taste: Always use a unique, random salt for each password or key. It's like adding a secret ingredient that makes each hash unique.

  3. Adjust your recipe: Choose appropriate work factors (iterations, memory cost) based on your security needs and hardware capabilities. It's like adjusting the cooking time and temperature.

  4. Keep your recipe secret: Securely generate and store your salts and other parameters. Don't let anyone peek at your secret ingredients!

  5. Never serve raw: Never store plain text passwords or encryption keys. Always serve them well-hashed or derived.

  6. Timing is everything: Use constant-time comparison functions when verifying passwords. It's like making sure you always take the same time to check a password, whether it's right or wrong.

  7. Keep up with the trends: Regularly review and update your chosen algorithms and parameters. Cryptography is like fashion - what's secure today might not be tomorrow!

What's Next?

Congratulations! You've just mastered the art of turning secrets into secure gibberish. These techniques are crucial for keeping passwords and keys safe in your applications.

Remember, in the world of cryptography, understanding these basics is crucial. It's like learning the fundamental recipes in cooking - once you've got these down, you can create all sorts of secure, delicious cryptographic dishes!

So, how about you try implementing a secure user authentication system using bcrypt? Or maybe create a file encryption tool using keys derived with HKDF? The world of secure password storage and key management is at your fingertips! Happy coding, crypto chef!

Top comments (0)