passwap

package module
v0.0.0-...-70049d7 Latest Latest
Warning

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

Go to latest
Published: Mar 14, 2023 License: BSD-3-Clause Imports: 4 Imported by: 0

README

Passwap

Go Reference Go codecov

Package passwap provides a unified implementation between different password hashing algorithms. It allows for easy swapping between algorithms, using the same API for all of them.

Passwords hashed with passwap, using a certain algorithm and parameters can be stored in a database. If at a later moment paramers or even the algorithm is changed, passwap is still able to verify the "outdated" hashes and automatically return an updated hash when applicable. Only when an updated hash is returned, the record in the database needs to be updated.

Resulting password hashes are encoded using dollar sign ($) notation. It's origin lies in Glibc, but there is no clear standard on the matter For passwap it is choosen to follow suit with python's passlib identifiers to be (hopefully) as portable as possible. Suplemental information can be found:

Glibc: https://man.archlinux.org/man/crypt.5;

Passlib "Modular Crypt Format": https://passlib.readthedocs.io/en/stable/modular_crypt_format.html;

Password Hashing Competition string format: https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md;

Documentation

Overview

Package passwap provides a unified implementation between different password hashing algorithms. It allows for easy swapping between algorithms, using the same API for all of them.

Passwords hashed with passwap, using a certain algorithm and parameters can be stored in a database. If at a later moment paramers or even the algorithm is changed, passwap is still able to verify the "outdated" hashes and automatically return an updated hash when applicable. Only when an updated hash is returned, the record in the database needs to be updated.

Resulting password hashes are encoded using dollar sign ($) notation. It's origin lies in Glibc, but there is no clear standard on the matter For passwap it is choosen to follow suit with python's passlib identifiers to be (hopefully) as portable as possible. Suplemental information can be found:

Glibc: https://man.archlinux.org/man/crypt.5;

Passlib "Modular Crypt Format": https://passlib.readthedocs.io/en/stable/modular_crypt_format.html;

Password Hashing Competition string format: https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md;

Example
// Create a new swapper which hashes using bcrypt,
// verifies and upgrades scrypt.
passwords := NewSwapper(
	bcrypt.New(bcrypt.DefaultCost),
	scrypt.Verifier,
)

// Create an encoded bcrypt hash string of password with salt.
encoded, err := passwords.Hash("good_password")
if err != nil {
	panic(err)
}
fmt.Println(encoded)
// $2a$10$eS.mS5Zc5YAJFlImXCpLMu9TxXwKUhgQxsbghlvyVwvwYO/17E2qy

// Replace the swapper to hash using argon2id,
// verifies and upgrades scrypt and bcrypt.
passwords = NewSwapper(
	argon2.NewArgon2id(argon2.RecommendedIDParams),
	bcrypt.Verifier,
	scrypt.Verifier,
)

// Attempt to verify encoded bcrypt string with a wrong password.
// Returns an error and empty "updated"
if updated, err := passwords.Verify(encoded, "wrong_password"); err != nil {
	fmt.Println(err)
	// passwap: password does not match hash
} else if updated != "" {
	encoded = updated
}
fmt.Println(encoded)
// $2a$10$eS.mS5Zc5YAJFlImXCpLMu9TxXwKUhgQxsbghlvyVwvwYO/17E2qy
// encoded is unchanged.

// Verify encoded bcrypt string with a good password.
// Returns a new encoded string with argon2id hash
// of password and new random salt.
if updated, err := passwords.Verify(encoded, "good_password"); err != nil {
	panic(err)
} else if updated != "" {
	encoded = updated
}
fmt.Println(encoded)
// $argon2id$v=19$m=65536,t=1,p=4$d6SOdxdIip9BC7sM5H7PUQ$2E7OIz7C1NkMLOsXi5nSe5vfbthdc9N9SWVlArd200E
// encoded is updated.

// Verify encoded argon2 string with a good password.
// "updated" now is empty because the parameters of the Hasher
// match the one in the encoded string.
if updated, err := passwords.Verify(encoded, "good_password"); err != nil {
	panic(err)
} else if updated != "" { // updated is empty, nothing is stored
	encoded = updated
}
fmt.Println(encoded)
// $argon2id$v=19$m=65536,t=1,p=4$d6SOdxdIip9BC7sM5H7PUQ$2E7OIz7C1NkMLOsXi5nSe5vfbthdc9N9SWVlArd200E
// encoded in unchanged.

// Replace the swapper again. This time we still
// use argon2id, but increased the Time parameter.
passwords = NewSwapper(
	argon2.NewArgon2id(argon2.Params{
		Time:    2,
		Memory:  64 * 1024,
		Threads: 4,
		KeyLen:  32,
		SaltLen: 16,
	}),
	bcrypt.Verifier,
	scrypt.Verifier,
)

// Verify encoded argon2id string with a good password.
// Returns a new encoded string with argon2id hash
// of password and new random salt,
// because of paremeter mis-match.
if updated, err := passwords.Verify(encoded, "good_password"); err != nil {
	panic(err)
} else if updated != "" {
	encoded = updated
}
fmt.Println(encoded)
// $argon2id$v=19$m=65536,t=2,p=4$44X+dwU+aSS85Kl1qH3/Jg$n/tQoAtx/I/Rt9BXHH9tScshWucltPPmB0HBLVtXCq0
// encoded is updated.
Output:

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	ErrPasswordMismatch = errors.New("passwap: password does not match hash")
	ErrNoVerifier       = errors.New("passwap: no verifier found for encoded string")
)

Functions

This section is empty.

Types

type Hasher

type Hasher interface {
	verifier.Verifier
	Hash(password string) (encoded string, err error)
}

Hasher is capable of creating new hashes of passwords, and verify passwords against existing hashes created by itself.

type SkipErrors

type SkipErrors []error

SkipErrors is only returned when multiple Verifiers matched an encoding string, but encountered an error decoding it.

func (SkipErrors) Error

func (e SkipErrors) Error() string

type Swapper

type Swapper struct {
	// contains filtered or unexported fields
}

Swapper is capable of creating new hashes of passwords and verify passwords against existing hashes for which it has verifiers configured. Swapper also updates hashes that are not created by the main hasher or use outdated cost parameters.

func NewSwapper

func NewSwapper(h Hasher, verifiers ...verifier.Verifier) *Swapper

NewSwapper with Hasher used for creating new hashes and primary verifier. Suplemental verifiers can be provided and will be used as fallback.

func (*Swapper) Hash

func (s *Swapper) Hash(password string) (encoded string, err error)

Hash returns a new encoded password hash using the configured Hasher.

func (*Swapper) Verify

func (s *Swapper) Verify(encoded, password string) (updated string, err error)

Verify a password against an existing encoded hash, using the configured Hasher or one of the Verifiers.

ErrNoVerifier is returned if no matching Verifier is found for the encoded string. ErrPasswordMismatch when the password hash doesn't match the encoded hash. When multiple Verifiers match and encounter an error during decoding, a SkipErrors is returned containing all those errors is returned.

If the used Verifier is different from the the current Hasher or the cost parameters differ, an updated encoded hash string is returned for the same (valid) password. In all other cases updated remains empty. When updated is not empty, it must be stored untill next use.

Directories

Path Synopsis
Package argon2 provides salt generation, hashing and verification for x/crypto/argon2.
Package argon2 provides salt generation, hashing and verification for x/crypto/argon2.
internal
salt
Package salt provides utilities for generating salts.
Package salt provides utilities for generating salts.
Package md5 provides hashing and verification or md5Crypt encoded passwords.
Package md5 provides hashing and verification or md5Crypt encoded passwords.
Package scrypt provides salt generation, hashing and verification for x/crypto/scrypt.
Package scrypt provides salt generation, hashing and verification for x/crypto/scrypt.
Package verifier provides types and interfaces for building verifiers, used by passwap.
Package verifier provides types and interfaces for building verifiers, used by passwap.

Jump to

Keyboard shortcuts

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