Try it yourself with our free Password Generator tool — runs entirely in your browser, no signup needed.

How to Generate secure passwords in Go

How to Generate Secure Passwords in Go

Generating secure passwords is a crucial aspect of building secure applications. A secure password should be unique, unpredictable, and resistant to guessing or brute-force attacks. In this article, we will explore how to generate secure passwords in Go, a modern programming language that prioritizes security and performance.

Quick Example

Here is a minimal example of generating a secure password in Go:

package main

import (
    "crypto/rand"
    "fmt"
    "math/big"
    "strings"
)

func generatePassword(length int) (string, error) {
    const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()"
    bytes := make([]byte, length)
    for i := range bytes {
        n, err := rand.Int(rand.Reader, big.NewInt(int64(len(letters))))
        if err != nil {
            return "", err
        }
        bytes[i] = letters[n.Int64()]
    }
    return string(bytes), nil
}

func main() {
    password, err := generatePassword(12)
    if err != nil {
        fmt.Println(err)
    } else {
        fmt.Println(password)
    }
}

This code generates a 12-character password consisting of letters, numbers, and special characters.

Step-by-Step Breakdown

Let's walk through the code line by line:

  • package main: This is the main package declaration.
  • import statements: We import the necessary packages, including crypto/rand for generating random numbers and math/big for working with large integers.
  • func generatePassword(length int) (string, error): This function generates a password of the specified length and returns it as a string, along with any error that may occur.
  • const letters = "...": We define a constant string containing all the possible characters that can appear in the password.
  • bytes := make([]byte, length): We create a byte slice of the specified length to store the password.
  • for i := range bytes: We loop over the byte slice, generating a random character for each position.
  • n, err := rand.Int(rand.Reader, big.NewInt(int64(len(letters)))): We generate a random integer between 0 and the length of the letters string.
  • if err != nil: If an error occurs during random number generation, we return the error.
  • bytes[i] = letters[n.Int64()]: We assign the random character to the current position in the byte slice.
  • return string(bytes), nil: We return the generated password as a string, along with a nil error.

Handling Edge Cases

Here are some common edge cases to consider:

Empty/null input

If the input length is 0 or less, we should return an error:

if length <= 0 {
    return "", errors.New("length must be greater than 0")
}

Invalid input

If the input length is not an integer, we should return an error:

if length < 0 {
    return "", errors.New("length must be a non-negative integer")
}

Large input

If the input length is very large, we should consider using a more efficient algorithm or returning an error:

if length > 1024 {
    return "", errors.New("length is too large")
}

Unicode/special characters

To include Unicode characters in the password, we can modify the letters constant to include Unicode characters:

const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()[]{};:,.<>?/~`|\\-=+_*&^%$#@!~`"

Note that this may require additional dependencies or configuration to handle Unicode characters correctly.

Common Mistakes

Here are some common mistakes developers make when generating secure passwords in Go:

Mistake 1: Using a weak random number generator

// Wrong
rand.Seed(time.Now().UnixNano())
password := fmt.Sprintf("%d", rand.Intn(1000000))

// Correct
bytes := make([]byte, 12)
rand.Read(bytes)
password := string(bytes)

Mistake 2: Not handling errors

// Wrong
password, _ := generatePassword(12)

// Correct
password, err := generatePassword(12)
if err != nil {
    // Handle error
}

Mistake 3: Using a predictable password format

// Wrong
password := fmt.Sprintf("password%d", time.Now().UnixNano())

// Correct
password, err := generatePassword(12)
if err != nil {
    // Handle error
}

Performance Tips

Here are some performance tips for generating secure passwords in Go:

Tip 1: Use a cryptographically secure random number generator

The crypto/rand package provides a cryptographically secure random number generator that is suitable for generating secure passwords.

Tip 2: Use a efficient algorithm

The algorithm used in the generatePassword function is efficient and suitable for generating secure passwords. However, for very large input lengths, a more efficient algorithm may be necessary.

Tip 3: Avoid unnecessary allocations

The generatePassword function avoids unnecessary allocations by using a single byte slice to store the password.

FAQ

Q: What is the recommended password length?

A: The recommended password length is at least 12 characters.

Q: Can I use this code to generate passwords for users?

A: Yes, but you should consider additional security measures, such as salting and hashing, to protect user passwords.

Q: How can I customize the password format?

A: You can modify the letters constant to include or exclude specific characters.

Q: Is this code thread-safe?

A: Yes, the generatePassword function is thread-safe.

Q: Can I use this code in production?

A: Yes, but you should consider additional testing and validation to ensure the code meets your specific security requirements.

AI agent tools available. The CodeTidy MCP Server gives Claude, Cursor, and other AI agents access to 60+ developer tools. One command: npx @codetidy/mcp