gopherbounce

package module
v0.0.0-...-4c02cbf Latest Latest
Warning

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

Go to latest
Published: Mar 7, 2020 License: Apache-2.0 Imports: 18 Imported by: 0

README

The gopherbounce project

This package is but a small part of the gopherbounce project. This package implements only a very small part of the capabilities. For the documentation on how to use the gopherbounce project please refer to the wiki.

gopherbounce

gopherbounce is a Golang authentication framework. It bundles bcrypt, scrypt and argon2 (argon2i and argon2id) under a common interface. It provides easy to use functions for hashing and validating passwords. Find the full code documentation on GoDoc.

DO NOT USE THIS LIBRARY YET, IT IS STILL UNDER DEVELOPMENT

Installation

The easiest way: go get -u github.com/FabianWe/gopherbounce.

Quickstart

The following example demonstrates how to use this library in the most easy way. It first creates the password hash of the clear text password and then compares it with another clear text password. Just create the string variables password and testPassword. A runnable example can be found in quick.go

hashed, hashErr := gopherbounce.Generate(gopherbounce.DefaultHasher, password)
if hashErr != nil {
  panic(hashErr)
}
fmt.Println("Hashed password:", string(hashed))
validator := gopherbounce.GuessValidatorFunc(hashed)
okay := validator(testPassword)
if okay == nil {
  fmt.Println("Password correct")
} else {
  fmt.Println("Password wrong")
}

A more elaborate example exists in play.go

NOTE: Password hashing is a security sensitive part of your program! Be sure to read the foll doc!

Using different hash / key functions

There are three algorithms implemented. Each algorithm implements the Hasher interface. Implemented algorithms currently include bcrypt, scrypt and argon2 (argon2i and argon2id). Each of them has an implementation wrapping it, for example ScryptHasher. These hashers can be created with an algorithm specific config (NewScryptHasher with a ScryptConf). The New functions usually accept nil and create some sane defaults. Change those values only if you know what you're doing! For example: ScryptHasher by default creates keys and salts of length 64. If you want a length of 32 you can do:

hasher := gopherbounce.NewScryptHasher(nil)
hasher.KeyLen = 32

For all parameters check the code documentation on GoDoc. A list of default parameters can be found below. There are instances of all Hashers with sane default parameters: gopherbounce.Bcrypt, gopherbounce.Scrypt, gopherbounce.Argon2i and gopherbounce.Argon2id. You can use these hashers without creating new Hasher instances by yourself. There is also a gopherbounce.DefaultHasher which can be used if you have no idea which algorithm you should use. The current default hasher is argon2id. Argon2 is the winner of the Password Hashing Competition in July 2015. You should never change the parameters of these default hashers, that could be confusing. Instead use their Copy functions or create new ones with nil as the conf parameter as shown above.

Note on using hashers

Instead of calling yourHasher.Generate(password) you should instead use gopherbounce.Generate(yourHasher, password). This function recovers from all panics. Of course hashers should not panic, but return errors instead. But because password hashing is crucial I think it's best to wrap all hasher calls. This same is true for validators (below) whose calls should always be wrapped by a call to gopherbounce.Compare.

Hasher parsing

Instead of creating your hasher in your source code you can also load a config file. The syntax is explained in more detail in the Constraints section below. A config file looks like this:

[argon2id]
time = 3
KeyLen = 32

A list of the algorithm parameters can be found in the Parameters section. This will parse an argon2id hasher with time set to 3 and keylen set to 32. All other parameters of the algorithm are set to their default values. But usually you would define them all in a config file.

You can parse configs with ParseHasher or ParseHasherConfFile.

Your current hasher settings can be written to such a config file with WriteHasherConf.

Which hash function should I use?

bcrypt, scrypt and argon2id should all be fine. bcrypt is very often used and should be fine. Argon2id is the winner of the Password Hashing Competition in July 2015. So it's not very old and not in use for a long time (like bcrypt), thus has received less scrutiny. argon2id is the default in this package though, I like how argon2id scales even for further hardware improvements. So in short: bcrypt is fine and often used and thus battle-tested. argon2id seems very good and scales nicely. scrypt should be fine as well, argon2i should not be used, in constrast to argon2id. argon2id has the big advantage that it scales nicely (with both time and memory).

Validating hashes

The easiest way to validate hashes is to use GuessValidatorFunc or GuessValidator. They both accept the hashed version of a password and return either a function that can compare passwords with the hashed entry or a Validator object. See the documentation for more details.

NOTE: You should not use a validator (like from GuessValidator) directly. Instead of calling yourValidator.Compare(hashed, password) you should wrap your calls with gopherbounce.Compare(yourValidator, hashed, password). The reason is the same as for wrapping your hasher calls: The wrapper recovers from any unexpected panics.

GuessValidatorFunc always wraps the validator function with something similar: SecureValidatorFunc. So there's no need to wrap a function retrieved from GuessValidatorFunc.

Parsing hashes

The password hashes are encoded in a single string and there are functions to parse these hash strings. For example scrypt may produce the following string: $scrypt$ln=17,r=8,p=1$iDXJYV9jfWJVxmT7WxJvQ36G+gstxkYaapud/VfyZNs$Fknczp5AEqM6AwehE6D6VtV2lk/6gUNHM311ICEMkrE. This contains all parameters as well as the key and salt (encoded with base64). This string can be parsed with ParseScryptData. Similar functions exist for other hashers as well. This is exactly what is done by the Validator implementations by the way.

How to embed into an application

There are some basic rules on how to store user passwords. I'm not a security expert, that should be said for the whole library! I did my best to make everything secure, but that's not a promise! So here's a short recap on how to deal with passwords:

  1. Never store the password in clear text, always store hashed versions. Compute the hashed version with Generate(yourHasher, password)
  2. Store these hashes in a database or in a file. Hashers return []byte and these can be converted to a string with string(hashed)
  3. When a user tries to login: Retrieve the stored hashed string, use GuessValidatorFunc or Compare(yourValidator, hashed, password) in combination with GuessValidator to compare the hashed version with a clear text password
  4. Only if the returned error is nil accept the password. If any error is returned (no matter which one) assume that the login failed. Check the different errors in the documentation for more details
  5. Use a minimum password length that is always checked on the server-side in web applications
  6. All implemented algorithms compute a cryptographically secure salt and include this salt in the encoding
  7. If you ever have to compare raw keys by yourself, never compare them by iterating over all entries. Always use a constant time compare function such as subtle/ConstantTimeCompare

Parameters

This section describes the parameter values of the hashers as well as their defaults. The cost parameters are rather high compared to the proposed defaults of the algorithms. Since the documentations are usually some years old I think it's a good idea to increase the parameters. I've tried to reach 241ms computation time for each hash computation.

bcrypt

Read details in the bcrypt documentation.

Parameter Default Note
Cost 12 Must be a value between 4 and 31

The cost parameter can be increased to make the computation more expensive. The default cost is set to 12, in contrast to the bcrypt package which uses 10. This is due to better hardware performance as of today.

scrypt

Read the details in the scrypt documentation. More details can be found here.

Parameter Default Note
N 65536 (= 2¹⁶) CPU / memory cost parameter
R 8 r * p < 2³⁰
P 1 r * p < 2³⁰
KeyLen 64

N is the main CPU / memory cost parameter. The scrypt package documentation recommends N = 32768 (2¹⁵). However I've found that to small due to improved hardware, thus the default is 65536 (2¹⁶). However note that N scales both CPU and memory, on systems with restricted memory (maybe even some servers with lots of hash computations) 2¹⁶ can be too much. I really prefer argon2.

Note that N is the cost parameter (as can be found in the documentation). N must be a power of two. You can't set n directly, instead you can set the number of rounds with N = 2^(rounds). So for a value of N = 65536 do SetRounds(16). For invalid rounds (2^(rounds) overflows int) rounds = 16 will used and a warning gets logged. Just use rounds s.t. 2^rounds fits in an integer.

Argon2i

Read the details in the argon2 documentation.

Parameter Default Note
Time 5 CPU cost parameter
Memory 64*1024 ~64 MB Memory in KiB
Threads Number of CPUs Concurrency parameter
KeyLen 64

The documentation suggests Time (t) = 3 and Memory (m) = 32 * 1024 ~32 MB, this is not enough in my opinion so both have been increased.

Argon2id

Read the details in the argon2 documentation.

Parameter Default Note
Time 5 CPU cost parameter
Memory 64*1024 ~64 MB Memory in KiB
Threads Number of CPUs Concurrency parameter
KeyLen 64

The documentation suggests Time (t) = 1. Again this parameter has been increased.

Auto tuning

In order to automatically compute cost parameters for the algorithms there are four auto tuning functions:

  1. TuneBcrypt: Tunes the cost parameter
  2. TuneScrypt: Tunes the N parameter, all other parameters are left unchanged
  3. TuneArgon2i: Tunes the Time parameter, all other parameters are left unchanged
  4. TuneArgon2id: Tunes the Time parameter, all other parameters are left unchanged

However you should not use these methods in your software to automatically compute your parameters! Run the functions, check the parameters and draw your own conclusions.

There is also a small tool tune in cmd/tune/tune.go. Example usage: ./tune scrypt 241ms. This will compute the scrypt conf with increasing N values until at least an average of 241ms per computation is reached.

Hash sizes

The computed hashes contain the parameters as well as the key (encoded base64) and the salt (same length as the key, also encoded base64). To store hashes in a database a VARCHAR with a big enough size should be used. Here is a list of the max encoding length (not guaranteed to be correct, but should be fine).

Algorithm KeyLen Max Encoding length
bcrypt 32 (fixed) 60
scrypt 32 149
scrypt 64 237
argon2i 32 176
argon2i 64 264
argon2id 32 177
argon2id 64 265

Hash formats

The library uses a phc-like format wherever possible. I've tried to be compatible with python hashing libraries though (and I think by this many of its C base libraries). This means not all hashes are pure phc: bcrypt uses the encoding of the bcrypt package, argon2 hashes contain the version in its own section like in python passlib.

Examples of hashes:

  • bcrypt: $2a$12$EQvhgTqh1YSzPaI215iX1.oDMckmbm29DCvVvmQvYx.8RlwIbEXpC
  • scrypt: $scrypt$ln=16,r=8,p=1$T3atTORf3LoPvGc1ocgyghoONHQnSobSpBAZ7w9jeIBK3Q4K0oeqRuQ6a67/dJLXOT8PrGxoHiyKUC73pH5Mgg$Pq1+fp9EJ61FOUrb9FN7Mwyn6zg1mG524s6i7E1sO3IBl32eXpogQzCNQvA5BKAgpt54/fuzEHBmlSXheJgGIA
  • argon2: $argon2id$v=19$m=65536,t=5,p=4$/grUZ55pLAb2wDCxuMAWTXbjsIqNHxuCEHGDv3hQI8PdB5swVXMKah9WHnW2A2B8eVLLondKnaU2NTuZIbpDUg$qNGIMqbNZAUIaO45T9qFkktssIHhkkHRwSpxEUBciCHsMjY2z61WYxT1zQOcvxtu+XUYlVe1oLiRDEpeGFr5mQ

Constraints

Constraints impose restrictions on the arguments of hashers. That is if a password hash was created with values that now became insecure (better hardware or whatever) or with a hashing algorithm that proved to be insecure these password hashes should be replaced. gopherbounce has a Constraint interface for this purpose.

There are several implementations of this interface, here are their usecases:

  • Filter by algorithm: If you used bcrypt all the time but now you think that bcrypt is not safe enough any more use an AlgConstraint. For example gopherbounce.NewAlgConstraint(gopherbounce.BcryptAlg). This will create a constraint that returns true for all bcrypt hashes.
  • Filter by algorithm parameters: If you want to find all scrypt hashes that were created with N < 32768 you can use ScryptConstraint. This type does not implement the Constraint interface directly but implements instead AbstractScryptConstraint. To create the constraint mentioned above use gopherbounce.NewScryptConstraint(32768, "N", gopherbounce.Less). To use it directly as a Constraint you can use MultiConstraint as explained below. There are also algorithm specific constraints for the other algorithms: BcryptConstraint and Argon2Constraint (for both argon2i and argon2id).
  • Accumulate algorithm specific constraints: If you want a constraint for scrypt that checks if N < 32768 or r < 8 you can build a disjunction of these two constraints:
c1 := gopherbounce.NewScryptConstraint(32768, "N", gopherbounce.Less)
c2 := gopherbounce.NewScryptConstraint(8, "r", gopherbounce.Less)
c := gopherbounce.NewScryptAcc(gopherbounce.Disjunction, c1, c2)
  • An ScryptAcc can be used to combine different scrypt constraints. In this case we create a disjunction. That is if either one of the constraints is true the disjunction is true. ScryptAcc itself again implements AbstractScryptConstraint. Again there are accumlators for other algorithms: BcryptAcc, Argon2iAcc, Argon2idAcc
  • Use a MultiConstraint to use algorithm specific constraints as a general Constraint. MultiConstraint implements the general Constraint interface and performs tests for specific algorithms. See the godoc for more details. It can be used to "convert" an algorithm specific constraint to a general Constraint. The example below demonstrates this: The Check method of the MultiConstraint returns true for all bcrypt hashes and all scrypt hashes where N < 32768 or r < 8:
multi := gopherbounce.NewMultiConstraint()
s1 := gopherbounce.NewScryptConstraint(32768, "N", gopherbounce.Less)
s2 := gopherbounce.NewScryptConstraint(8, "r", gopherbounce.Less)
s := gopherbounce.NewScryptAcc(gopherbounce.Disjunction, s1, s2)
// ignore bcrypt
multi.AddAlgConstraint(gopherbounce.BcryptAlg)
// set scrypt constraint
multi.ScryptConstraint = s
  • Multiple Constraints can be combined in a disjunction or conjunction.
  • Note that whenever we use a conjunction (ConstraintConjunction or one of the algorithm specific accumulators) the empty conjunction always returns true.
Parsing constraints

You can also parse constraints from a file (or any reader) with ParseConstraints or ParseConstraintsFromFile. Valid parameters for the algorithms are described in the Parameters section. Here is a small example (the values must not really make sense, it's just a syntax example):

[bcrypt]
Cost < 12

[scrypt = foo]
KeyLen < 12
R <= 9

ignore bcrypt

[argon2i = bar]
Time < 4
Memory = 2

[argon2id]
Time < 10
KeyLen = 32

As you can see there are different blocks and constraints for that block. For example "[scrypt]" followed by constraints for scrypt. Blocks must be separated by at least one blank line. Instead of a line of the form "[ALG]" a line of the form "ignore ALG" is accepted, for example "ignore bcrypt". The meaning is that bcrypt should be ignored completely. This function returns all parsed constraints in form of the collection type ConstraintsCol. The form "[argon2i = bar]" is a named block. Though this is syntactically correct the names are ignored by the parse method.

Whatever you do with the result: The bcrypt constraint "Cost < 12" should be useless because "ignore bcrypt" completely ignores bcrypt. Again, just a syntax example.

You can also write these constraints to a file with WriteHasherConf.

The workflow with constraints should be as follows:

  1. User tries to log in
  2. If password is correct try the validator on the hash
  3. If validator returns true: Compute new hash (with a more secure hasher) and store the new hash

License

Copyright 2018, 2019 Fabian Wenzelmann

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

The following external packages are imported:

golang/crypto, comes with the following license: Copyright (c) 2009 The Go Authors. All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  • Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  • Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Documentation

Index

Constants

View Source
const (
	// BcryptName is the name of the bcrypt algorithm.
	BcryptName = "bcrypt"

	// ScryptName is the name of the scrypt algorithm.
	ScryptName = "scrypt"

	// Argon2iName is the name of the Argon2i algorithm.
	Argon2iName = "argon2i"

	// Argon2idName is the name of the Argon2id algorithm.
	Argon2idName = "argon2id"

	// BcryptPrefix is the algorithm prefix in the hash encoding.
	BcryptPrefix = "$2a"

	// ScryptPrefix is the algorithm prefix in the hash encoding.
	ScryptPrefix = "$scrypt"

	// Argon2iPrefix is the algorithm prefix in the hash encoding.
	Argon2iPrefix = "$argon2i$"

	// Argon2idPrefix is the algorithm prefix in the hash encoding.
	Argon2idPrefix = "$argon2id$"
)
View Source
const Defaultalphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

Defaultalphabet is the alphabet used by most algorithms.

View Source
const (
	// MaxIntLength is the maximal length that we assume an integer encoding
	// as a string can have.
	MaxIntLength = 20
)

Variables

View Source
var (
	// ConstraintLineRx is the regex used to parse a single constraint line.
	ConstraintLineRx = regexp.MustCompile(`^\s*([a-zA-Z]+)\s+(<|>|<=|>=|=|≤|≥)\s+(-?\d+)\s*$`)
	// HeadLineRx is the regex used to parse a heading line.
	HeadLineRx = regexp.MustCompile(`^\s*\[\s*(\w+)(\s*=\s*(\w+))?\s*\]\s*$`)
	// IgnoreAlgLineRx is the regex used to parse a algorithm ignore line.
	IgnoreAlgLineRx = regexp.MustCompile(`^\s*ignore\s+([a-zA-Z]+)\s*$`)
)
View Source
var (
	// Bcrypt is a bcrypt Hasher.
	Bcrypt = NewBcryptHasher(nil)

	// Scrypt is a scrypt Hasher.
	Scrypt = NewScryptHasher(nil)

	// Argon2i is a argon2 Hasher using the Argon2i key function.
	Argon2i = NewArgon2iHasher(nil)

	// Argon2id is a argon2 Hasher using the Argon2id key function.
	// Argon2id is considered more secure than Argon2i.
	Argon2id = NewArgon2idHasher(nil)

	// DefaultHasher ia a rather secure Hasher that should be safe to be used
	// by most applications. At the moment it's  Argon2id with the default
	// paramters.
	DefaultHasher = NewArgon2idHasher(nil)
)
View Source
var (
	// BcryptVal is a Validator for bcrypt encoded hashes.
	BcryptVal = BcryptValidator{}

	// ScryptVal is a Validator for scrypt encoded hashes.
	ScryptVal = ScryptValidator{}

	// Argon2iVal is a Validator for argon2i encoded hashes.
	Argon2iVal = Argon2iValidator{}

	// Argon2idVal is a Validator for argon2id encoded hashes.
	Argon2idVal = Argon2idValidator{}
)
View Source
var (
	// PHCScryptConfig is the phc description of scrypt hashes.
	PHCScryptConfig = &PHCInfo{
		MinSaltLength: -1,
		MaxSaltLength: -1,
		MinHashLength: -1,
		MaxHashLength: -1,
		ParamInfos: []*PHCParamInfo{
			&PHCParamInfo{"ln", 2, false},
			&PHCParamInfo{"r", -1, false},
			&PHCParamInfo{"p", -1, false},
		},
	}

	// PHCArgon2Config is the phc description of argon2 hashes.
	PHCArgon2Config = &PHCInfo{
		MinSaltLength: -1,
		MaxSaltLength: -1,
		MinHashLength: -1,
		MaxHashLength: -1,
		ParamInfos: []*PHCParamInfo{
			&PHCParamInfo{"m", 10, false},
			&PHCParamInfo{"t", 10, false},
			&PHCParamInfo{"p", 3, false},
		},
	}
)
View Source
var DefaultBcryptConf = &BcryptConf{Cost: 12}

DefaultBcryptConf is the default configuration for bcrypt.

DefaultEncoding is the internal encoding based on Defaultalphabet.

View Source
var DefaultScryptConf = NewScryptConf(16, 8, 1, 64)

DefaultScryptConf is the default configuration for scrypt.

Functions

func Argon2iHashSize

func Argon2iHashSize(keyLen int) int

Argon2iHashSize returns the maximal hash size of a argon2i hash with a key and salt of with KeyLen bytes. The length is the maximal length, not the actual length.

func Argon2idHashSize

func Argon2idHashSize(keyLen int) int

Argon2idHashSize returns the maximal hash size of a argon2id hash with a key and salt of with KeyLen bytes. The length is the maximal length, not the actual length.

func Base64Decode

func Base64Decode(src []byte) ([]byte, error)

Base64Decode decodes the source using the encoding.

func Base64Encode

func Base64Encode(src []byte) []byte

Base64Encode encodes the source to base64 using the default encoding.

func BcryptHashSize

func BcryptHashSize() int

BcryptHashSize returns the hash size of bcrypt hashes.

func Compare

func Compare(v Validator, hashed []byte, password string) (err error)

Compare wraps a call to v.Compare(hashed, password) and recovers from any panic that might occur, it's advised to always use Compare instead of using the validator directly. v is not allowed to be nil.

func CompareHashes

func CompareHashes(x, y []byte) bool

CompareHashes uses a constant time compare algorithm to compare to key hashes. Constant time compare functions are important or otherwise attackers might infer knowledge about the real password.

func CompareInt

func CompareInt(a, b int64, rel BinRelation) bool

CompareInt compares two integers given the relation. For example CompareInt(21, 42, Less) would return true. For an unkown relation it returns false and logs a warning.

func CompareUint

func CompareUint(a, b uint64, rel BinRelation) bool

CompareUint compares to uints given the relation. It works as CompareInt, but works with uints instead of ints.

func EncodePHCHash

func EncodePHCHash(w io.Writer, hash string, minLength, maxLength int) (int, error)

EncodePHCHash writes the hash to the writer. If the hash is empty nothing is written. It returns the number of bytes written. An error might occur if the hash is invalid (according to min/max length) or if writing to w fails. The length can be < 0 in which case they're ignored.

func EncodePHCID

func EncodePHCID(w io.Writer, id string) (int, error)

EncodePHCID writes the algorithm id in the phc format to the writer. The string written is simply "$ID". It returns the number of bytes written.

func EncodePHCParams

func EncodePHCParams(w io.Writer, values []string, infos []*PHCParamInfo) (int, error)

EncodePHCParams writes the pch parameters to the writer. values and infos must be of the same length. See PCH type documentation for more details. If no parameters are written (parameter is empty, all parameters are optional and not given) nothing is written to the writer. It returns the number of bytes written. An error might occur if the parameter values do not match the description (length, non-optional and not given etc.) and if writing to w fails.

func EncodePHCSalt

func EncodePHCSalt(w io.Writer, salt string, minLength, maxLength int) (int, error)

EncodePHCSalt writes the salt to the writer. If the salt is empty nothing is written. It returns the number of bytes written. An error might occur if the salt is invalid (according to min/max length) or if writing to w fails. The length can be < 0 in which case they're ignored.

func GenSalt

func GenSalt(numBytes int) ([]byte, error)

GenSalt computes a cryptographically secure salt given the number of bytes.

func Generate

func Generate(h Hasher, password string) (res []byte, err error)

Generate wraps a call to h.Generate and recovers from any panic that might occur, it's advised to always use Generate instead of using the hasher directly. h is not allowed to be nil.

func PHCParseParams

func PHCParseParams(s string, infos []*PHCParamInfo) ([]string, error)

PHCParseParams parses the parameter part from a phc string. That is the list of parameter / value pairs. infos is the information about all parameters, the result is always exactly the size of the infos. Optional parameters are set to "". This function validates all names, the order of the parameters and validates the value as well.

func PHCSplitParam

func PHCSplitParam(s string) (string, string, error)

PHCSplitParam parses a single phc parameter of the form PARAM=VALUE. No validation checking is performed: No test if the param or value is a valid sequence of characters. It just finds the first = in the string and splits accordingly.

func PHCSplitString

func PHCSplitString(s string) []string

PHCSplitString splits the string according to the separator $.

func PHCValidateHash

func PHCValidateHash(hash string, minLength, maxLength int) error

PHCValidateHash checks if a string is a valid phc hash. It checks if the string only contains valid characters and if the length of the hash is in the given boundaries. Setting a boundary to -1 means that there is no restriction.

func PHCValidateID

func PHCValidateID(id string) error

PHCValidateID checks if a string is a valid phc id. The function tests if the string has a length of at most 32 and contains only valid characters.

func PHCValidateParamName

func PHCValidateParamName(param string) error

PHCValidateParamName checks if a string is a valid phc parameter name. The function tests if the string has a length of at most 32 and contains only valid characters.

func PHCValidateSalt

func PHCValidateSalt(salt string, minLength, maxLength int) error

PHCValidateSalt checks if a string is a valid phc salt. It checks if the string only contains valid characters and if the length of the salt is in the given boundaries. Setting a boundary to -1 means that there is no restriction.

func PHCValidateValue

func PHCValidateValue(value string, maxLength int) error

PHCValidateValue checks if a string is a valid phc parameter value. It cecks if the string only contains valid characters and if the length is not greater than maxLength, MaxLength < 0 meaning that now boundary exists.

func ParseAlgIgnoreLine

func ParseAlgIgnoreLine(line string) (algorithm string, err error)

ParseAlgIgnoreLine parses a algorithm ignore line (with IgnoreAlgLineRx). Example of a line: "ignore bcrypt". This would return "bcrypt". This function does not check if the algorithm name is valid, for example "ignore foo" would be valid.

func ParseArgon2Conf

func ParseArgon2Conf(hashed []byte) (*PHC, *Argon2Conf, error)

func ParseHeadLine

func ParseHeadLine(line string) (algorithm, name string, err error)

ParseHeadLine parses a heading line (with HeadLineRx). Example of a line "[bcypt]" or with a name [scrypt = foo]. The first one yields to "bcrypt" and the empty string, the second to "scrypt" and "foo". This function does not check if the algorithm name is valid, for example "[foo]" would be valid.

func Pow

func Pow(base, exp int64) int64

Pow computes base**exp. It only works with positive integers.

func SycryptHashSize

func SycryptHashSize(keyLen int) int

SycryptHashSize returns the maximal hash size of a scrypt hash with a key and salt of with KeyLen bytes. The length is the maximal length, not the actual length.

func WriteArgon2iConstraints

func WriteArgon2iConstraints(w io.Writer, cs []Argon2Constraint) (int, error)

WriteArgon2iConstraints writes all constraints to a file s.t. they can be parsed again later.

func WriteArgon2idConstraints

func WriteArgon2idConstraints(w io.Writer, cs []Argon2Constraint) (int, error)

WriteArgon2idConstraints writes all constraints to a file s.t. they can be parsed again later.

func WriteBcryptConstraints

func WriteBcryptConstraints(w io.Writer, cs []BcryptConstraint) (int, error)

WriteBcryptConstraints writes all constraints to a file s.t. they can be parsed again later.

func WriteHasherConf

func WriteHasherConf(w io.Writer, hasher Hasher) (int, error)

WriteHasherConf writes the config of a hasher in a format that can be read by ParseHasher.

func WriteScryptConstraints

func WriteScryptConstraints(w io.Writer, cs []ScryptConstraint) (int, error)

WriteScryptConstraints writes all constraints to a file s.t. they can be parsed again later.

Types

type AbstractArgon2iConstraint

type AbstractArgon2iConstraint interface {
	CheckArgon2i(data *Argon2iData) bool
}

AbstractArgon2iConstraint is a constraint based on argon2i data.

type AbstractArgon2idConstraint

type AbstractArgon2idConstraint interface {
	CheckArgon2id(data *Argon2idData) bool
}

AbstractArgon2idConstraint is a constraint based on argon2id data.

type AbstractBcryptConstraint

type AbstractBcryptConstraint interface {
	CheckBcrypt(conf *BcryptConf) bool
}

AbstractBcryptConstraint is a constraint based on bcrypt configs.

type AbstractScryptConstraint

type AbstractScryptConstraint interface {
	CheckScrypt(data *ScryptData) bool
}

AbstractScryptConstraint is a constraint based on scrypt data.

type AccType

type AccType int

AccType is an accumlator type used to combine constraints. Constraints can be a Conjunction (and) or Disjunction (or).

const (
	// Disjunction is an or connection.
	Disjunction AccType = iota
	// Conjunction is an and connection. Note that an empty Conjunction is always
	// true.
	Conjunction
)

type AlgConstraint

type AlgConstraint HashAlg

AlgConstraint implements Constraint and only tests if the hashed string represents a specific type.

func NewAlgConstraint

func NewAlgConstraint(alg HashAlg) AlgConstraint

NewAlgConstraint returns a new AlgConstraint that returns true if the algorithm represented by a hashed password is alg.

func (AlgConstraint) Check

func (c AlgConstraint) Check(hashed []byte) bool

Check implements the Constraint interface.

type AlgIDError

type AlgIDError struct {
	Prefix        string
	Expected, Got string
}

AlgIDError is returned if a hash version has the wrong prefix for a certain Validator. This does not mean that the hashes version is invalid in general, only for the specific Validator.

func NewAlgIDError

func NewAlgIDError(prefix, expected, got string) AlgIDError

NewAlgIDError returns a new AlgIDError. Prefix is appended to the error message. Expected and got are the resp. ids.

func (AlgIDError) Error

func (err AlgIDError) Error() string

Error returns the string representation of the error.

func (AlgIDError) String

func (err AlgIDError) String() string

String returns the string representation of the error.

type Argon2Conf

type Argon2Conf struct {
	Time    uint32
	Memory  uint32
	Threads uint8
	KeyLen  uint32
}

Argon2Conf contains all parameters for argon2, it is used by argon2i and argon2id.

func (*Argon2Conf) Copy

func (conf *Argon2Conf) Copy() *Argon2Conf

Copy returns a copy of a config.

func (*Argon2Conf) String

func (conf *Argon2Conf) String() string

String returns a human-readable string reprensetation.

type Argon2Constraint

type Argon2Constraint struct {
	Bound   uint64
	VarName string
	Rel     BinRelation
}

Argon2Constraint imposes a restriction on one of the parameters of an Argon2Conf. The parameter is describec by the string name. It imposes the restriction [VarName] [Rel] [Bound]. For example time < 2.

It implements both AbstractArgon2iConstraint and AbstractArgon2idConstraint.

VarName must be either "time", "memory", "keylen" or "threads".

func NewArgon2Constraint

func NewArgon2Constraint(bound uint64, varName string, rel BinRelation) Argon2Constraint

NewArgon2Constraint returns a new Argon2Constraint. It does not check if varName is valid.

func ParseArgon2Cons

func ParseArgon2Cons(line string) (Argon2Constraint, error)

ParseArgon2Cons parses a constraint for argon2 (argon2i and argon2id). It allows the following format: "LHS RELATION BOUND" where LHS is either "time", "memory", "Threads" or "KeyLen".

func (Argon2Constraint) CheckArgon2i

func (c Argon2Constraint) CheckArgon2i(data *Argon2iData) bool

// CheckArgon2i checks the argon2 data based on the variable name, relation and bound.

func (Argon2Constraint) CheckArgon2id

func (c Argon2Constraint) CheckArgon2id(data *Argon2idData) bool

CheckArgon2id checks the argon2 data based on the variable name, relation and bound.

func (Argon2Constraint) String

func (c Argon2Constraint) String() string

type Argon2iAcc

type Argon2iAcc struct {
	Constraints []AbstractArgon2iConstraint
	Type        AccType
}

Argon2iAcc is an accumulation of argon2i constraints. It implements AbstractArgon2iConstraint.

func NewArgon2iAcc

func NewArgon2iAcc(t AccType, constraints ...AbstractArgon2iConstraint) Argon2iAcc

NewArgon2iAcc returns a new Argon2iAcc given the accumulation type and the constraints it's composed of.

func (Argon2iAcc) CheckArgon2i

func (acc Argon2iAcc) CheckArgon2i(data *Argon2iData) bool

CheckArgon2i composes the constraints based on the accumulation type.

type Argon2iConf

type Argon2iConf struct {
	*Argon2Conf
}

Argon2iConf contains all parameters for argon2i.

func TuneArgon2i

func TuneArgon2i(base *Argon2iConf, duration time.Duration) (*Argon2iConf, time.Duration, error)

TuneArgon2i runs argon2i with increasing time values until an average runtime of at least duration is reached. Do not use this function to automatically compute your configuration, it is not safe enough! Run it, check the result and draw your own conclusions.

func (*Argon2iConf) Copy

func (conf *Argon2iConf) Copy() *Argon2iConf

Copy returns a copy of a config.

type Argon2iData

type Argon2iData struct {
	*Argon2iConf
	Salt, Key       string
	RawSalt, RawKey []byte
}

Argon2iData stores in addition to a config also the salt and key, both base64 encoded (Salt and Key) as well as the raw version (decoded from Salt and Key).

func ParseArgon2iData

func ParseArgon2iData(hashed []byte) (*Argon2iData, error)

ParseArgon2iData parses argon2i data from the hashed version.

type Argon2iHasher

type Argon2iHasher struct {
	*Argon2iConf
}

Argon2iHasher is a Hasher using argon2i.

func NewArgon2iHasher

func NewArgon2iHasher(conf *Argon2iConf) *Argon2iHasher

NewArgon2iHasher returns a new NewArgon2iHasher with the given parameter.

func (*Argon2iHasher) Copy

func (h *Argon2iHasher) Copy() *Argon2iHasher

Copy returns a copy of the hasher.

func (*Argon2iHasher) Generate

func (h *Argon2iHasher) Generate(password string) ([]byte, error)

Generate implements the Hasher interface.

func (*Argon2iHasher) Key

func (h *Argon2iHasher) Key(password string, salt []byte) ([]byte, error)

Key returns the argon2i key of the password given the clear text password, salt and parameters from the config of the Hasher.

type Argon2iValidator

type Argon2iValidator struct{}

Argon2iValidator implements Validator for argon2i hashes.

func (Argon2iValidator) Compare

func (v Argon2iValidator) Compare(hashed []byte, password string) error

Compare implements the Validator interface for argon2i hashes.

type Argon2idAcc

type Argon2idAcc struct {
	Constraints []AbstractArgon2idConstraint
	Type        AccType
}

Argon2idAcc is an accumulation of argon2id constraints. It implements AbstractArgon2idConstraint.

func NewArgon2idAcc

func NewArgon2idAcc(t AccType, constraints ...AbstractArgon2idConstraint) Argon2idAcc

NewArgon2idAcc returns a new Argon2idAcc given the accumulation type and the constraints it's composed of.

func (Argon2idAcc) CheckArgon2id

func (acc Argon2idAcc) CheckArgon2id(data *Argon2idData) bool

CheckArgon2id composes the constraints based on the accumulation type.

type Argon2idConf

type Argon2idConf struct {
	*Argon2Conf
}

Argon2idConf contains all parameters for argon2id.

func TuneArgon2id

func TuneArgon2id(base *Argon2idConf, duration time.Duration) (*Argon2idConf, time.Duration, error)

TuneArgon2id runs argon2id with increasing time values until an average runtime of at least duration is reached. Do not use this function to automatically compute your configuration, it is not safe enough! Run it, check the result and draw your own conclusions.

func (*Argon2idConf) Copy

func (conf *Argon2idConf) Copy() *Argon2idConf

Copy returns a copy of a config.

type Argon2idData

type Argon2idData struct {
	*Argon2idConf
	// encoded with base64
	Salt, Key       string
	RawSalt, RawKey []byte
}

Argon2idData stores in addition to a config also the salt and key, both base64 encoded (Salt and Key) as well as the raw version (decoded from Salt and Key).

func ParseArgon2idData

func ParseArgon2idData(hashed []byte) (*Argon2idData, error)

ParseArgon2idData parses argon2id data from the hashed version.

type Argon2idHasher

type Argon2idHasher struct {
	*Argon2idConf
}

Argon2idHasher is a Hasher using argon2id.

func NewArgon2idHasher

func NewArgon2idHasher(conf *Argon2idConf) *Argon2idHasher

NewArgon2idHasher returns a new NewArgon2idHasher with the given parameter.

func (*Argon2idHasher) Copy

func (h *Argon2idHasher) Copy() *Argon2idHasher

Copy returns a copy of the hasher.

func (*Argon2idHasher) Generate

func (h *Argon2idHasher) Generate(password string) ([]byte, error)

Generate implements the Hasher interface.

func (*Argon2idHasher) Key

func (h *Argon2idHasher) Key(password string, salt []byte) ([]byte, error)

Key returns the argon2id key of the password given the clear text password, salt and parameters from the config of the Hasher.

type Argon2idValidator

type Argon2idValidator struct{}

Argon2idValidator implements Validator for argon2id hashes.

func (Argon2idValidator) Compare

func (v Argon2idValidator) Compare(hashed []byte, password string) error

Compare implements the Validator interface for argon2id hashes.

type Base64Encoding

type Base64Encoding struct {
	Alphabet string
	Encoding *base64.Encoding
}

Base64Encoding is the internal reprensetation of a base64 encoding. The base64 encoding / decoding is inspired by https://github.com/golang/crypto/blob/master/bcrypt/base64.go

func NewBase64Encoding

func NewBase64Encoding(alphabet string) *Base64Encoding

NewBase64Encoding returns a new Base64Encoding.

func (*Base64Encoding) Base64Decode

func (enc *Base64Encoding) Base64Decode(src []byte) ([]byte, error)

Base64Decode decodes the source using the alphabet.

func (*Base64Encoding) Base64Encode

func (enc *Base64Encoding) Base64Encode(src []byte) []byte

Base64Encode encodes the source to base64 using the alphabet.

func (*Base64Encoding) SetAlphabet

func (enc *Base64Encoding) SetAlphabet(alphabet string)

SetAlphabet sets the encoding alphabet to a new alphabet.

type BcryptAcc

type BcryptAcc struct {
	Constraints []AbstractBcryptConstraint
	Type        AccType
}

BcryptAcc is an accumulation of bcrypt constraints. It implements AbstractBcryptConstraint.

func NewBcryptAcc

func NewBcryptAcc(t AccType, constraints ...AbstractBcryptConstraint) BcryptAcc

NewBcryptAcc returns a new BcryptAcc given the accumulation type and the constraints it's composed of.

func (BcryptAcc) CheckBcrypt

func (acc BcryptAcc) CheckBcrypt(conf *BcryptConf) bool

CheckBcrypt composes the constraints based on the accumulation type.

type BcryptConf

type BcryptConf struct {
	Cost int
}

BcryptConf contains all parameters for bcrypt.

func ParseBcryptConf

func ParseBcryptConf(hashed []byte) (*BcryptConf, error)

ParseBcryptConf parses a configuration from a hashes version.

func TuneBcrypt

func TuneBcrypt(base *BcryptConf, duration time.Duration) (*BcryptConf, time.Duration, error)

TuneBcrypt runs bcrypt with increasing cost values until an average runtime of at least duration is reached. Do not use this function to automatically compute your configuration, it is not safe enough! Run it, check the result and draw your own conclusions.

func (*BcryptConf) Copy

func (conf *BcryptConf) Copy() *BcryptConf

Copy returns a copy of a config.

func (*BcryptConf) String

func (conf *BcryptConf) String() string

String returns a human-readable string reprensetation.

type BcryptConstraint

type BcryptConstraint struct {
	CostBound int64
	Rel       BinRelation
}

BcryptConstraint implements AbstractBcryptConstraint and imposes a restriction on the cost of the config.

func NewBcryptConstraint

func NewBcryptConstraint(bound int, rel BinRelation) BcryptConstraint

NewBcryptConstraint returns a new BcryptConstraint.

func ParseBcryptCons

func ParseBcryptCons(line string) (BcryptConstraint, error)

ParseBcryptCons parses a constraint for bcrypt. The only allowed form is "cost RELATION BOUND".

func (BcryptConstraint) CheckBcrypt

func (c BcryptConstraint) CheckBcrypt(conf *BcryptConf) bool

CheckBcrypt checks the cost according to the provided relation.

func (BcryptConstraint) String

func (c BcryptConstraint) String() string

type BcryptHasher

type BcryptHasher struct {
	*BcryptConf
}

BcryptHasher is a Hasher using bcrypt.

func NewBcryptHasher

func NewBcryptHasher(conf *BcryptConf) *BcryptHasher

NewBcryptHasher returns a new BcryptHasher with the given parameters.

func (*BcryptHasher) Copy

func (h *BcryptHasher) Copy() BcryptHasher

Copy returns a copy of the hasher.

func (*BcryptHasher) Generate

func (h *BcryptHasher) Generate(password string) ([]byte, error)

Generate implements the Hasher interface. All errors returned are from golang.org/x/crypto/bcrypt.

type BcryptValidator

type BcryptValidator struct{}

BcryptValidator implements Validator for bcrypt hashes.

func (BcryptValidator) Compare

func (v BcryptValidator) Compare(hashed []byte, password string) error

Compare implements the Validator interface for bcrypt hashes.

type BinRelation

type BinRelation int

BinRelation is a type used to identify relations on integers (<, = etc.).

const (
	// Less describes the relation <.
	Less BinRelation = iota
	// Greater describes the relation >.
	Greater
	// Leq describes the relation ≤.
	Leq
	// Geq describes the relation ≥.
	Geq
	// Eq describes the equality relation =.
	Eq
)

func ParseConstraintInt

func ParseConstraintInt(line string, bitSize int) (lhs string, rhs int64, rel BinRelation, err error)

ParseConstraintInt works as ParseConstraintLine but the right-hand side is parsed into a int64 (with the given bitSize).

func ParseConstraintLine

func ParseConstraintLine(line string) (lhs, rhs string, rel BinRelation, err error)

ParseConstraintLine parses a single line constraint line (with ConstraintLineRx). It returns the lhs and rhs as a string. Example of a line "cost < 10" that would return "cost" "10" Less. This function does not check if the identifiers are valid. For example "foo < 10" would be valid.

func ParseConstraintUint

func ParseConstraintUint(line string, bitSize int) (lhs string, rhs uint64, rel BinRelation, err error)

ParseConstraintUint works as ParseConstraintInt but parses a uint.

func ParseRelation

func ParseRelation(s string) (BinRelation, error)

ParseRelation parses the relation type from a string. It accepts the "obvious" symbols like <, >=, =. It also accepts ≤ and ≥.

func (BinRelation) String

func (rel BinRelation) String() string

type Constraint

type Constraint interface {
	Check(hashed []byte) bool
}

Constraint describes a property a hasher must have. Usually they inclucde a restriction on the type of the hasher and restrictions on the hasher's parameters. Like: A bcrypt hasher with cost < 10. Constraints are used to find hashes that should be renewed / replaced. A constraints check function gets a hashed entry as input and decides what to do with it, like decoding it. Usually there are accumlator functions to avoid decoding an entry again and again.

type ConstraintConjunction

type ConstraintConjunction []Constraint

ConstraintConjunction is a conjunction of Constraints and itself implements the Constraint interface. An empty conjunction is considered true.

func NewConstraintConjunction

func NewConstraintConjunction(constraints ...Constraint) ConstraintConjunction

NewConstraintConjunction returns a new conjunction.

func (ConstraintConjunction) Check

func (conj ConstraintConjunction) Check(hashed []byte) bool

Check checks if all conjuncts are true.

type ConstraintDisjunction

type ConstraintDisjunction []Constraint

ConstraintDisjunction is a disjunction of Constraints and itself implements the Constraint interface.

func NewConstraintDisjunction

func NewConstraintDisjunction(constraints ...Constraint) ConstraintDisjunction

NewConstraintDisjunction returns a new disjunction.

func (ConstraintDisjunction) Check

func (disj ConstraintDisjunction) Check(hashed []byte) bool

Check checks if at least one disjunct is true.

type ConstraintSyntaxError

type ConstraintSyntaxError string

ConstraintSyntaxError is an error returned if an error occurred due to invalid syntax while parsing constraints.

func NewConstraintSyntaxError

func NewConstraintSyntaxError(cause string) ConstraintSyntaxError

NewConstraintSyntaxError returns a new ConstraintSyntaxError.

func (ConstraintSyntaxError) Error

func (err ConstraintSyntaxError) Error() string

type ConstraintsCol

type ConstraintsCol struct {
	AlgConstraints      []HashAlg
	BcryptConstraints   []BcryptConstraint
	ScryptConstraints   []ScryptConstraint
	Argon2iConstraints  []Argon2Constraint
	Argon2idConstraints []Argon2Constraint
}

ConstraintsCol is a collection of "standard" constraints (for bcrypt, scrypt, argon2i and argon2id). Such a collection can be parsed from a file (or any reader with the correct syntax) with ParseConstraints.

It also stores a list of all algorithms that should be completely ignored (AlgConstraints).

func NewConstraintCol

func NewConstraintCol() *ConstraintsCol

NewConstraintCol returns an empty constraints collection.

func ParseConstraints

func ParseConstraints(r io.Reader) (*ConstraintsCol, error)

ParseConstraints parses all constraints from a reader, see the README for more details.

func ParseConstraintsFromFile

func ParseConstraintsFromFile(filename string) (*ConstraintsCol, error)

ParseConstraintsFromFile works like ParseConstraints and reads the content from a file.

func (*ConstraintsCol) WriteConstraints

func (col *ConstraintsCol) WriteConstraints(w io.Writer, printTime bool) (int, error)

WriteConstraints writes all constraints to a file. The output is a file that can be parsed by ParseConstraints. If printTime is true a timestamp will be added as a comment to the output specifying the time the config file was created.

type HashAlg

type HashAlg int

HashAlg is a type used to enumerate all implemented algorithms.

const (
	// BcryptAlg stands for the bcrypt algorithm.
	BcryptAlg HashAlg = iota

	// ScryptAlg stands for the scrypt algorithm.
	ScryptAlg

	// Argon2iAlg stands for the argon2i algorithm.
	Argon2iAlg

	// Argon2idAlg stands for the argon2id algorithm.
	Argon2idAlg
)

func GuessAlg

func GuessAlg(hashed []byte) HashAlg

GuessAlg returns the algorithm used to create the specified hashed version. If the algorithm is unknown it returns -1.

func ParseAlg

func ParseAlg(name string) (HashAlg, error)

ParseAlg parses the algorithm from the algorith name. Valid names are "bcrypt", "scrypt", "argon2i" and "argon2id".

func (HashAlg) String

func (i HashAlg) String() string

type HashGenerator

type HashGenerator interface {
	Key(password string, salt []byte) ([]byte, error)
}

HashGenerator is an interface describing all algorithms that can be used to directly create a hashed version of a password. The difference between HashGenerator and Hasher is that Hasher returns a formatted string whereas HashGenerator returns the raw generated key.

type Hasher

type Hasher interface {
	Generate(password string) ([]byte, error)
}

Hasher is the general interface for creating hashed versions of passwords. The returned encoded string contains all information required for parsing the parameters of the key function (like https://openwall.info/wiki/john/sample-hashes).

func ParseHasher

func ParseHasher(r io.Reader) (Hasher, error)

ParseHasher parses a hasher from a config file. The syntax is the same as for constraint, but the relation must be =.

func ParseHasherConfFile

func ParseHasherConfFile(path string) (Hasher, error)

ParseHasherConfFile works as ParseHasher and reads the content from a file.

type MultiConstraint

type MultiConstraint struct {
	BcryptConstraint   AbstractBcryptConstraint
	ScryptConstraint   AbstractScryptConstraint
	Argon2iConstraint  AbstractArgon2iConstraint
	Argon2idConstraint AbstractArgon2idConstraint
	DefaultConstraint  Constraint
	// contains filtered or unexported fields
}

MultiConstraint composes the basic constraint types (bcrypt, scrypt argon2i and argon2id). It implements the general Constraint interface.

It's behaviour is as follows: It checks the hashed string and decides which algorithm it belongs to. First it checks if there is a general constraint for this algorithm. For example if bcrypt should be completely ignored you can use AddAlgConstraint(BcryptAlg). If this is the case it returns true. Otherwise it decodes the config / data from the hash and passes it to the corresponding constraint.

For example bcrypt hashes (beginning with $2a$) are passed to the BcryptConstraint. The config is parsed from that hash.

It also has a "fallback" constraint that is applied if the hashing algorithm is unkown.

func NewMultiConstraint

func NewMultiConstraint() *MultiConstraint

NewMultiConstraint returns a new MultiConstraint where all constraints are set to nil, that is it always returns false.

func (*MultiConstraint) AddAlgConstraint

func (c *MultiConstraint) AddAlgConstraint(alg HashAlg)

AddAlgConstraint adds a constraint that all hashes of algorithm alg should be ignored.

func (*MultiConstraint) Check

func (c *MultiConstraint) Check(hashed []byte) bool

Check implements the Constraint interface.

func (*MultiConstraint) HasAlgConstraint

func (c *MultiConstraint) HasAlgConstraint(alg HashAlg) bool

HasAlgConstraint checks if there is a constraint that all hashes of algorithm alg should be ignored.

func (*MultiConstraint) RemoveAlgConstraint

func (c *MultiConstraint) RemoveAlgConstraint(alg HashAlg)

RemoveAlgConstraint removes the constraint that all hashes of algorithm alg should be ignored.

type PHC

type PHC struct {
	ID         string
	Params     []string
	Salt, Hash string
}

PHC is a format for hash encodings, see https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md scrypt and argon2 use this encoding, though not everything is supported at the moment.

A PHC value is used to describe the parsed data. The ID is the algorithm id, for example "scrypt". Salt and Hash are the salt and hash strings, usually that is the base64 encoding of a binary salt/hash and must be decoded first.

Params are the value of the phc parameters. The names of these parameters are given by the algorithm specification, that is before parsing. See PHCInfo type for more information. For optional parameters that are not present in the phc string the parameter value is set to the empty string "". This should be fine since each other valid value should have at least length one.

func ParsePHC

func ParsePHC(s string, info *PHCInfo) (*PHC, error)

ParsePHC parses a phc string and returns the result as a PHC object. The info is used to check the format against the input string.

func ParsePHCAlternate

func ParsePHCAlternate(s string, info *PHCInfo) (*PHC, error)

ParsePHCAlternate parses a phc string and returns the result as a PHC object. The info is used to check the format against the input string. This version is callend "Alternate" because: It was the first draft of a parse function, I wrote another one with less code, which I thought would be slower. It turned out to be faster and is now called ParsePHC. This one is here if we ever decide to build a faster one without string splitting. Maybe some of the code can be used.

func ParsePHCFromParts

func ParsePHCFromParts(split []string, info *PHCInfo) (*PHC, error)

ParsePHCFromParts parses a phc (like ParsePHC) from the parts, that is the array of strings after splitting an input on $. This is useful if you have a slightly different encoding for a hash but want to parse it with the phc parser. For example argon2 has an additional field $v=... The argon2 parser splits the string, removes the $v=... and composes the other parts to a new string slice that is used on this function.

func (*PHC) Encode

func (phc *PHC) Encode(w io.Writer, info *PHCInfo) (int, error)

Encode encodes the pch object to a string. The info contains the specification used for the encoding. Optional parameters (set to the empty string in phc.Params) are not contained in the result.

If you want to create your own phc-like format you may want to look at the EncodePHC... functions, like EncodePHCParams. It basically combines those methods.

It returns the number of bytes written. An error might occur if the parameters do not satisfy the description or if writing to w fails.

func (*PHC) EncodeString

func (phc *PHC) EncodeString(info *PHCInfo) (string, error)

EncodeString encodes the pch object to a string. For more details see Encode.

type PHCError

type PHCError string

PHCError is returned by the pch parse function.

func NewPHCError

func NewPHCError(s string) PHCError

NewPHCError returns a new PHCError.

func (PHCError) Error

func (err PHCError) Error() string

type PHCInfo

type PHCInfo struct {
	ParamInfos                   []*PHCParamInfo
	MinSaltLength, MaxSaltLength int
	MinHashLength, MaxHashLength int
}

PHCInfo bundles information about a PHC hash string. It describes information about the parameters (in the ParamInfos slice, the order in the slice implies the order of the parameters) as well as minimum and maximum lengths for both the salt and the hash. All boundaries can be set to -1, meaning that no min/max value is set.

func NewPHCInfo

func NewPHCInfo() *PHCInfo

NewPHCInfo returns a new PHCInfo with empty parameters and no restrictions on the salt / hash length.

type PHCParamInfo

type PHCParamInfo struct {
	Name      string
	MaxLength int
	Optional  bool
}

PHCParamInfo describes information about a parameter in pch. A parameter has a name (like "r" in scrypt). MaxLength is the maximal length the parameter is allowed to have. We allow -1 which means that there is no boundary. Optional should be set to true if the parameter is optional.

func NewPHCParamInfo

func NewPHCParamInfo(name string) *PHCParamInfo

NewPHCParamInfo returns a new phc parameter without a max length and optional set to false.

type PasswordMismatchError

type PasswordMismatchError struct{}

PasswordMismatchError is returned if a hashes version and a clear text version do not match. No password details are made public by this error.

func NewPasswordMismatchError

func NewPasswordMismatchError() PasswordMismatchError

NewPasswordMismatchError returns a new PasswordMismatchError.

func (PasswordMismatchError) Error

func (err PasswordMismatchError) Error() string

Error returns the string representation of the error.

func (PasswordMismatchError) String

func (err PasswordMismatchError) String() string

String returns the string representation of the error.

type ScryptAcc

type ScryptAcc struct {
	Constraints []AbstractScryptConstraint
	Type        AccType
}

ScryptAcc is an accumulation of bcrypt constraints. It implements AbstractScryptConstraint.

func NewScryptAcc

func NewScryptAcc(t AccType, constraints ...AbstractScryptConstraint) ScryptAcc

NewScryptAcc returns a new ScryptAcc given the accumulation type and the constraints it's composed of.

func (ScryptAcc) CheckScrypt

func (acc ScryptAcc) CheckScrypt(data *ScryptData) bool

CheckScrypt composes the constraints based on the accumulation type.

type ScryptConf

type ScryptConf struct {
	R, P, KeyLen int
	// contains filtered or unexported fields
}

ScryptConf contains all parameters for scrypt.

func NewScryptConf

func NewScryptConf(rounds, r, p, keyLen int) *ScryptConf

func TuneScrypt

func TuneScrypt(base *ScryptConf, duration time.Duration) (*ScryptConf, time.Duration, error)

TuneScrypt runs scrypt with increasing N values until an average runtime of at least duration is reached. Do not use this function to automatically compute your configuration, it is not safe enough! Run it, check the result and draw your own conclusions.

func (*ScryptConf) Copy

func (conf *ScryptConf) Copy() *ScryptConf

Copy returns a copy of a config.

func (*ScryptConf) GetN

func (conf *ScryptConf) GetN() int

func (*ScryptConf) GetRounds

func (conf *ScryptConf) GetRounds() int

func (*ScryptConf) SetRounds

func (conf *ScryptConf) SetRounds(rounds int)

func (*ScryptConf) String

func (conf *ScryptConf) String() string

String returns a human-readable string reprensetation.

type ScryptConstraint

type ScryptConstraint struct {
	Bound   int64
	VarName string
	Rel     BinRelation
}

ScryptConstraint implements AbstractScryptConstraint and imposes a restriction on one of the parameters. The parameter is describec by the string name. It imposes the restriction [VarName] [Rel] [Bound]. For example n < 32768.

Note that n = 2^(rounds).

VarName must be either n, rounds, r, p or KeyLen.

func NewScryptConstraint

func NewScryptConstraint(bound int64, varName string, rel BinRelation) ScryptConstraint

NewScryptConstraint returns a new ScryptConstraint. It does not check if varName is valid.

func ParseScryptCons

func ParseScryptCons(line string) (ScryptConstraint, error)

ParseScryptCons parses a constraint for scrypt. It allows the following format: "LHS RELATION BOUND" where LHS is either "N", "R", "P" or "KeyLen".

func (ScryptConstraint) CheckScrypt

func (c ScryptConstraint) CheckScrypt(data *ScryptData) bool

CheckScrypt checks the scrypt data based on the variable name, relation and bound.

func (ScryptConstraint) String

func (c ScryptConstraint) String() string

type ScryptData

type ScryptData struct {
	*ScryptConf
	// encoded with base64
	Salt, Key       string
	RawSalt, RawKey []byte
}

ScryptData stores in addition to a config also the salt and key, both base64 encoded (Salt and Key) as well as the raw version (decoded from Salt and Key).

func ParseScryptData

func ParseScryptData(hashed []byte) (*ScryptData, error)

ParseScryptData parses scrypt data from the hashed version.

type ScryptHasher

type ScryptHasher struct {
	*ScryptConf
}

ScryptHasher is a Hasher using scrypt.

func NewScryptHasher

func NewScryptHasher(conf *ScryptConf) *ScryptHasher

NewScryptHasher returns a new ScryptHasher with the given parameters.

func (*ScryptHasher) Copy

func (h *ScryptHasher) Copy() *ScryptHasher

Copy returns a copy of the hasher.

func (*ScryptHasher) Generate

func (h *ScryptHasher) Generate(password string) ([]byte, error)

Generate implements the Hasher interface.

func (*ScryptHasher) Key

func (h *ScryptHasher) Key(password string, salt []byte) ([]byte, error)

Key returns the scrypt key of the password given the clear text password, salt and parameters from the config of the Hasher.

type ScryptValidator

type ScryptValidator struct{}

ScryptValidator implements Validator for scrypt hashes.

func (ScryptValidator) Compare

func (v ScryptValidator) Compare(hashed []byte, password string) error

Compare implements the Validator interface for scrypt hashes.

type SyntaxError

type SyntaxError string

SyntaxError is used if a hashed version is not stored in a valid syntax.

func NewSyntaxError

func NewSyntaxError(cause string) SyntaxError

NewSyntaxError returns a new SyntaxError.

func (SyntaxError) Error

func (err SyntaxError) Error() string

Error returns the string representation of the error.

func (SyntaxError) String

func (err SyntaxError) String() string

String returns the string representation of the error.

type UnknownAlgError

type UnknownAlgError struct{}

UnknownAlgError if a hashed version describes an unkown algorithm.

func NewUnknownAlgError

func NewUnknownAlgError() UnknownAlgError

NewUnknownAlgError returns a new UnknownAlgError.

func (UnknownAlgError) Error

func (err UnknownAlgError) Error() string

Error returns the string representation of the error.

func (UnknownAlgError) String

func (err UnknownAlgError) String() string

String returns the string representation of the error.

type Validator

type Validator interface {
	Compare(hashed []byte, password string) error
}

Validator is an interface that provides a method to compare a hashed version of a password with a prorivde clear text version. Any error returned should be considered as an authentication fail. Only a nil return value indicates success.

There are some predefined errors that can help you to narrow the cause. But not all implementaions are required to use these errors. Special errors include: Syntax error if the hashes version can't be parsed. VersionError: IF the version used to created the hashes value is not compatible with the implemented algorithm. AlgIDError: The provided algorithm prefix does not match the prefix required by the validator. PasswordMismatchError: If the clear text version is not the password used to create the hash.

Note that a valdiator implementation provides validation for a specific hashing algorithm, like one implementation for bcrypt, scrypt etc. If you want to validate a hashed version without knowing the used algorithm use GuessValidator or GuessValidatorFunc.

func GuessValidator

func GuessValidator(hashed []byte) Validator

GuessValidator returns a validator for the hashes version. That is a clear text password can be compared with the hashed version using the validator. If the algorithm is unknown it returns nil.

type ValidatorFunc

type ValidatorFunc func(password string) error

ValidatorFunc is a function that returns an error as specified in the Validator interface. GuessValidatorFunc can be used to create a ValidatorFunc from the hashed version of a password.

func GuessValidatorFunc

func GuessValidatorFunc(hashed []byte) ValidatorFunc

GuessValidatorFunc guesses the algorithm based on the hashe's version. The returned error is compatible with the Validator interface specification. In addition it might return an UnknownAlgError if the algorithm cannot be guessed from the hashed version.

The returned function gets wrapped by SecureValidatorFunc, so calling SecureValidatorFunc on the function is not required.

func SecureValidatorFunc

func SecureValidatorFunc(f ValidatorFunc) ValidatorFunc

SecureValidatorFunc wraps a call to f(password) and recovers from any panic that might occur, it's advised to always use SecureValidatorFunc if dealing with raw validator functions. But validator functions retrieved from GuessValidatorFunc are already wrapped by SecureValidatorFunc. f is not allowed to be nil.

type VersionError

type VersionError struct {
	Prefix        string
	Expected, Got string
}

VersionError is an error returned if the version of a hashes version is not compatible with the library.

func NewVersionError

func NewVersionError(prefix, expected, got string) VersionError

NewVersionError returns a new VersionError. Prefix is appended to the error message, expected and got describe the the version execpted resp. found.

func (VersionError) Error

func (err VersionError) Error() string

Error returns the string representation of the error.

func (VersionError) String

func (err VersionError) String() string

String returns the string representation of the error.

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

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