passforge

package module
v1.1.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 3, 2026 License: MIT Imports: 12 Imported by: 0

README

PassForge

PassForge is a Go library for secure password encoding and verification. It provides a collection of password encoders implementing various hashing algorithms with a consistent interface.

Features

  • Multiple password encoding algorithms:
    • BCrypt: Industry-standard adaptive hashing function
    • SCrypt: Memory-hard password hashing function
    • Argon2: Winner of the Password Hashing Competition, considered the most secure option
    • PBKDF2: Password-Based Key Derivation Function 2, widely used for password hashing
    • NoOp: No-operation encoder for testing (not for production use)
  • Delegating encoder: Allows using multiple encoders with automatic algorithm detection
  • Configurable parameters for each algorithm
  • Simple, consistent API across all encoders

Installation

go get github.com/nduyhai/passforge

Usage

Basic Usage
package main

import (
    "fmt"
    "github.com/nduyhai/passforge" 
)

func main() {
    // Create a BCrypt encoder with default cost
    encoder := passforge.NewBcryptPasswordEncoder()

    // Encode a password
    encoded, err := encoder.Encode("mySecurePassword")
    if err != nil {
        panic(err)
    }
    fmt.Println("Encoded password:", encoded)

    // Verify a password
    match, err := encoder.Verify("mySecurePassword", encoded)
    if err != nil {
        panic(err)
    }

    if match {
        fmt.Println("Password matches!")
    } else {
        fmt.Println("Password does not match!")
    }
}
Using Different Encoders
BCrypt Encoder
// Example: Create a BCrypt encoder with custom cost (higher is more secure but slower)
bcryptEncoder := passforge.NewBcryptPasswordEncoder(passforge.WithCost(12))
SCrypt Encoder
// Example: Create an SCrypt encoder with custom parameters
// Parameters: N (CPU/memory cost), r (block size), p (parallelization), keyLen, saltLen
scryptEncoder := passforge.NewScryptPasswordEncoder(
	passforge.WithScryptN(16384),
	passforge.WithScryptR(8), 
	passforge.WithScryptP(1), 
	passforge.WithScryptKeyLen(32), 
	passforge.WithScryptSaltLen(16))

// Or use default parameters
scryptEncoder := passforge.NewScryptPasswordEncoder()
Argon2 Encoder
// Example: Create an Argon2 encoder with custom parameters
// Parameters: time, memory, threads, keyLen, saltLen
argon2Encoder := passforge.NewArgon2PasswordEncoder(
	passforge.WithArgon2Time(1), 
	passforge.WithArgon2Memory(64*1024),
	passforge.WithArgon2Threads(4), 
	passforge.WithArgon2KeyLen(32), 
	passforge.WithArgon2SaltLen(16))

// Or use default parameters
argon2Encoder := passforge.NewArgon2PasswordEncoder()
PBKDF2 Encoder
// Example: Create a PBKDF2 encoder with custom parameters
// Parameters: iterations, keyLen, saltLen, hashFunc
import "crypto/sha256"
pbkdf2Encoder := passforge.NewPBKDF2PasswordEncoder(
	passforge.WithPBKDF2Iterations(1000), 
	passforge.WithPBKDF2KeyLen(32), 
	passforge.WithPBKDF2SaltLen(16), 
	passforge.WithPBKDF2HashFunc(sha256.New, "sha256"))

// Or use default parameters (SHA-256 hash function is used by default)
pbkdf2Encoder := passforge.NewPBKDF2PasswordEncoder()
NoOp Encoder (for testing only)
// Example: Create a NoOp encoder (stores passwords in plain text - DO NOT USE IN PRODUCTION)
noopEncoder := passforge.NewNoOpPasswordEncoder()
Delegating Password Encoder

The delegating encoder allows you to use multiple encoders and automatically detect which one to use for verification:

// Example: Using the delegating password encoder

// First, create individual encoders
bcryptEncoder := passforge.NewBcryptPasswordEncoder()
argon2Encoder := passforge.NewArgon2PasswordEncoder()
pbkdf2Encoder := passforge.NewPBKDF2PasswordEncoder()

// Create a list of encoders with their IDs. This supports backward compatibility with existing passwords.
encoders := []passforge.PasswordEncoder{
    bcryptEncoder,
    rgon2Encoder,
    pbkdf2Encoder,
}

// Create a delegating encoder with bcrypt as the default
delegatingEncoder := passforge.NewDelegatingPasswordEncoder(bcryptEncoder.Name(), encoders...)

// Encode a password (will use the default encoder - bcrypt in this case)
encoded, _ := delegatingEncoder.Encode("myPassword")
// Result will be something like: {bcrypt}$2a$10$...

// Verify a password (will automatically detect the encoder from the prefix)
match, _ := delegatingEncoder.Verify("myPassword", encoded)

// You can also verify passwords encoded with any of the configured encoders
argon2Password := "{argon2}time=1,memory=65536,threads=4,keyLen=32$KwuPJjEdIoq1nSZWGsrO6w==$5OqqfWw4e/s2UJpnvFOerxMynrBV9OGDRrGsu60RS+I="
pbkdf2Password := "{pbkdf2}iterations=10000,keyLen=32,hashFunc=sha256$+uTgq1Ll15T2MloP8UJdyQ==$G+nDsgsyWuVoQrAy8DNJXXKVTWGr9P1gmM/YNxQxyEE="
match, _ = delegatingEncoder.Verify("myPassword", argon2Password)
match, _ = delegatingEncoder.Verify("myPassword", pbkdf2Password)

Development

Prerequisites
  • Go 1.25 or higher
Available Make Commands

The project includes a Makefile with the following commands:

# Build the project
make build

# Run tests
make test

# Run tests with coverage
make test-coverage

# Clean build artifacts
make clean

# Install dependencies
make deps

# Run linter
make lint

# Format code
make fmt

# Verify dependencies
make verify

# Show help
make help
Continuous Integration

This project uses GitHub Actions for continuous integration. The workflow includes:

  • Running tests on multiple Go versions

The configuration files are:

  • .github/workflows/ci.yml: GitHub Actions workflow configuration
  • .golangci.yml: golangci-lint configuration

License

This project is licensed under the MIT License - see the LICENSE file for details.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrInvalidFormat = errors.New("invalid format")

ErrInvalidFormat is returned when the encoded password format is invalid

View Source
var ErrUnknownEncoding = errors.New("unknown encoding")

ErrUnknownEncoding is returned when the encoding ID is not recognized

Functions

This section is empty.

Types

type Argon2Option added in v1.0.0

type Argon2Option func(*Argon2PasswordEncoder)

Argon2Option is a function that configures an Argon2PasswordEncoder

func WithArgon2KeyLen added in v1.0.0

func WithArgon2KeyLen(keyLen uint32) Argon2Option

WithArgon2KeyLen sets the length of the derived key Recommended minimum: 16 Recommended maximum: 2^32-1 Default: 32 See https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.md#parameters Note: The length of the derived key is expressed in bytes, not bits.

This is because the length of the derived key is expressed in bytes, not bits.
For example, 1024 = 1024 bytes = 1024 bits.

func WithArgon2Memory added in v1.0.0

func WithArgon2Memory(memory uint32) Argon2Option

WithArgon2Memory sets the memory usage in KiB Recommended minimum: 8 Recommended maximum: 2^32-1 Default: 64MB See https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.md#parameters Note: The memory usage is expressed in KiB, not MiB.

This is because the memory usage is expressed in bytes, not kilobytes.
For example, 1024 * 1024 = 1048576 bytes = 1 MiB.

func WithArgon2SaltLen added in v1.0.0

func WithArgon2SaltLen(saltLen uint32) Argon2Option

WithArgon2SaltLen sets the length of the salt Recommended minimum: 16 Recommended maximum: 2^32-1 Default: 16 See https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.md#parameters Note: The length of the salt is expressed in bytes, not bits.

This is because the length of the salt is expressed in bytes, not bits.
For example, 1024 = 1024 bytes = 1024 bits.

func WithArgon2Threads added in v1.0.0

func WithArgon2Threads(threads uint8) Argon2Option

WithArgon2Threads sets the number of threads Recommended minimum: 1 Recommended maximum: 255 Default: 4 See https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.md#parameters Note: The number of threads is expressed as a byte, not a number.

This is because the number of threads is expressed as a power of two.
For example, 2^4 = 16 threads.

func WithArgon2Time added in v1.0.0

func WithArgon2Time(time uint32) Argon2Option

WithArgon2Time sets the number of iterations Recommended minimum: 1 Recommended maximum: 2^32-1 Default: 1 See https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.md#parameters

type Argon2PasswordEncoder

type Argon2PasswordEncoder struct {
	Time    uint32 // Number of iterations
	Memory  uint32 // Memory usage in KiB
	Threads uint8  // Number of threads
	KeyLen  uint32 // Length of the derived key
	SaltLen uint32 // Length of the salt
}

Argon2PasswordEncoder is a password encoder that uses the Argon2id algorithm

func NewArgon2PasswordEncoder

func NewArgon2PasswordEncoder(opts ...Argon2Option) *Argon2PasswordEncoder

NewArgon2PasswordEncoder creates a new Argon2PasswordEncoder with default parameters if not specified

func (*Argon2PasswordEncoder) Encode

func (a *Argon2PasswordEncoder) Encode(rawPassword string) (string, error)

Encode hashes the raw password using Argon2id

func (*Argon2PasswordEncoder) Name added in v1.1.0

func (a *Argon2PasswordEncoder) Name() string

Name returns the name of the encoder.

func (*Argon2PasswordEncoder) Verify

func (a *Argon2PasswordEncoder) Verify(rawPassword, encodedPassword string) (bool, error)

Verify checks if the raw password matches the encoded password

type BcryptOption added in v1.0.0

type BcryptOption func(*BcryptPasswordEncoder)

BcryptOption is a function that configures a BcryptPasswordEncoder. See https://pkg.go.dev/golang.org/x/crypto/bcrypt#GenerateFromPassword for the list of available options.

The default cost is 10.
The minimum cost is 4.
The maximum cost is 31.
The recommended cost is 12.
The recommended cost is 14.

func WithCost added in v1.0.0

func WithCost(cost int) BcryptOption

WithCost sets the cost of the bcrypt algorithm. Recommended minimum: 4 Recommended maximum: 31 Default: 10 See https://pkg.go.dev/golang.org/x/crypto/bcrypt#GenerateFromPassword for the list of available options.

The default cost is 10.
The minimum cost is 4.

type BcryptPasswordEncoder

type BcryptPasswordEncoder struct {
	Cost int
}

BcryptPasswordEncoder is a password encoder that uses the bcrypt algorithm

func NewBcryptPasswordEncoder

func NewBcryptPasswordEncoder(opts ...BcryptOption) *BcryptPasswordEncoder

NewBcryptPasswordEncoder creates a new BcryptPasswordEncoder with default parameters if not specified.

func (*BcryptPasswordEncoder) Encode

func (b *BcryptPasswordEncoder) Encode(rawPassword string) (string, error)

Encode hashes the raw password using bcrypt.

func (*BcryptPasswordEncoder) Name added in v1.1.0

func (b *BcryptPasswordEncoder) Name() string

Name returns the name of the encoder.

func (*BcryptPasswordEncoder) Verify

func (b *BcryptPasswordEncoder) Verify(rawPassword, encodedPassword string) (bool, error)

Verify checks if the raw password matches the encoded password.

type DelegatingPasswordEncoder

type DelegatingPasswordEncoder struct {
	DefaultEncoder   PasswordEncoder
	DefaultEncoderID string
	Encoders         map[string]PasswordEncoder // e.g., "bcrypt" => bcrypt encoder
}

DelegatingPasswordEncoder delegates encoding to a default encoder and a map of encoders

func NewDelegatingPasswordEncoder

func NewDelegatingPasswordEncoder(defaultEncoderID string, encoders ...PasswordEncoder) (*DelegatingPasswordEncoder, error)

NewDelegatingPasswordEncoder creates a DelegatingPasswordEncoder with a default encoder and additional encoders. Additional encoders support backward compatibility with existing passwords.

func (*DelegatingPasswordEncoder) Encode

func (d *DelegatingPasswordEncoder) Encode(rawPassword string) (string, error)

Encode encodes the given raw password using the default encoder and prefixes it with the default encoder's ID.

func (*DelegatingPasswordEncoder) Verify

func (d *DelegatingPasswordEncoder) Verify(rawPassword, encodedPassword string) (bool, error)

Verify checks if the provided raw password matches the encoded password using the appropriate encoder. It identifies the encoder by extracting the prefix from the encoded password. Returns a boolean indicating a match and an error if verification fails or the encoding is unknown.

type NoOpPasswordEncoder

type NoOpPasswordEncoder struct{}

NoOpPasswordEncoder is a password encoder that does not perform any encoding It's useful for testing and development purposes only and should not be used in production

func NewNoOpPasswordEncoder

func NewNoOpPasswordEncoder() *NoOpPasswordEncoder

NewNoOpPasswordEncoder creates a new NoOpPasswordEncoder

func (*NoOpPasswordEncoder) Encode

func (n *NoOpPasswordEncoder) Encode(rawPassword string) (string, error)

Encode returns the raw password as-is without any encoding

func (*NoOpPasswordEncoder) Name added in v1.1.0

func (n *NoOpPasswordEncoder) Name() string

Name returns the name of the encoder.

func (*NoOpPasswordEncoder) Verify

func (n *NoOpPasswordEncoder) Verify(rawPassword, encodedPassword string) (bool, error)

Verify checks if the raw password matches the encoded password Since NoOpPasswordEncoder doesn't perform any encoding, it just compares the strings directly

type PBKDF2Option added in v1.0.0

type PBKDF2Option func(*PBKDF2PasswordEncoder)

PBKDF2Option is a functional option used to configure a PBKDF2PasswordEncoder instance.

func WithPBKDF2HashFunc added in v1.0.0

func WithPBKDF2HashFunc(hashFunc func() hash.Hash, hashFuncName string) PBKDF2Option

WithPBKDF2HashFunc sets the hash function to use Recommended minimum: 10000 Default: sha256.New See https://en.wikipedia.org/wiki/PBKDF2#Parameters

The hash function is used to derive the key from the password and the salt.
The hash function must be deterministic, i.e., the same input should always produce the same output.
The hash function must be cryptographically secure, i.e., it must be impossible to reverse the hash function.

func WithPBKDF2Iterations added in v1.0.0

func WithPBKDF2Iterations(iterations int) PBKDF2Option

WithPBKDF2Iterations sets the number of iterations Recommended minimum: 10000 Default: 10000 See https://en.wikipedia.org/wiki/PBKDF2#Parameters

func WithPBKDF2KeyLen added in v1.0.0

func WithPBKDF2KeyLen(keyLen int) PBKDF2Option

WithPBKDF2KeyLen sets the length of the derived key Recommended minimum: 16 Recommended maximum: 256 Default: 32 See https://en.wikipedia.org/wiki/PBKDF2#Parameters

The length of the derived key is expressed in bytes, not bits.
For example, 1024 = 1024 bytes = 1024 bits.

func WithPBKDF2SaltLen added in v1.0.0

func WithPBKDF2SaltLen(saltLen int) PBKDF2Option

WithPBKDF2SaltLen sets the length of the salt Recommended minimum: 16 Recommended maximum: 256 Default: 16 See https://en.wikipedia.org/wiki/PBKDF2#Parameters

The length of the salt is expressed in bytes, not bits.
For example, 1024 = 1024 bytes = 1024 bits.

type PBKDF2PasswordEncoder

type PBKDF2PasswordEncoder struct {
	Iterations   int              // Number of iterations
	KeyLen       int              // Length of the derived key
	SaltLen      int              // Length of the salt
	HashFunc     func() hash.Hash // Hash function to use (e.g., sha256.New)
	HashFuncName string           // Name of the hash function (e.g., "sha256")
}

PBKDF2PasswordEncoder is a password encoder that uses the PBKDF2 algorithm

func NewPBKDF2PasswordEncoder

func NewPBKDF2PasswordEncoder(opts ...PBKDF2Option) *PBKDF2PasswordEncoder

NewPBKDF2PasswordEncoder creates a new PBKDF2PasswordEncoder with default parameters if not specified

func (*PBKDF2PasswordEncoder) Encode

func (p *PBKDF2PasswordEncoder) Encode(rawPassword string) (string, error)

Encode hashes the raw password using PBKDF2

func (*PBKDF2PasswordEncoder) Name added in v1.1.0

func (p *PBKDF2PasswordEncoder) Name() string

Name returns the name of the encoder.

func (*PBKDF2PasswordEncoder) Verify

func (p *PBKDF2PasswordEncoder) Verify(rawPassword, encodedPassword string) (bool, error)

Verify checks if the raw password matches the encoded password

type PasswordEncoder

type PasswordEncoder interface {
	// Encode returns the encoded password
	Encode(rawPassword string) (string, error)

	// Verify returns true if the raw password matches the encoded password
	Verify(rawPassword, encodedPassword string) (bool, error)

	// Name returns the name of the encoder.
	Name() string
}

PasswordEncoder is an interface for password encoding and verification

type ScryptOption added in v1.0.0

type ScryptOption func(*ScryptPasswordEncoder)

ScryptOption is a functional option used to configure a ScryptPasswordEncoder instance.

func WithScryptKeyLen added in v1.0.0

func WithScryptKeyLen(keyLen int) ScryptOption

WithScryptKeyLen sets the length of the derived key Recommended minimum: 16 Recommended maximum: 2^32-1 Default: 32 See https://en.wikipedia.org/wiki/Scrypt#Parameters

The length of the derived key is the length of the derived key in bytes.
The length of the derived key is the length of the derived key in bytes.

func WithScryptN added in v1.0.0

func WithScryptN(n int) ScryptOption

WithScryptN sets the CPU/memory cost parameter (logN) Recommended minimum: 10 Recommended maximum: 31 Default: 16384 See https://en.wikipedia.org/wiki/Scrypt#Parameters

The CPU/memory cost parameter (logN) is the logarithm of the memory cost (in MiB) and the CPU cost (in ms).
The memory cost (in MiB) is the memory usage of the scrypt function, measured in MiB.

func WithScryptP added in v1.0.0

func WithScryptP(p int) ScryptOption

WithScryptP sets the parallelization parameter Recommended minimum: 1 Recommended maximum: 255 Default: 1 See https://en.wikipedia.org/wiki/Scrypt#Parameters

The parallelization parameter (p) is the number of threads used by the scrypt function.
The parallelization parameter is the number of threads used by the scrypt function.

func WithScryptR added in v1.0.0

func WithScryptR(r int) ScryptOption

WithScryptR sets the block size parameter Recommended minimum: 1 Recommended maximum: 255 Default: 8 See https://en.wikipedia.org/wiki/Scrypt#Parameters

The block size parameter (r) is the block size of the scrypt function, measured in bytes.
The block size is the number of bytes processed by the scrypt function at a time.

func WithScryptSaltLen added in v1.0.0

func WithScryptSaltLen(saltLen int) ScryptOption

WithScryptSaltLen sets the length of the salt Recommended minimum: 16 Recommended maximum: 2^32-1 Default: 16 See https://en.wikipedia.org/wiki/Scrypt#Parameters

The length of the salt is the length of the salt in bytes.
The length of the salt is the length of the salt in bytes.

type ScryptPasswordEncoder

type ScryptPasswordEncoder struct {
	N       int // CPU/memory cost parameter (logN)
	R       int // Block size parameter
	P       int // Parallelization parameter
	KeyLen  int // Length of the derived key
	SaltLen int // Length of the salt
}

ScryptPasswordEncoder is a password encoder that uses the scrypt algorithm

func NewScryptPasswordEncoder

func NewScryptPasswordEncoder(opts ...ScryptOption) *ScryptPasswordEncoder

NewScryptPasswordEncoder creates a new ScryptPasswordEncoder with default parameters if not specified

func (*ScryptPasswordEncoder) Encode

func (s *ScryptPasswordEncoder) Encode(rawPassword string) (string, error)

Encode hashes the raw password using scrypt

func (*ScryptPasswordEncoder) Name added in v1.1.0

func (s *ScryptPasswordEncoder) Name() string

Name returns the name of the encoder.

func (*ScryptPasswordEncoder) Verify

func (s *ScryptPasswordEncoder) Verify(rawPassword, encodedPassword string) (bool, error)

Verify checks if the raw password matches the encoded password

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL