Documentation ¶
Overview ¶
Package argonize is a wrapper for the functions of the "golang.org/x/crypto/argon2" package to facilitate the use of the Argon2id password hashing algorithm.
* This package is strongly influenced by an article by Alex Edwards (https://www.alexedwards.net/).
- "How to Hash and Verify Passwords With Argon2 in Go"
- https://www.alexedwards.net/blog/how-to-hash-and-verify-passwords-with-argon2-in-go
Example ¶
// The password to be hashed. // Note that once hashed, passwords cannot be recovered and can only be // verified. password := []byte("my password") // Password hashing using the Argon2id algorithm. // The parameters use the settings recommended in the draft Argon2 RFC. // To customize the parameters, use the argonize.HashCustom() function. hashedObj, err := argonize.Hash(password) if err != nil { log.Fatal(err) } // Use the Hashed.String() function to obtain the hash to be stored in the // database as a string. // // hashed := hashedObj.String() // Validate the password against the hashed password. if hashedObj.IsValidPassword([]byte("my password")) { fmt.Println("the password is valid") } else { fmt.Println("the password is invalid") } if hashedObj.IsValidPassword([]byte("wrong password")) { fmt.Println("the password is valid") } else { fmt.Println("the password is invalid") }
Output: the password is valid the password is invalid
Example (Custom_params) ¶
password := []byte("my password") params := argonize.NewParams() fmt.Println("Default iterations:", params.Iterations) fmt.Println("Default key length:", params.KeyLength) fmt.Println("Default memory cost:", params.MemoryCost) fmt.Println("Default salt length:", params.SaltLength) fmt.Println("Default parallelism:", params.Parallelism) salt, err := argonize.NewSalt(params.SaltLength) if err != nil { log.Fatal(err) } salt.AddPepper([]byte("my pepper")) // Hash the password using the Argon2id algorithm with the custom parameters. hashedObj := argonize.HashCustom(password, salt, params) // Validate the password against the hashed password. if hashedObj.IsValidPassword([]byte("my password")) { fmt.Println("the password is valid") } else { fmt.Println("the password is invalid") } if hashedObj.IsValidPassword([]byte("wrong password")) { fmt.Println("the password is valid") } else { fmt.Println("the password is invalid") }
Output: Default iterations: 1 Default key length: 32 Default memory cost: 65536 Default salt length: 16 Default parallelism: 2 the password is valid the password is invalid
Example (From_saved_password) ¶
// Load the hashed password from a file, DB or etc. //nolint:gosec // hardcoded credentials as an example savedPasswd := "$argon2id$v=19$m=65536,t=1,p=2$iuIIXq4foOhcGUH1BjE08w$kA+XOAMls8hzWg3J1sYxkeuK/lkU4HDRBf0zchdyllY" // Decode the saved password to a Hashed object. // Note that once hashed, passwords cannot be recovered and can only be // verified. hashObj, err := argonize.DecodeHashStr(savedPasswd) if err != nil { log.Fatal(err) } // Validate the password against the hashed password. if hashObj.IsValidPassword([]byte("my password")) { fmt.Println("the password is valid") } else { fmt.Println("the password is invalid") } if hashObj.IsValidPassword([]byte("wrong password")) { fmt.Println("the password is valid") } else { fmt.Println("the password is invalid") }
Output: the password is valid the password is invalid
Example (Gob_encode_and_decode) ¶
exitOnError := func(err error) { if err != nil { log.Fatal(err) } } // The password to be hashed. password := []byte("my secret password") // Password hashing using the Argon2id algorithm with default parameters. hashedObj1, err := argonize.Hash(password) exitOnError(err) // Obtain the Hashed object as a gob encoded byte slice. Useful when hashes // are stored in the database in bytes. Also see the DecodeHashStr() example. gobEnc, err := hashedObj1.Gob() exitOnError(err) // Re-create the Hashed object from the gob encoded byte slice. Suppose the // gobEnc is the value stored in a database. hashedObj2, err := argonize.DecodeHashGob(gobEnc) exitOnError(err) // The recovered Hashed object works as a validator. if hashedObj2.IsValidPassword([]byte("my secret password")) { fmt.Println("the password is valid") } else { fmt.Println("the password is invalid") } if hashedObj2.IsValidPassword([]byte("my bad password")) { fmt.Println("the password is valid") } else { fmt.Println("the password is invalid") }
Output: the password is valid the password is invalid
Example (Static_output) ¶
Example_static_output demonstrates how to obtain a static output from the Argon2 algorithm for testing purposes.
Note that it is not recommended to use the static output as a password hash.
// Backup and defer restoring the random reader. oldRandRead := argonize.RandRead defer func() { argonize.RandRead = oldRandRead }() // Set/mock the random reader function as a static reader. // // Note that it is not recommended to use the static output as a password // hash. The static output is only useful for testing purposes. argonize.RandRead = func(b []byte) (int, error) { return copy(b, []byte("0123456789abcdef")), nil } pwd := "my very strong password" hashedObj, err := argonize.Hash([]byte(pwd)) if err != nil { log.Panic(err) } fmt.Println("String:", hashedObj.String()) fmt.Printf("Hashed: %x\n", hashedObj.Hash)
Output: String: $argon2id$v=19$m=65536,t=1,p=2$MDEyMzQ1Njc4OWFiY2RlZg$ytVHh/XAyQmzALFYvBRKET/7GswiVnDdubchuBeU/Yw Hashed: cad54787f5c0c909b300b158bc144a113ffb1acc225670ddb9b721b81794fd8c
Index ¶
Examples ¶
Constants ¶
const ( // IterationsDefault is the default number of iterations of the parameter used by the Argon2id algorithm. IterationsDefault = uint32(1) // KeyLengthDefault is the default key length used in the Argon2id algorithm parameters. KeyLengthDefault = uint32(32) // MemoryCostDefault is the default amount of memory (KiB) used by the algorithm parameters. MemoryCostDefault = uint32(64 * 1024) // ParallelismDefault is the default number of threads used in the algorithm parameters. ParallelismDefault = uint8(2) // SaltLengthDefault is the default length of the salt used in the Argon2id algorithm parameters. SaltLengthDefault = uint32(16) )
Variables ¶
var RandRead = rand.Read
RandRead is a copy of `crypto.rand.Read` to ease testing.
It is a helper function that calls Reader.Read using io.ReadFull. The returned `n` and `err` values, `n` will be len of the input if `err` is nil.
Functions ¶
func RandomBytes ¶
RandomBytes returns a random number of byte slice with the given length. It is a cryptographically secure random number generated from `crypto.rand` package.
If it is determined that a cryptographically secure number cannot be generated, an error is returned. Also note that if lenOut is zero, an empty byte slice is returned with no error.
Example ¶
// Generate 32 byte length random value. r1, err := argonize.RandomBytes(32) if err != nil { log.Fatal(err) } // Generate 32 byte length random value. r2, err := argonize.RandomBytes(32) if err != nil { log.Fatal(err) } // Require that the two random values are different. if bytes.Equal(r1, r2) { log.Fatal("random bytes are not random") } fmt.Println("OK")
Output: OK
Types ¶
type Hashed ¶
Hashed holds the Argon2id hash value and its parameters.
func DecodeHashGob ¶
DecodeHashGob decodes gob-encoded byte slice into a Hashed object. The argument should be the value from Hashed.Gob() method.
Note that the password remains hashed even if the object is decoded. Once hashed, the original password cannot be recovered in any case.
func DecodeHashStr ¶
DecodeHashStr decodes an Argon2id formatted hash string into a Hashed object. Which is the value returned by Hashed.String() method.
Note that the password remains hashed even if the object is decoded. Once hashed, the original password cannot be recovered in any case.
Example ¶
// The Argon2id hash string to be decoded. hashed := "$argon2id$v=19$m=65536,t=3,p=2$Woo1mErn1s7AHf96ewQ8Uw$D4TzIwGO4XD2buk96qAP+Ed2baMo/KbTRMqXX00wtsU" // Decode the standard encoded hash representation of the Argon2 algorithm // to a Hashed object. hashObj, err := argonize.DecodeHashStr(hashed) if err != nil { log.Fatal(err) } fmt.Printf("Hash: %x\n", hashObj.Hash) fmt.Printf("Salt: %x\n", hashObj.Salt) fmt.Println("Params:") fmt.Println("- Iterations:", hashObj.Params.Iterations) fmt.Println("- Key length:", hashObj.Params.KeyLength) fmt.Println("- Memory cost:", hashObj.Params.MemoryCost) fmt.Println("- Salt length:", hashObj.Params.SaltLength) fmt.Println("- Parallelism:", hashObj.Params.Parallelism) // Print the hashed string representation of the Argon2id algorithm. // It should return the same string as the one passed to the DecodeHashStr() // function. fmt.Println("Stringer:", hashObj.String())
Output: Hash: 0f84f323018ee170f66ee93deaa00ff847766da328fca6d344ca975f4d30b6c5 Salt: 5a8a35984ae7d6cec01dff7a7b043c53 Params: - Iterations: 3 - Key length: 32 - Memory cost: 65536 - Salt length: 16 - Parallelism: 2 Stringer: $argon2id$v=19$m=65536,t=3,p=2$Woo1mErn1s7AHf96ewQ8Uw$D4TzIwGO4XD2buk96qAP+Ed2baMo/KbTRMqXX00wtsU
func Hash ¶
Hash returns a Hashed object from the password using the Argon2id algorithm.
Note that this function, by its nature, consumes memory and CPU.
func HashCustom ¶
HashCustom returns a Hashed object from the password using the Argon2id algorithm.
Similar to the Hash() function, but allows you to specify the algorithm parameters.
func (*Hashed) Gob ¶
Gob returns the gob-encoded byte slice of the current Hashed object. This is useful when hashes are stored in the database in bytes.
func (*Hashed) IsValidPassword ¶
IsValidPassword returns true if the given password is valid.
Note that the parameters must be the same as those used to generate the hash.
type Params ¶
type Params struct { // Iterations is the number of iterations or passes over the memory. // Defaults to 1 which is the sensible number from the Argon2's draft RFC // recommends[2]. Iterations uint32 // KeyLength is the length of the key used in Argon2. // Defaults to 32. KeyLength uint32 // MemoryCost is the amount of memory used by the algorithm in KiB. // Defaults to 64 * 1024 KiB = 64 MiB. Which is the sensible number from // the Argon2's draft RFC recommends[2]. MemoryCost uint32 // SaltLength is the length of the salt used in Argon2. // Defaults to 16. SaltLength uint32 // Parallelism is the number of threads or lanes used by the algorithm. // Defaults to 2. Parallelism uint8 }
Params holds the parameters for the Argon2id algorithm.
func NewParams ¶
func NewParams() *Params
NewParams returns a new Params object with default values.
Example ¶
params := argonize.NewParams() fmt.Println("Default iterations:", params.Iterations) fmt.Println("Default key length:", params.KeyLength) fmt.Println("Default memory cost:", params.MemoryCost) fmt.Println("Default salt length:", params.SaltLength) fmt.Println("Default parallelism:", params.Parallelism)
Output: Default iterations: 1 Default key length: 32 Default memory cost: 65536 Default salt length: 16 Default parallelism: 2
func (*Params) SetDefault ¶
func (p *Params) SetDefault()
SetDefault sets the fields to default values.
type Salt ¶
type Salt []byte
Salt holds the salt value. You can add a pepper value to the salt through the AddPepper() method.
func (*Salt) AddPepper ¶
AddPepper add/appends a pepper value to the salt.
Example ¶
// Create 16 byte length random salt. salt, err := argonize.NewSalt(16) if err != nil { log.Fatal(err) } noPepper := salt[:] salt.AddPepper([]byte("pepper")) withPepper := salt[:] // Require peppered salt to be different from the original salt. if bytes.Equal(noPepper, withPepper) { log.Fatal("salt and salt+pepper values should be different") } fmt.Println("OK")
Output: OK
Directories ¶
Path | Synopsis |
---|---|
=============================================================================== This Go application takes a password and an optional salt as arguments and outputs the hashed password using the Argon2id algorithm.
|
=============================================================================== This Go application takes a password and an optional salt as arguments and outputs the hashed password using the Argon2id algorithm. |