mirror of
https://gogs.blitter.com/RLabs/xs
synced 2024-08-14 10:26:42 +00:00
1/3 Updated Makefile to allow VENDOR flag (adds -vendor to version string)
2/3 Added vendor/ dir to lock down dependent pkg versions. The author of git.schwanenlied.me/yawning/{chacha20,newhope,kyber}.git has copied their repos to gitlab.com/yawning/ but some imports of chacha20 from newhope still inconsistently refer to git.schwanenlied.me/, breaking build. Licenses for chacha20 also changed from CC0 to AGPL, which may or may not be an issue. Until the two aforementioned issues are resolved, locking to last-good versions is probably the best way forward for now. To build with vendored deps, use make VENDOR=1 clean all 3/3 Moved body of CI push script into bacillus/
This commit is contained in:
parent
7fe915450b
commit
f5be3578a8
854 changed files with 287417 additions and 7 deletions
12
vendor/gopkg.in/hlandau/passlib.v1/.travis.yml
generated
vendored
Normal file
12
vendor/gopkg.in/hlandau/passlib.v1/.travis.yml
generated
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
language: go
|
||||
os:
|
||||
- linux
|
||||
go:
|
||||
- 1.10
|
||||
- tip
|
||||
sudo: false
|
||||
install:
|
||||
- mkdir -p $HOME/gopath/src/gopkg.in/hlandau/
|
||||
- ln -s $TRAVIS_BUILD_DIR $HOME/gopath/src/gopkg.in/hlandau/passlib.v1
|
||||
- cd $HOME/gopath/src/gopkg.in/hlandau/passlib.v1
|
||||
- go get
|
39
vendor/gopkg.in/hlandau/passlib.v1/COPYING
generated
vendored
Normal file
39
vendor/gopkg.in/hlandau/passlib.v1/COPYING
generated
vendored
Normal file
|
@ -0,0 +1,39 @@
|
|||
passlib is a Golang password verification library strongly inspired by and
|
||||
derived from Python passlib (<https://pypi.python.org/pypi/passlib>). The BSD
|
||||
license is preserved and extended to all new code.
|
||||
|
||||
License for Passlib
|
||||
===================
|
||||
Passlib is (c) `Assurance Technologies <http://www.assurancetechnologies.com>`_,
|
||||
and is released under the `BSD license <http://www.opensource.org/licenses/bsd-license.php>`_::
|
||||
|
||||
Passlib
|
||||
Copyright (c) 2008-2012 Assurance Technologies, LLC.
|
||||
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 Assurance Technologies, nor the names of the
|
||||
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.
|
100
vendor/gopkg.in/hlandau/passlib.v1/README.md
generated
vendored
Normal file
100
vendor/gopkg.in/hlandau/passlib.v1/README.md
generated
vendored
Normal file
|
@ -0,0 +1,100 @@
|
|||
passlib for go
|
||||
==============
|
||||
|
||||
[](https://godoc.org/gopkg.in/hlandau/passlib.v1) [](https://travis-ci.org/hlandau/passlib)
|
||||
|
||||
[Python's passlib](https://pythonhosted.org/passlib/) is quite an amazing
|
||||
library. I'm not sure there's a password library in existence with more thought
|
||||
put into it, or with more support for obscure password formats.
|
||||
|
||||
This is a skeleton of a port of passlib to Go. It dogmatically adopts the
|
||||
modular crypt format, which [passlib has excellent documentation for](https://pythonhosted.org/passlib/modular_crypt_format.html#modular-crypt-format).
|
||||
|
||||
Currently, it supports:
|
||||
|
||||
- sha256-crypt
|
||||
- sha512-crypt
|
||||
- scrypt-sha256
|
||||
- bcrypt
|
||||
- passlib's bcrypt-sha256 variant
|
||||
- pbkdf2-sha1 (in passlib format)
|
||||
- pbkdf2-sha256 (in passlib format)
|
||||
- pbkdf2-sha512 (in passlib format)
|
||||
|
||||
By default, it will hash using scrypt-sha256 and verify existing hashes using
|
||||
any of these schemes.
|
||||
|
||||
Example Usage
|
||||
-------------
|
||||
There's a default context for ease of use. Most people need only concern
|
||||
themselves with the functions `Hash` and `Verify`:
|
||||
|
||||
```go
|
||||
// Hash a plaintext, UTF-8 password.
|
||||
func Hash(password string) (hash string, err error)
|
||||
|
||||
// Verifies a plaintext, UTF-8 password using a previously derived hash.
|
||||
// Returns non-nil err if verification fails.
|
||||
//
|
||||
// Also returns an upgraded password hash if the hash provided is
|
||||
// deprecated.
|
||||
func Verify(password, hash string) (newHash string, err error)
|
||||
```
|
||||
|
||||
Here's a rough skeleton of typical usage.
|
||||
|
||||
```go
|
||||
import "gopkg.in/hlandau/passlib.v1"
|
||||
|
||||
func RegisterUser() {
|
||||
(...)
|
||||
|
||||
password := get a (UTF-8, plaintext) password from somewhere
|
||||
|
||||
hash, err := passlib.Hash(password)
|
||||
if err != nil {
|
||||
// couldn't hash password for some reason
|
||||
return
|
||||
}
|
||||
|
||||
(store hash in database, etc.)
|
||||
}
|
||||
|
||||
func CheckPassword() bool {
|
||||
password := get the password the user entered
|
||||
hash := the hash you stored from the call to Hash()
|
||||
|
||||
newHash, err := passlib.Verify(password, hash)
|
||||
if err != nil {
|
||||
// incorrect password, malformed hash, etc.
|
||||
// either way, reject
|
||||
return false
|
||||
}
|
||||
|
||||
// The context has decided, as per its policy, that
|
||||
// the hash which was used to validate the password
|
||||
// should be changed. It has upgraded the hash using
|
||||
// the verified password.
|
||||
if newHash != "" {
|
||||
(store newHash in database, replacing old hash)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
```
|
||||
|
||||
scrypt Modular Crypt Format
|
||||
---------------------------
|
||||
Since scrypt does not have a pre-existing modular crypt format standard, I made one. It's as follows:
|
||||
|
||||
$s2$N$r$p$salt$hash
|
||||
|
||||
...where `N`, `r` and `p` are the respective difficulty parameters to scrypt as positive decimal integers without leading zeroes, and `salt` and `hash` are base64-encoded binary strings. Note that the RFC 4648 base64 encoding is used (not the one used by sha256-crypt and sha512-crypt).
|
||||
|
||||
Licence
|
||||
-------
|
||||
passlib is partially derived from Python's passlib and so maintains its BSD license.
|
||||
|
||||
© 2008-2012 Assurance Technologies LLC. (Python passlib) BSD License
|
||||
© 2014 Hugo Landau <hlandau@devever.net> BSD License
|
||||
|
11
vendor/gopkg.in/hlandau/passlib.v1/abstract/compare.go
generated
vendored
Normal file
11
vendor/gopkg.in/hlandau/passlib.v1/abstract/compare.go
generated
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
package abstract
|
||||
|
||||
import "crypto/subtle"
|
||||
|
||||
// Compares two strings (typicaly password hashes) in a secure, constant-time
|
||||
// fashion. Returns true iff they are equal.
|
||||
func SecureCompare(a, b string) bool {
|
||||
ab := []byte(a)
|
||||
bb := []byte(b)
|
||||
return subtle.ConstantTimeCompare(ab, bb) == 1
|
||||
}
|
15
vendor/gopkg.in/hlandau/passlib.v1/abstract/errors.go
generated
vendored
Normal file
15
vendor/gopkg.in/hlandau/passlib.v1/abstract/errors.go
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
// Package abstract contains the abstract description of the Scheme interface,
|
||||
// plus supporting error definitions.
|
||||
package abstract
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Indicates that password verification failed because the provided password
|
||||
// does not match the provided hash.
|
||||
var ErrInvalidPassword = fmt.Errorf("invalid password")
|
||||
|
||||
// Indicates that password verification is not possible because the hashing
|
||||
// scheme used by the hash provided is not supported.
|
||||
var ErrUnsupportedScheme = fmt.Errorf("unsupported scheme")
|
||||
|
||||
// © 2014 Hugo Landau <hlandau@devever.net> MIT License
|
34
vendor/gopkg.in/hlandau/passlib.v1/abstract/scheme.go
generated
vendored
Normal file
34
vendor/gopkg.in/hlandau/passlib.v1/abstract/scheme.go
generated
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
package abstract
|
||||
|
||||
// The Scheme interface provides an abstract interface to an implementation
|
||||
// of a particular password hashing scheme. The Scheme generates password
|
||||
// hashes from passwords, verifies passwords using password hashes, randomly
|
||||
// generates new stubs and can determines whether it recognises a given
|
||||
// stub or hash. It may also decide to issue upgrades.
|
||||
type Scheme interface {
|
||||
// Hashes a plaintext UTF-8 password using a modular crypt stub. Returns the
|
||||
// hashed password in modular crypt format.
|
||||
//
|
||||
// A modular crypt stub is a prefix of a hash in modular crypt format which
|
||||
// expresses all necessary configuration information, such as salt and
|
||||
// iteration count. For example, for sha256-crypt, a valid stub would be:
|
||||
//
|
||||
// $5$rounds=6000$salt
|
||||
//
|
||||
// A full modular crypt hash may also be passed as the stub, in which case
|
||||
// the hash is ignored.
|
||||
Hash(password string) (string, error)
|
||||
|
||||
// Verifies a plaintext UTF-8 password using a modular crypt hash. Returns
|
||||
// an error if the inputs are malformed or the password does not match.
|
||||
Verify(password, hash string) (err error)
|
||||
|
||||
// Returns true iff this crypter supports the given stub.
|
||||
SupportsStub(stub string) bool
|
||||
|
||||
// Returns true iff this stub needs an update.
|
||||
NeedsUpdate(stub string) bool
|
||||
|
||||
// Make a stub with the configured defaults. The salt is generated randomly.
|
||||
//MakeStub() (string, error)
|
||||
}
|
141
vendor/gopkg.in/hlandau/passlib.v1/default.go
generated
vendored
Normal file
141
vendor/gopkg.in/hlandau/passlib.v1/default.go
generated
vendored
Normal file
|
@ -0,0 +1,141 @@
|
|||
package passlib
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"gopkg.in/hlandau/passlib.v1/abstract"
|
||||
"gopkg.in/hlandau/passlib.v1/hash/argon2"
|
||||
"gopkg.in/hlandau/passlib.v1/hash/bcrypt"
|
||||
"gopkg.in/hlandau/passlib.v1/hash/bcryptsha256"
|
||||
"gopkg.in/hlandau/passlib.v1/hash/pbkdf2"
|
||||
"gopkg.in/hlandau/passlib.v1/hash/scrypt"
|
||||
"gopkg.in/hlandau/passlib.v1/hash/sha2crypt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// This is the first and default set of defaults used by passlib. It prefers
|
||||
// scrypt-sha256. It is now obsolete.
|
||||
const Defaults20160922 = "20160922"
|
||||
|
||||
// This is the most up-to-date set of defaults preferred by passlib. It prefers
|
||||
// Argon2i. You must opt into it by calling UseDefaults at startup.
|
||||
const Defaults20180601 = "20180601"
|
||||
|
||||
// This value, when passed to UseDefaults, causes passlib to always use the
|
||||
// very latest set of defaults. DO NOT use this unless you are sure that
|
||||
// opportunistic hash upgrades will not cause breakage for your application
|
||||
// when future versions of passlib are released. See func UseDefaults.
|
||||
const DefaultsLatest = "latest"
|
||||
|
||||
// Default schemes as of 2016-09-22.
|
||||
var defaultSchemes20160922 = []abstract.Scheme{
|
||||
scrypt.SHA256Crypter,
|
||||
argon2.Crypter,
|
||||
sha2crypt.Crypter512,
|
||||
sha2crypt.Crypter256,
|
||||
bcryptsha256.Crypter,
|
||||
pbkdf2.SHA512Crypter,
|
||||
pbkdf2.SHA256Crypter,
|
||||
bcrypt.Crypter,
|
||||
pbkdf2.SHA1Crypter,
|
||||
}
|
||||
|
||||
// Default schemes as of 2018-06-01.
|
||||
var defaultSchemes20180601 = []abstract.Scheme{
|
||||
argon2.Crypter,
|
||||
scrypt.SHA256Crypter,
|
||||
sha2crypt.Crypter512,
|
||||
sha2crypt.Crypter256,
|
||||
bcryptsha256.Crypter,
|
||||
pbkdf2.SHA512Crypter,
|
||||
pbkdf2.SHA256Crypter,
|
||||
bcrypt.Crypter,
|
||||
pbkdf2.SHA1Crypter,
|
||||
}
|
||||
|
||||
// The default schemes, most preferred first. The first scheme will be used to
|
||||
// hash passwords, and any of the schemes may be used to verify existing
|
||||
// passwords. The contents of this value may change with subsequent releases.
|
||||
//
|
||||
// If you want to change this, set DefaultSchemes to a slice to an
|
||||
// abstract.Scheme array of your own construction, rather than mutating the
|
||||
// array the slice points to.
|
||||
//
|
||||
// To see the default schemes used in the current release of passlib, see
|
||||
// default.go. See also the UseDefaults function for more information on how
|
||||
// the list of default schemes is determined. The default value of
|
||||
// DefaultSchemes (the default defaults) won't change; you need to call
|
||||
// UseDefaults to allow your application to upgrade to newer hashing schemes
|
||||
// (or set DefaultSchemes manually, or create a custom context with its own
|
||||
// schemes set).
|
||||
var DefaultSchemes []abstract.Scheme
|
||||
|
||||
func init() {
|
||||
DefaultSchemes = defaultSchemes20160922
|
||||
}
|
||||
|
||||
// It is strongly recommended that you call this function like this before using passlib:
|
||||
//
|
||||
// passlib.UseDefaults("YYYYMMDD")
|
||||
//
|
||||
// where YYYYMMDD is a date. This will be used to select the preferred scheme
|
||||
// to use. If you do not call UseDefaults, the preferred scheme (the first item
|
||||
// in the default schemes list) current as of 2016-09-22 will always be used,
|
||||
// meaning that upgrade will not occur even though better schemes are now
|
||||
// available.
|
||||
//
|
||||
// Note that even if you don't call this function, new schemes will still be
|
||||
// added to DefaultSchemes over time as non-initial values (items not at index
|
||||
// 0), so servers will always, by default, be able to validate all schemes
|
||||
// which passlib supports at any given time.
|
||||
//
|
||||
// The reason you must call this function is as follows: If passlib is deployed
|
||||
// as part of a web application in a multi-server deployment, and passlib is
|
||||
// updated, and the new version of that application with the updated passlib is
|
||||
// deployed, that upgrade process is unlikely to be instantaneous. Old versions
|
||||
// of the web application may continue to run on some servers. If merely
|
||||
// upgrading passlib caused password hashes to be upgraded to the newer scheme
|
||||
// on login, the older daemons may not be able to validate these passwords and
|
||||
// users may have issues logging in. Although this can be ameliorated to some
|
||||
// extent by introducing a new scheme to passlib, waiting some months, and only
|
||||
// then making this the default, this could still cause issued if passlib is
|
||||
// only updated very occasionally.
|
||||
//
|
||||
// Thus, you should update your call to UseDefaults only when all servers have
|
||||
// been upgraded, and it is thus guaranteed that they will all be able to
|
||||
// verify the new scheme. Making this value loadable from a configuration file
|
||||
// is recommended.
|
||||
//
|
||||
// If you are using a single-server configuration, you can use the special
|
||||
// value "latest" here (or, equivalently, a date far into the future), which
|
||||
// will always use the most preferred scheme. This is hazardous in a
|
||||
// multi-server environment.
|
||||
//
|
||||
// The constants beginning 'Defaults' in this package document dates
|
||||
// which are meaningful to this function. The constant values they are equal to
|
||||
// will never change, so there is no need to use them instead of string
|
||||
// literals, although you may if you wish; they are intended mainly as
|
||||
// documentation as to the significance of various dates.
|
||||
//
|
||||
// Example for opting in to the latest set of defaults:
|
||||
//
|
||||
// passlib.UseDefaults(passlib.Defaults20180601)
|
||||
//
|
||||
func UseDefaults(date string) error {
|
||||
if date == "latest" {
|
||||
DefaultSchemes = defaultSchemes20180601
|
||||
return nil
|
||||
}
|
||||
|
||||
t, err := time.ParseInLocation("20060102", date, time.UTC)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid time string passed to passlib.UseDefaults: %q", date)
|
||||
}
|
||||
|
||||
if !t.Before(time.Date(2016, 9, 22, 0, 0, 0, 0, time.UTC)) {
|
||||
DefaultSchemes = defaultSchemes20180601
|
||||
return nil
|
||||
}
|
||||
|
||||
DefaultSchemes = defaultSchemes20160922
|
||||
return nil
|
||||
}
|
115
vendor/gopkg.in/hlandau/passlib.v1/hash/argon2/argon2.go
generated
vendored
Normal file
115
vendor/gopkg.in/hlandau/passlib.v1/hash/argon2/argon2.go
generated
vendored
Normal file
|
@ -0,0 +1,115 @@
|
|||
// Package argon2 implements the argon2 password hashing mechanism, wrapped in
|
||||
// the argon2 encoded format.
|
||||
package argon2
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/crypto/argon2"
|
||||
"gopkg.in/hlandau/passlib.v1/abstract"
|
||||
"gopkg.in/hlandau/passlib.v1/hash/argon2/raw"
|
||||
)
|
||||
|
||||
// An implementation of Scheme performing argon2 hashing.
|
||||
//
|
||||
// Uses the recommended values for time, memory and threads defined in raw.
|
||||
var Crypter abstract.Scheme
|
||||
|
||||
const saltLength = 16
|
||||
|
||||
func init() {
|
||||
Crypter = New(
|
||||
raw.RecommendedTime,
|
||||
raw.RecommendedMemory,
|
||||
raw.RecommendedThreads,
|
||||
)
|
||||
}
|
||||
|
||||
// Returns an implementation of Scheme implementing argon2
|
||||
// with the specified parameters.
|
||||
func New(time, memory uint32, threads uint8) abstract.Scheme {
|
||||
return &scheme{
|
||||
time: time,
|
||||
memory: memory,
|
||||
threads: threads,
|
||||
}
|
||||
}
|
||||
|
||||
type scheme struct {
|
||||
time, memory uint32
|
||||
threads uint8
|
||||
}
|
||||
|
||||
func (c *scheme) SetParams(time, memory uint32, threads uint8) error {
|
||||
c.time = time
|
||||
c.memory = memory
|
||||
c.threads = threads
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *scheme) SupportsStub(stub string) bool {
|
||||
return strings.HasPrefix(stub, "$argon2i$")
|
||||
}
|
||||
|
||||
func (c *scheme) Hash(password string) (string, error) {
|
||||
|
||||
stub, err := c.makeStub()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
_, newHash, _, _, _, _, _, err := c.hash(password, stub)
|
||||
return newHash, err
|
||||
}
|
||||
|
||||
func (c *scheme) Verify(password, hash string) (err error) {
|
||||
|
||||
_, newHash, _, _, _, _, _, err := c.hash(password, hash)
|
||||
if err == nil && !abstract.SecureCompare(hash, newHash) {
|
||||
err = abstract.ErrInvalidPassword
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (c *scheme) NeedsUpdate(stub string) bool {
|
||||
salt, _, version, time, memory, threads, err := raw.Parse(stub)
|
||||
if err != nil {
|
||||
return false // ...
|
||||
}
|
||||
|
||||
return c.needsUpdate(salt, version, time, memory, threads)
|
||||
}
|
||||
|
||||
func (c *scheme) needsUpdate(salt []byte, version int, time, memory uint32, threads uint8) bool {
|
||||
return len(salt) < saltLength || version < argon2.Version || time < c.time || memory < c.memory || threads < c.threads
|
||||
}
|
||||
|
||||
func (c *scheme) hash(password, stub string) (oldHashRaw []byte, newHash string, salt []byte, version int, memory, time uint32, threads uint8, err error) {
|
||||
|
||||
salt, oldHashRaw, version, time, memory, threads, err = raw.Parse(stub)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return oldHashRaw, raw.Argon2(password, salt, time, memory, threads), salt, version, memory, time, threads, nil
|
||||
}
|
||||
|
||||
func (c *scheme) makeStub() (string, error) {
|
||||
buf := make([]byte, saltLength)
|
||||
_, err := rand.Read(buf)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
salt := base64.RawStdEncoding.EncodeToString(buf)
|
||||
|
||||
return fmt.Sprintf("$argon2i$v=%d$m=%d,t=%d,p=%d$%s$", argon2.Version, c.memory, c.time, c.threads, salt), nil
|
||||
}
|
||||
|
||||
func (c *scheme) String() string {
|
||||
return fmt.Sprintf("argon2(%d,%d,%d,%d)", argon2.Version, c.memory, c.time, c.threads)
|
||||
}
|
186
vendor/gopkg.in/hlandau/passlib.v1/hash/argon2/raw/argon2.go
generated
vendored
Normal file
186
vendor/gopkg.in/hlandau/passlib.v1/hash/argon2/raw/argon2.go
generated
vendored
Normal file
|
@ -0,0 +1,186 @@
|
|||
// Package raw provides a raw implementation of the modular-crypt-wrapped Argon2i primitive.
|
||||
package raw
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"golang.org/x/crypto/argon2"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// The current recommended time value for interactive logins.
|
||||
const RecommendedTime uint32 = 4
|
||||
|
||||
// The current recommended memory for interactive logins.
|
||||
const RecommendedMemory uint32 = 32 * 1024
|
||||
|
||||
// The current recommended number of threads for interactive logins.
|
||||
const RecommendedThreads uint8 = 4
|
||||
|
||||
// Wrapper for golang.org/x/crypto/argon2 implementing a sensible
|
||||
// hashing interface.
|
||||
//
|
||||
// password should be a UTF-8 plaintext password.
|
||||
// salt should be a random salt value in binary form.
|
||||
//
|
||||
// Time, memory, and threads are parameters to argon2.
|
||||
//
|
||||
// Returns an argon2 encoded hash.
|
||||
func Argon2(password string, salt []byte, time, memory uint32, threads uint8) string {
|
||||
passwordb := []byte(password)
|
||||
|
||||
hash := argon2.Key(passwordb, salt, time, memory, threads, 32)
|
||||
|
||||
hstr := base64.RawStdEncoding.EncodeToString(hash)
|
||||
sstr := base64.RawStdEncoding.EncodeToString(salt)
|
||||
|
||||
return fmt.Sprintf("$argon2i$v=%d$m=%d,t=%d,p=%d$%s$%s", argon2.Version, memory, time, threads, sstr, hstr)
|
||||
}
|
||||
|
||||
// Indicates that a password hash or stub is invalid.
|
||||
var ErrInvalidStub = fmt.Errorf("invalid argon2 password stub")
|
||||
|
||||
// Indicates that a key-value pair in the configuration part is malformed.
|
||||
var ErrInvalidKeyValuePair = fmt.Errorf("invalid argon2 key-value pair")
|
||||
|
||||
// Indicates that the version part had the wrong number of parameters.
|
||||
var ErrParseVersion = fmt.Errorf("version section has wrong number of parameters")
|
||||
|
||||
// Indicates that the hash config part had the wrong number of parameters.
|
||||
var ErrParseConfig = fmt.Errorf("hash config section has wrong number of parameters")
|
||||
|
||||
// Indicates that the version parameter ("v") was missing in the version part,
|
||||
// even though it is required.
|
||||
var ErrMissingVersion = fmt.Errorf("version parameter (v) is missing")
|
||||
|
||||
// Indicates that the memory parameter ("m") was mossing in the hash config
|
||||
// part, even though it is required.
|
||||
var ErrMissingMemory = fmt.Errorf("memory parameter (m) is missing")
|
||||
|
||||
// Indicates that the time parameter ("t") was mossing in the hash config part,
|
||||
// even though it is required.
|
||||
var ErrMissingTime = fmt.Errorf("time parameter (t) is missing")
|
||||
|
||||
// Indicates that the parallelism parameter ("p") was mossing in the hash config
|
||||
// part, even though it is required.
|
||||
var ErrMissingParallelism = fmt.Errorf("parallelism parameter (p) is missing")
|
||||
|
||||
// Parses an argon2 encoded hash.
|
||||
//
|
||||
// The format is as follows:
|
||||
//
|
||||
// $argon2i$v=version$m=memory,t=time,p=threads$salt$hash // hash
|
||||
// $argon2i$v=version$m=memory,t=time,p=threads$salt // stub
|
||||
//
|
||||
func Parse(stub string) (salt, hash []byte, version int, time, memory uint32, parallelism uint8, err error) {
|
||||
if len(stub) < 26 || !strings.HasPrefix(stub, "$argon2i$") {
|
||||
err = ErrInvalidStub
|
||||
return
|
||||
}
|
||||
|
||||
// $argon2i$ v=version$m=memory,t=time,p=threads$salt-base64$hash-base64
|
||||
parts := strings.Split(stub[9:], "$")
|
||||
|
||||
// version-params$hash-config-params$salt[$hash]
|
||||
if len(parts) < 3 || len(parts) > 4 {
|
||||
err = ErrInvalidStub
|
||||
return
|
||||
}
|
||||
|
||||
// Parse the first configuration part, the version parameters.
|
||||
versionParams, err := parseKeyValuePair(parts[0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Must be exactly one parameter in the version part.
|
||||
if len(versionParams) != 1 {
|
||||
err = ErrParseVersion
|
||||
return
|
||||
}
|
||||
|
||||
// It must be "v".
|
||||
val, ok := versionParams["v"]
|
||||
if !ok {
|
||||
err = ErrMissingVersion
|
||||
return
|
||||
}
|
||||
|
||||
version = int(val)
|
||||
|
||||
// Parse the second configuration part, the hash config parameters.
|
||||
hashParams, err := parseKeyValuePair(parts[1])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// It must have exactly three parameters.
|
||||
if len(hashParams) != 3 {
|
||||
err = ErrParseConfig
|
||||
return
|
||||
}
|
||||
|
||||
// Memory parameter.
|
||||
val, ok = hashParams["m"]
|
||||
if !ok {
|
||||
err = ErrMissingMemory
|
||||
return
|
||||
}
|
||||
|
||||
memory = uint32(val)
|
||||
|
||||
// Time parameter.
|
||||
val, ok = hashParams["t"]
|
||||
if !ok {
|
||||
err = ErrMissingTime
|
||||
return
|
||||
}
|
||||
|
||||
time = uint32(val)
|
||||
|
||||
// Parallelism parameter.
|
||||
val, ok = hashParams["p"]
|
||||
if !ok {
|
||||
err = ErrMissingParallelism
|
||||
return
|
||||
}
|
||||
|
||||
parallelism = uint8(val)
|
||||
|
||||
// Decode salt.
|
||||
salt, err = base64.RawStdEncoding.DecodeString(parts[2])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Decode hash if present.
|
||||
if len(parts) >= 4 {
|
||||
hash, err = base64.RawStdEncoding.DecodeString(parts[3])
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func parseKeyValuePair(pairs string) (result map[string]uint64, err error) {
|
||||
result = map[string]uint64{}
|
||||
|
||||
parameterParts := strings.Split(pairs, ",")
|
||||
|
||||
for _, parameter := range parameterParts {
|
||||
parts := strings.SplitN(parameter, "=", 2)
|
||||
if len(parts) != 2 {
|
||||
err = ErrInvalidKeyValuePair
|
||||
return
|
||||
}
|
||||
|
||||
parsedi, err := strconv.ParseUint(parts[1], 10, 32)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
result[parts[0]] = parsedi
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
72
vendor/gopkg.in/hlandau/passlib.v1/hash/bcrypt/bcrypt.go
generated
vendored
Normal file
72
vendor/gopkg.in/hlandau/passlib.v1/hash/bcrypt/bcrypt.go
generated
vendored
Normal file
|
@ -0,0 +1,72 @@
|
|||
// Package bcrypt implements the bcrypt password hashing mechanism.
|
||||
//
|
||||
// Please note that bcrypt truncates passwords to 72 characters in length. Consider using
|
||||
// a more modern hashing scheme such as scrypt or sha-crypt. If you must use bcrypt,
|
||||
// consider using bcrypt-sha256 instead.
|
||||
package bcrypt
|
||||
|
||||
import "golang.org/x/crypto/bcrypt"
|
||||
import "gopkg.in/hlandau/passlib.v1/abstract"
|
||||
import "fmt"
|
||||
|
||||
// An implementation of Scheme implementing bcrypt.
|
||||
//
|
||||
// Uses RecommendedCost.
|
||||
var Crypter abstract.Scheme
|
||||
|
||||
// The recommended cost for bcrypt. This may change with subsequent releases.
|
||||
const RecommendedCost = 12
|
||||
|
||||
// bcrypt.DefaultCost is a bit low (10), so use 12 instead.
|
||||
|
||||
func init() {
|
||||
Crypter = New(RecommendedCost)
|
||||
}
|
||||
|
||||
// Create a new scheme implementing bcrypt. The recommended cost is RecommendedCost.
|
||||
func New(cost int) abstract.Scheme {
|
||||
return &scheme{
|
||||
Cost: cost,
|
||||
}
|
||||
}
|
||||
|
||||
type scheme struct {
|
||||
Cost int
|
||||
}
|
||||
|
||||
func (s *scheme) SupportsStub(stub string) bool {
|
||||
return len(stub) >= 3 && stub[0] == '$' && stub[1] == '2' &&
|
||||
(stub[2] == '$' || (len(stub) >= 4 && stub[3] == '$' &&
|
||||
(stub[2] == 'a' || stub[2] == 'b' || stub[2] == 'y')))
|
||||
}
|
||||
|
||||
func (s *scheme) Hash(password string) (string, error) {
|
||||
h, err := bcrypt.GenerateFromPassword([]byte(password), s.Cost)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(h), nil
|
||||
}
|
||||
|
||||
func (s *scheme) Verify(password, hash string) error {
|
||||
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
|
||||
if err == bcrypt.ErrMismatchedHashAndPassword {
|
||||
err = abstract.ErrInvalidPassword
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *scheme) NeedsUpdate(stub string) bool {
|
||||
cost, err := bcrypt.Cost([]byte(stub))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return cost < s.Cost
|
||||
}
|
||||
|
||||
func (s *scheme) String() string {
|
||||
return fmt.Sprintf("bcrypt(%d)", s.Cost)
|
||||
}
|
96
vendor/gopkg.in/hlandau/passlib.v1/hash/bcryptsha256/bcryptsha256.go
generated
vendored
Normal file
96
vendor/gopkg.in/hlandau/passlib.v1/hash/bcryptsha256/bcryptsha256.go
generated
vendored
Normal file
|
@ -0,0 +1,96 @@
|
|||
// Package bcryptsha256 implements bcrypt with a SHA256 prehash in a format that is compatible with Python passlib's equivalent bcrypt-sha256 scheme.
|
||||
//
|
||||
// This is preferred over bcrypt because the prehash essentially renders bcrypt's password length
|
||||
// limitation irrelevant; although of course it is less compatible.
|
||||
package bcryptsha256
|
||||
|
||||
import "gopkg.in/hlandau/passlib.v1/abstract"
|
||||
import "gopkg.in/hlandau/passlib.v1/hash/bcrypt"
|
||||
import "encoding/base64"
|
||||
import "crypto/sha256"
|
||||
import "strings"
|
||||
import "fmt"
|
||||
|
||||
type scheme struct {
|
||||
underlying abstract.Scheme
|
||||
cost int
|
||||
}
|
||||
|
||||
// An implementation of Scheme implementing Python passlib's `$bcrypt-sha256$`
|
||||
// bcrypt variant. This is bcrypt with a SHA256 prehash, which removes bcrypt's
|
||||
// password length limitation.
|
||||
var Crypter abstract.Scheme
|
||||
|
||||
// The recommended cost for bcrypt-sha256. This may change with subsequent releases.
|
||||
const RecommendedCost = bcrypt.RecommendedCost
|
||||
|
||||
func init() {
|
||||
Crypter = New(bcrypt.RecommendedCost)
|
||||
}
|
||||
|
||||
// Instantiates a new Scheme implementing bcrypt with the given cost.
|
||||
//
|
||||
// The recommended cost is RecommendedCost.
|
||||
func New(cost int) abstract.Scheme {
|
||||
return &scheme{
|
||||
underlying: bcrypt.New(cost),
|
||||
cost: cost,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *scheme) Hash(password string) (string, error) {
|
||||
p := s.prehash(password)
|
||||
h, err := s.underlying.Hash(p)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return mangle(h), nil
|
||||
}
|
||||
|
||||
func (s *scheme) Verify(password, hash string) error {
|
||||
p := s.prehash(password)
|
||||
return s.underlying.Verify(p, demangle(hash))
|
||||
}
|
||||
|
||||
func (s *scheme) prehash(password string) string {
|
||||
h := sha256.New()
|
||||
h.Write([]byte(password))
|
||||
v := base64.StdEncoding.EncodeToString(h.Sum(nil))
|
||||
return v
|
||||
}
|
||||
|
||||
func (s *scheme) SupportsStub(stub string) bool {
|
||||
return strings.HasPrefix(stub, "$bcrypt-sha256$") && s.underlying.SupportsStub(demangle(stub))
|
||||
}
|
||||
|
||||
func (s *scheme) NeedsUpdate(stub string) bool {
|
||||
return s.underlying.NeedsUpdate(demangle(stub))
|
||||
}
|
||||
|
||||
func (s *scheme) String() string {
|
||||
return fmt.Sprintf("bcrypt-sha256(%d)", s.cost)
|
||||
}
|
||||
|
||||
func demangle(stub string) string {
|
||||
if strings.HasPrefix(stub, "$bcrypt-sha256$2") {
|
||||
parts := strings.Split(stub[15:], "$")
|
||||
// 0: 2a,12
|
||||
// 1: salt
|
||||
// 2: hash
|
||||
parts0 := strings.Split(parts[0], ",")
|
||||
return "$" + parts0[0] + "$" + fmt.Sprintf("%02s", parts0[1]) + "$" + parts[1] + parts[2]
|
||||
} else {
|
||||
return stub
|
||||
}
|
||||
}
|
||||
|
||||
func mangle(hash string) string {
|
||||
parts := strings.Split(hash[1:], "$")
|
||||
// 0: 2a
|
||||
// 1: rounds
|
||||
// 2: salt + hash
|
||||
salt := parts[2][0:22]
|
||||
h := parts[2][22:]
|
||||
return "$bcrypt-sha256$" + parts[0] + "," + parts[1] + "$" + salt + "$" + h
|
||||
}
|
94
vendor/gopkg.in/hlandau/passlib.v1/hash/pbkdf2/pbkdf2.go
generated
vendored
Normal file
94
vendor/gopkg.in/hlandau/passlib.v1/hash/pbkdf2/pbkdf2.go
generated
vendored
Normal file
|
@ -0,0 +1,94 @@
|
|||
// Package pbkdf2 implements a modular crypt format for PBKDF2-SHA1,
|
||||
// PBKDF2-SHA256 and PBKDF-SHA512.
|
||||
//
|
||||
// The format is the same as that used by Python's passlib and is compatible.
|
||||
package pbkdf2
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"fmt"
|
||||
"gopkg.in/hlandau/passlib.v1/abstract"
|
||||
"gopkg.in/hlandau/passlib.v1/hash/pbkdf2/raw"
|
||||
"hash"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// An implementation of Scheme implementing a number of PBKDF2 modular crypt
|
||||
// formats used by Python's passlib ($pbkdf2$, $pbkdf2-sha256$,
|
||||
// $pbkdf2-sha512$).
|
||||
//
|
||||
// Uses RecommendedRounds.
|
||||
//
|
||||
// WARNING: SHA1 should not be used for new applications under any
|
||||
// circumstances. It should be used for legacy compatibility only.
|
||||
var SHA1Crypter abstract.Scheme
|
||||
var SHA256Crypter abstract.Scheme
|
||||
var SHA512Crypter abstract.Scheme
|
||||
|
||||
const (
|
||||
RecommendedRoundsSHA1 = 131000
|
||||
RecommendedRoundsSHA256 = 29000
|
||||
RecommendedRoundsSHA512 = 25000
|
||||
)
|
||||
|
||||
const SaltLength = 16
|
||||
|
||||
func init() {
|
||||
SHA1Crypter = New("$pbkdf2$", sha1.New, RecommendedRoundsSHA1)
|
||||
SHA256Crypter = New("$pbkdf2-sha256$", sha256.New, RecommendedRoundsSHA256)
|
||||
SHA512Crypter = New("$pbkdf2-sha512$", sha512.New, RecommendedRoundsSHA512)
|
||||
}
|
||||
|
||||
type scheme struct {
|
||||
Ident string
|
||||
HashFunc func() hash.Hash
|
||||
Rounds int
|
||||
}
|
||||
|
||||
func New(ident string, hf func() hash.Hash, rounds int) abstract.Scheme {
|
||||
return &scheme{
|
||||
Ident: ident,
|
||||
HashFunc: hf,
|
||||
Rounds: rounds,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *scheme) Hash(password string) (string, error) {
|
||||
salt := make([]byte, SaltLength)
|
||||
_, err := rand.Read(salt)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
hash := raw.Hash([]byte(password), salt, s.Rounds, s.HashFunc)
|
||||
|
||||
newHash := fmt.Sprintf("%s%d$%s$%s", s.Ident, s.Rounds, raw.Base64Encode(salt), hash)
|
||||
return newHash, nil
|
||||
}
|
||||
|
||||
func (s *scheme) Verify(password, stub string) (err error) {
|
||||
_, rounds, salt, oldHash, err := raw.Parse(stub)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
newHash := raw.Hash([]byte(password), salt, rounds, s.HashFunc)
|
||||
|
||||
if len(newHash) == 0 || !abstract.SecureCompare(oldHash, newHash) {
|
||||
err = abstract.ErrInvalidPassword
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (s *scheme) SupportsStub(stub string) bool {
|
||||
return strings.HasPrefix(stub, s.Ident)
|
||||
}
|
||||
|
||||
func (s *scheme) NeedsUpdate(stub string) bool {
|
||||
_, rounds, salt, _, err := raw.Parse(stub)
|
||||
return err == raw.ErrInvalidRounds || rounds < s.Rounds || len(salt) < SaltLength
|
||||
}
|
20
vendor/gopkg.in/hlandau/passlib.v1/hash/pbkdf2/raw/base64.go
generated
vendored
Normal file
20
vendor/gopkg.in/hlandau/passlib.v1/hash/pbkdf2/raw/base64.go
generated
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
package raw
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var b64 = base64.RawStdEncoding
|
||||
|
||||
func Base64Encode(src []byte) (dst string) {
|
||||
dst = b64.EncodeToString(src)
|
||||
dst = strings.Replace(dst, "+", ".", -1)
|
||||
return
|
||||
}
|
||||
|
||||
func Base64Decode(src string) (dst []byte, err error) {
|
||||
src = strings.Replace(src, ".", "+", -1)
|
||||
dst, err = b64.DecodeString(src)
|
||||
return
|
||||
}
|
62
vendor/gopkg.in/hlandau/passlib.v1/hash/pbkdf2/raw/parse.go
generated
vendored
Normal file
62
vendor/gopkg.in/hlandau/passlib.v1/hash/pbkdf2/raw/parse.go
generated
vendored
Normal file
|
@ -0,0 +1,62 @@
|
|||
package raw
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"fmt"
|
||||
"hash"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Indicates that a password hash or stub is invalid.
|
||||
var ErrInvalidStub = fmt.Errorf("invalid stub")
|
||||
|
||||
// Indicates that the number of rounds specified is not in the valid range.
|
||||
var ErrInvalidRounds = fmt.Errorf("invalid number of rounds")
|
||||
|
||||
var hashMap = map[string]func() hash.Hash{
|
||||
"pbkdf2": sha1.New,
|
||||
"pbkdf2-sha256": sha256.New,
|
||||
"pbkdf2-sha512": sha512.New,
|
||||
}
|
||||
|
||||
func Parse(stub string) (hashFunc func() hash.Hash, rounds int, salt []byte, hash string, err error) {
|
||||
// does not start with $pbkdf2
|
||||
if !strings.HasPrefix(stub, "$pbkdf2") {
|
||||
err = ErrInvalidStub
|
||||
return
|
||||
}
|
||||
|
||||
parts := strings.Split(stub, "$")
|
||||
if f, ok := hashMap[parts[1]]; ok {
|
||||
hashFunc = f
|
||||
} else {
|
||||
err = ErrInvalidStub
|
||||
return
|
||||
}
|
||||
|
||||
roundsStr := parts[2]
|
||||
var n uint64
|
||||
n, err = strconv.ParseUint(roundsStr, 10, 31)
|
||||
if err != nil {
|
||||
err = ErrInvalidStub
|
||||
return
|
||||
}
|
||||
rounds = int(n)
|
||||
|
||||
if rounds < MinRounds || rounds > MaxRounds {
|
||||
err = ErrInvalidRounds
|
||||
return
|
||||
}
|
||||
|
||||
salt, err = Base64Decode(parts[3])
|
||||
if err != nil {
|
||||
err = fmt.Errorf("could not decode base64 salt")
|
||||
return
|
||||
}
|
||||
hash = parts[4]
|
||||
|
||||
return
|
||||
}
|
15
vendor/gopkg.in/hlandau/passlib.v1/hash/pbkdf2/raw/pbkdf2.go
generated
vendored
Normal file
15
vendor/gopkg.in/hlandau/passlib.v1/hash/pbkdf2/raw/pbkdf2.go
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
package raw
|
||||
|
||||
import (
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
"hash"
|
||||
)
|
||||
|
||||
const (
|
||||
MinRounds = 1
|
||||
MaxRounds = 0xffffffff // setting at 32-bit limit for now
|
||||
)
|
||||
|
||||
func Hash(password, salt []byte, rounds int, hf func() hash.Hash) (hash string) {
|
||||
return Base64Encode(pbkdf2.Key(password, salt, rounds, hf().Size(), hf))
|
||||
}
|
30
vendor/gopkg.in/hlandau/passlib.v1/hash/pbkdf2/test.py
generated
vendored
Normal file
30
vendor/gopkg.in/hlandau/passlib.v1/hash/pbkdf2/test.py
generated
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
#!/usr/bin/env python3
|
||||
import passlib.hash
|
||||
import base64
|
||||
def f(p):
|
||||
h = passlib.hash.pbkdf2_sha256.hash(p)
|
||||
print(' {"%s", "%s"},' % (p,h))
|
||||
|
||||
f('')
|
||||
f('a')
|
||||
f('ab')
|
||||
f('abc')
|
||||
f('abcd')
|
||||
f('abcde')
|
||||
f('abcdef')
|
||||
f('abcdefg')
|
||||
f('abcdefgh')
|
||||
f('abcdefghi')
|
||||
f('abcdefghij')
|
||||
f('abcdefghijk')
|
||||
f('abcdefghijkl')
|
||||
f('abcdefghijklm')
|
||||
f('abcdefghijklmn')
|
||||
f('abcdefghijklmno')
|
||||
f('abcdefghijklmnop')
|
||||
f('qrstuvwxyz012345')
|
||||
f('67890./')
|
||||
f('ABCDEFGHIJKLMNOP')
|
||||
f('QRSTUVWXYZ012345')
|
||||
for i in range(70):
|
||||
f(('password'*10)[0:i])
|
95
vendor/gopkg.in/hlandau/passlib.v1/hash/scrypt/raw/scrypt.go
generated
vendored
Normal file
95
vendor/gopkg.in/hlandau/passlib.v1/hash/scrypt/raw/scrypt.go
generated
vendored
Normal file
|
@ -0,0 +1,95 @@
|
|||
// Package raw provides a raw implementation of the modular-crypt-wrapped scrypt primitive.
|
||||
package raw
|
||||
|
||||
import "golang.org/x/crypto/scrypt"
|
||||
import "encoding/base64"
|
||||
import "strings"
|
||||
import "strconv"
|
||||
import "fmt"
|
||||
|
||||
// The current recommended N value for interactive logins.
|
||||
const RecommendedN = 16384
|
||||
|
||||
// The current recommended r value for interactive logins.
|
||||
const Recommendedr = 8
|
||||
|
||||
// The current recommended p value for interactive logins.
|
||||
const Recommendedp = 1
|
||||
|
||||
// Wrapper for golang.org/x/crypto/scrypt implementing a sensible
|
||||
// modular crypt interface.
|
||||
//
|
||||
// password should be a UTF-8 plaintext password.
|
||||
// salt should be a random salt value in binary form.
|
||||
//
|
||||
// N, r and p are parameters to scrypt.
|
||||
//
|
||||
// Returns a modular crypt hash.
|
||||
func ScryptSHA256(password string, salt []byte, N, r, p int) string {
|
||||
passwordb := []byte(password)
|
||||
|
||||
hash, err := scrypt.Key(passwordb, salt, N, r, p, 32)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
hstr := base64.StdEncoding.EncodeToString(hash)
|
||||
sstr := base64.StdEncoding.EncodeToString(salt)
|
||||
|
||||
return fmt.Sprintf("$s2$%d$%d$%d$%s$%s", N, r, p, sstr, hstr)
|
||||
}
|
||||
|
||||
// Indicates that a password hash or stub is invalid.
|
||||
var ErrInvalidStub = fmt.Errorf("invalid scrypt password stub")
|
||||
|
||||
// Parses an scrypt modular hash or stub string.
|
||||
//
|
||||
// The format is as follows:
|
||||
//
|
||||
// $s2$N$r$p$salt$hash // hash
|
||||
// $s2$N$r$p$salt // stub
|
||||
//
|
||||
func Parse(stub string) (salt, hash []byte, N, r, p int, err error) {
|
||||
if len(stub) < 10 || !strings.HasPrefix(stub, "$s2$") {
|
||||
err = ErrInvalidStub
|
||||
return
|
||||
}
|
||||
|
||||
// $s2$ N$r$p$salt-base64$hash-base64
|
||||
parts := strings.Split(stub[4:], "$")
|
||||
|
||||
if len(parts) < 4 {
|
||||
err = ErrInvalidStub
|
||||
return
|
||||
}
|
||||
|
||||
var Ni, ri, pi uint64
|
||||
|
||||
Ni, err = strconv.ParseUint(parts[0], 10, 31)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ri, err = strconv.ParseUint(parts[1], 10, 31)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
pi, err = strconv.ParseUint(parts[2], 10, 31)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
N, r, p = int(Ni), int(ri), int(pi)
|
||||
|
||||
salt, err = base64.StdEncoding.DecodeString(parts[3])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(parts) >= 5 {
|
||||
hash, err = base64.StdEncoding.DecodeString(parts[4])
|
||||
}
|
||||
|
||||
return
|
||||
}
|
113
vendor/gopkg.in/hlandau/passlib.v1/hash/scrypt/scrypt.go
generated
vendored
Normal file
113
vendor/gopkg.in/hlandau/passlib.v1/hash/scrypt/scrypt.go
generated
vendored
Normal file
|
@ -0,0 +1,113 @@
|
|||
// Package scrypt implements the scrypt password hashing mechanism, wrapped in
|
||||
// the modular crypt format.
|
||||
package scrypt
|
||||
|
||||
import "fmt"
|
||||
import "expvar"
|
||||
import "strings"
|
||||
import "crypto/rand"
|
||||
import "encoding/base64"
|
||||
import "gopkg.in/hlandau/passlib.v1/hash/scrypt/raw"
|
||||
import "gopkg.in/hlandau/passlib.v1/abstract"
|
||||
|
||||
var cScryptSHA256HashCalls = expvar.NewInt("passlib.scryptsha256.hashCalls")
|
||||
var cScryptSHA256VerifyCalls = expvar.NewInt("passlib.scryptsha256.verifyCalls")
|
||||
|
||||
// An implementation of Scheme performing scrypt-sha256.
|
||||
//
|
||||
// Uses the recommended values for N,r,p defined in raw.
|
||||
var SHA256Crypter abstract.Scheme
|
||||
|
||||
func init() {
|
||||
SHA256Crypter = NewSHA256(
|
||||
raw.RecommendedN,
|
||||
raw.Recommendedr,
|
||||
raw.Recommendedp,
|
||||
)
|
||||
}
|
||||
|
||||
// Returns an implementation of Scheme implementing scrypt-sha256
|
||||
// with the specified parameters.
|
||||
func NewSHA256(N, r, p int) abstract.Scheme {
|
||||
return &scryptSHA256Crypter{
|
||||
nN: N,
|
||||
r: r,
|
||||
p: p,
|
||||
}
|
||||
}
|
||||
|
||||
type scryptSHA256Crypter struct {
|
||||
nN, r, p int
|
||||
}
|
||||
|
||||
func (c *scryptSHA256Crypter) SetParams(N, r, p int) error {
|
||||
c.nN = N
|
||||
c.r = r
|
||||
c.p = p
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *scryptSHA256Crypter) SupportsStub(stub string) bool {
|
||||
return strings.HasPrefix(stub, "$s2$")
|
||||
}
|
||||
|
||||
func (c *scryptSHA256Crypter) Hash(password string) (string, error) {
|
||||
cScryptSHA256HashCalls.Add(1)
|
||||
|
||||
stub, err := c.makeStub()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
_, newHash, _, _, _, _, err := c.hash(password, stub)
|
||||
return newHash, err
|
||||
}
|
||||
|
||||
func (c *scryptSHA256Crypter) Verify(password, hash string) (err error) {
|
||||
cScryptSHA256VerifyCalls.Add(1)
|
||||
|
||||
_, newHash, _, _, _, _, err := c.hash(password, hash)
|
||||
if err == nil && !abstract.SecureCompare(hash, newHash) {
|
||||
err = abstract.ErrInvalidPassword
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (c *scryptSHA256Crypter) NeedsUpdate(stub string) bool {
|
||||
salt, _, N, r, p, err := raw.Parse(stub)
|
||||
if err != nil {
|
||||
return false // ...
|
||||
}
|
||||
|
||||
return c.needsUpdate(salt, N, r, p)
|
||||
}
|
||||
|
||||
func (c *scryptSHA256Crypter) needsUpdate(salt []byte, N, r, p int) bool {
|
||||
return len(salt) < 18 || N < c.nN || r < c.r || p < c.p
|
||||
}
|
||||
|
||||
func (c *scryptSHA256Crypter) hash(password, stub string) (oldHashRaw []byte, newHash string, salt []byte, N, r, p int, err error) {
|
||||
salt, oldHashRaw, N, r, p, err = raw.Parse(stub)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return oldHashRaw, raw.ScryptSHA256(password, salt, N, r, p), salt, N, r, p, nil
|
||||
}
|
||||
|
||||
func (c *scryptSHA256Crypter) makeStub() (string, error) {
|
||||
buf := make([]byte, 18)
|
||||
_, err := rand.Read(buf)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
salt := base64.StdEncoding.EncodeToString(buf)
|
||||
|
||||
return fmt.Sprintf("$s2$%d$%d$%d$%s", c.nN, c.r, c.p, salt), nil
|
||||
}
|
||||
|
||||
func (c *scryptSHA256Crypter) String() string {
|
||||
return fmt.Sprintf("scrypt-sha256(%d,%d,%d)", c.nN, c.r, c.p)
|
||||
}
|
34
vendor/gopkg.in/hlandau/passlib.v1/hash/sha2crypt/raw/base64.go
generated
vendored
Normal file
34
vendor/gopkg.in/hlandau/passlib.v1/hash/sha2crypt/raw/base64.go
generated
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
package raw
|
||||
|
||||
const bmap = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
||||
|
||||
// Encodes a byte string using the sha2-crypt base64 variant.
|
||||
func EncodeBase64(b []byte) string {
|
||||
o := make([]byte, len(b)/3*4+4)
|
||||
|
||||
for i, j := 0, 0; i < len(b); {
|
||||
b1 := b[i]
|
||||
b2 := byte(0)
|
||||
b3 := byte(0)
|
||||
|
||||
if (i + 1) < len(b) {
|
||||
b2 = b[i+1]
|
||||
}
|
||||
if (i + 2) < len(b) {
|
||||
b3 = b[i+2]
|
||||
}
|
||||
|
||||
o[j] = bmap[(b1 & 0x3F)]
|
||||
o[j+1] = bmap[((b1&0xC0)>>6)|((b2&0x0F)<<2)]
|
||||
o[j+2] = bmap[((b2&0xF0)>>4)|((b3&0x03)<<4)]
|
||||
o[j+3] = bmap[(b3&0xFC)>>2]
|
||||
i += 3
|
||||
j += 4
|
||||
}
|
||||
|
||||
s := string(o)
|
||||
return s[0 : len(b)*4/3-(len(b)%4)+1]
|
||||
}
|
||||
|
||||
// © 2008-2012 Assurance Technologies LLC. (Python passlib) BSD License
|
||||
// © 2014 Hugo Landau <hlandau@devever.net> BSD License
|
82
vendor/gopkg.in/hlandau/passlib.v1/hash/sha2crypt/raw/parse.go
generated
vendored
Normal file
82
vendor/gopkg.in/hlandau/passlib.v1/hash/sha2crypt/raw/parse.go
generated
vendored
Normal file
|
@ -0,0 +1,82 @@
|
|||
package raw
|
||||
|
||||
import "fmt"
|
||||
import "strings"
|
||||
import "strconv"
|
||||
|
||||
// Indicates that a password hash or stub is invalid.
|
||||
var ErrInvalidStub = fmt.Errorf("invalid stub")
|
||||
|
||||
// Indicates that the number of rounds specified is not in the valid range.
|
||||
var ErrInvalidRounds = fmt.Errorf("invalid number of rounds")
|
||||
|
||||
// Scans a sha256-crypt or sha512-crypt modular crypt stub or modular crypt hash
|
||||
// to determine configuration parameters.
|
||||
func Parse(stub string) (isSHA512 bool, salt, hash string, rounds int, err error) {
|
||||
// $5$
|
||||
if len(stub) < 3 || stub[0] != '$' || stub[2] != '$' {
|
||||
err = ErrInvalidStub
|
||||
return
|
||||
}
|
||||
|
||||
if stub[1] == '6' {
|
||||
isSHA512 = true
|
||||
} else if stub[1] != '5' {
|
||||
err = ErrInvalidStub
|
||||
return
|
||||
}
|
||||
|
||||
rest := stub[3:]
|
||||
parts := strings.Split(rest, "$")
|
||||
roundsStr := ""
|
||||
|
||||
switch len(parts) {
|
||||
case 1:
|
||||
// $5$
|
||||
// $5$salt
|
||||
salt = parts[0]
|
||||
case 2:
|
||||
// $5$salt$hash
|
||||
// $5$rounds=1000$salt
|
||||
if strings.HasPrefix(parts[0], "rounds=") {
|
||||
roundsStr = parts[0]
|
||||
salt = parts[1]
|
||||
} else {
|
||||
salt = parts[0]
|
||||
hash = parts[1]
|
||||
}
|
||||
case 3:
|
||||
// $5$rounds=1000$salt$hash
|
||||
roundsStr = parts[0]
|
||||
salt = parts[1]
|
||||
hash = parts[2]
|
||||
default:
|
||||
err = ErrInvalidStub
|
||||
}
|
||||
|
||||
if roundsStr != "" {
|
||||
if !strings.HasPrefix(roundsStr, "rounds=") {
|
||||
err = ErrInvalidStub
|
||||
return
|
||||
}
|
||||
|
||||
roundsStr = roundsStr[7:]
|
||||
var n uint64
|
||||
n, err = strconv.ParseUint(roundsStr, 10, 31)
|
||||
if err != nil {
|
||||
err = ErrInvalidStub
|
||||
return
|
||||
}
|
||||
|
||||
rounds = int(n)
|
||||
|
||||
if rounds < MinimumRounds || rounds > MaximumRounds {
|
||||
err = ErrInvalidRounds
|
||||
return
|
||||
}
|
||||
} else {
|
||||
rounds = DefaultRounds
|
||||
}
|
||||
|
||||
return
|
||||
}
|
187
vendor/gopkg.in/hlandau/passlib.v1/hash/sha2crypt/raw/sha2crypt.go
generated
vendored
Normal file
187
vendor/gopkg.in/hlandau/passlib.v1/hash/sha2crypt/raw/sha2crypt.go
generated
vendored
Normal file
|
@ -0,0 +1,187 @@
|
|||
// Package raw provides a raw implementation of the sha256-crypt and sha512-crypt primitives.
|
||||
package raw
|
||||
|
||||
import "io"
|
||||
import "fmt"
|
||||
import "hash"
|
||||
import "crypto/sha256"
|
||||
import "crypto/sha512"
|
||||
|
||||
// The minimum number of rounds permissible for sha256-crypt and sha512-crypt.
|
||||
const MinimumRounds = 1000
|
||||
|
||||
// The maximum number of rounds permissible for sha256-crypt and sha512-crypt.
|
||||
// Don't use this!
|
||||
const MaximumRounds = 999999999
|
||||
|
||||
// This is the 'default' number of rounds for sha256-crypt and sha512-crypt. If
|
||||
// this rounds value is used the number of rounds is not explicitly specified
|
||||
// in the modular crypt format, as it is the default.
|
||||
const DefaultRounds = 5000
|
||||
|
||||
// This is the recommended number of rounds for sha256-crypt and sha512-crypt.
|
||||
// This may change with subsequent releases of this package. It is recommended
|
||||
// that you invoke sha256-crypt or sha512-crypt with this value, or a value
|
||||
// proportional to it.
|
||||
const RecommendedRounds = 10000
|
||||
|
||||
// Calculates sha256-crypt. The password must be in plaintext and be a UTF-8
|
||||
// string.
|
||||
//
|
||||
// The salt must be a valid ASCII between 0 and 16 characters in length
|
||||
// inclusive.
|
||||
//
|
||||
// See the constants in this package for suggested values for rounds.
|
||||
//
|
||||
// Rounds must be in the range 1000 <= rounds <= 999999999. The function panics
|
||||
// if this is not the case.
|
||||
//
|
||||
// The output is in modular crypt format.
|
||||
func Crypt256(password, salt string, rounds int) string {
|
||||
return "$5" + shaCrypt(password, salt, rounds, sha256.New, transpose256)
|
||||
}
|
||||
|
||||
// Calculates sha256-crypt. The password must be in plaintext and be a UTF-8
|
||||
// string.
|
||||
//
|
||||
// The salt must be a valid ASCII between 0 and 16 characters in length
|
||||
// inclusive.
|
||||
//
|
||||
// See the constants in this package for suggested values for rounds.
|
||||
//
|
||||
// Rounds must be in the range 1000 <= rounds <= 999999999. The function panics
|
||||
// if this is not the case.
|
||||
//
|
||||
// The output is in modular crypt format.
|
||||
func Crypt512(password, salt string, rounds int) string {
|
||||
return "$6" + shaCrypt(password, salt, rounds, sha512.New, transpose512)
|
||||
}
|
||||
|
||||
func shaCrypt(password, salt string, rounds int, newHash func() hash.Hash, transpose func(b []byte)) string {
|
||||
if rounds < MinimumRounds || rounds > MaximumRounds {
|
||||
panic("sha256-crypt rounds must be in 1000 <= rounds <= 999999999")
|
||||
}
|
||||
|
||||
passwordb := []byte(password)
|
||||
saltb := []byte(salt)
|
||||
if len(saltb) > 16 {
|
||||
panic("salt must not exceed 16 bytes")
|
||||
}
|
||||
|
||||
// B
|
||||
b := newHash()
|
||||
b.Write(passwordb)
|
||||
b.Write(saltb)
|
||||
b.Write(passwordb)
|
||||
bsum := b.Sum(nil)
|
||||
|
||||
// A
|
||||
a := newHash()
|
||||
a.Write(passwordb)
|
||||
a.Write(saltb)
|
||||
repeat(a, bsum, len(passwordb))
|
||||
|
||||
plen := len(passwordb)
|
||||
for plen != 0 {
|
||||
if (plen & 1) != 0 {
|
||||
a.Write(bsum)
|
||||
} else {
|
||||
a.Write(passwordb)
|
||||
}
|
||||
plen = plen >> 1
|
||||
}
|
||||
|
||||
asum := a.Sum(nil)
|
||||
|
||||
// DP
|
||||
dp := newHash()
|
||||
for i := 0; i < len(passwordb); i++ {
|
||||
dp.Write(passwordb)
|
||||
}
|
||||
|
||||
dpsum := dp.Sum(nil)
|
||||
|
||||
// P
|
||||
p := make([]byte, len(passwordb))
|
||||
repeatTo(p, dpsum)
|
||||
|
||||
// DS
|
||||
ds := newHash()
|
||||
for i := 0; i < (16 + int(asum[0])); i++ {
|
||||
ds.Write(saltb)
|
||||
}
|
||||
|
||||
dssum := ds.Sum(nil)[0:len(saltb)]
|
||||
|
||||
// S
|
||||
s := make([]byte, len(saltb))
|
||||
repeatTo(s, dssum)
|
||||
|
||||
// C
|
||||
cur := asum[:]
|
||||
for i := 0; i < rounds; i++ {
|
||||
c := newHash()
|
||||
if (i & 1) != 0 {
|
||||
c.Write(p)
|
||||
} else {
|
||||
c.Write(cur)
|
||||
}
|
||||
if (i % 3) != 0 {
|
||||
c.Write(s)
|
||||
}
|
||||
if (i % 7) != 0 {
|
||||
c.Write(p)
|
||||
}
|
||||
if (i & 1) == 0 {
|
||||
c.Write(p)
|
||||
} else {
|
||||
c.Write(cur)
|
||||
}
|
||||
cur = c.Sum(nil)[:]
|
||||
}
|
||||
|
||||
// Transposition
|
||||
transpose(cur)
|
||||
|
||||
// Hash
|
||||
hstr := EncodeBase64(cur)
|
||||
|
||||
if rounds == DefaultRounds {
|
||||
return fmt.Sprintf("$%s$%s", salt, hstr)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("$rounds=%d$%s$%s", rounds, salt, hstr)
|
||||
}
|
||||
|
||||
func repeat(w io.Writer, b []byte, sz int) {
|
||||
var i int
|
||||
for i = 0; (i + len(b)) <= sz; i += len(b) {
|
||||
w.Write(b)
|
||||
}
|
||||
w.Write(b[0 : sz-i])
|
||||
}
|
||||
|
||||
func repeatTo(out []byte, b []byte) {
|
||||
if len(b) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
var i int
|
||||
for i = 0; (i + len(b)) <= len(out); i += len(b) {
|
||||
copy(out[i:], b)
|
||||
}
|
||||
copy(out[i:], b)
|
||||
}
|
||||
|
||||
func transpose256(b []byte) {
|
||||
b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15], b[16], b[17], b[18], b[19], b[20], b[21], b[22], b[23], b[24], b[25], b[26], b[27], b[28], b[29], b[30], b[31] =
|
||||
b[20], b[10], b[0], b[11], b[1], b[21], b[2], b[22], b[12], b[23], b[13], b[3], b[14], b[4], b[24], b[5], b[25], b[15], b[26], b[16], b[6], b[17], b[7], b[27], b[8], b[28], b[18], b[29], b[19], b[9], b[30], b[31]
|
||||
}
|
||||
|
||||
func transpose512(b []byte) {
|
||||
b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15], b[16], b[17], b[18], b[19], b[20], b[21], b[22], b[23], b[24], b[25], b[26], b[27], b[28], b[29], b[30], b[31], b[32], b[33], b[34], b[35], b[36], b[37], b[38], b[39], b[40], b[41], b[42], b[43], b[44], b[45], b[46], b[47], b[48], b[49], b[50], b[51], b[52], b[53], b[54], b[55], b[56], b[57], b[58], b[59], b[60], b[61], b[62], b[63] =
|
||||
b[42], b[21], b[0], b[1], b[43], b[22], b[23], b[2], b[44], b[45], b[24], b[3], b[4], b[46], b[25], b[26], b[5], b[47], b[48], b[27], b[6], b[7], b[49], b[28], b[29], b[8], b[50], b[51], b[30], b[9], b[10], b[52], b[31], b[32], b[11], b[53], b[54], b[33], b[12], b[13], b[55], b[34], b[35], b[14], b[56], b[57], b[36], b[15], b[16], b[58], b[37], b[38], b[17], b[59], b[60], b[39], b[18], b[19], b[61], b[40], b[41], b[20], b[62], b[63]
|
||||
}
|
||||
|
||||
// © 2008-2012 Assurance Technologies LLC. (Python passlib) BSD License
|
||||
// © 2014 Hugo Landau <hlandau@devever.net> BSD License
|
147
vendor/gopkg.in/hlandau/passlib.v1/hash/sha2crypt/sha2crypt.go
generated
vendored
Normal file
147
vendor/gopkg.in/hlandau/passlib.v1/hash/sha2crypt/sha2crypt.go
generated
vendored
Normal file
|
@ -0,0 +1,147 @@
|
|||
// Package sha2crypt implements sha256-crypt and sha512-crypt.
|
||||
package sha2crypt
|
||||
|
||||
import "fmt"
|
||||
import "expvar"
|
||||
import "crypto/rand"
|
||||
import "gopkg.in/hlandau/passlib.v1/hash/sha2crypt/raw"
|
||||
import "gopkg.in/hlandau/passlib.v1/abstract"
|
||||
|
||||
var cSHA2CryptHashCalls = expvar.NewInt("passlib.sha2crypt.hashCalls")
|
||||
var cSHA2CryptVerifyCalls = expvar.NewInt("passlib.sha2crypt.verifyCalls")
|
||||
|
||||
// An implementation of Scheme performing sha256-crypt.
|
||||
//
|
||||
// The number of rounds is raw.RecommendedRounds.
|
||||
var Crypter256 abstract.Scheme
|
||||
|
||||
// An implementation of Scheme performing sha512-crypt.
|
||||
//
|
||||
// The number of rounds is raw.RecommendedRounds.
|
||||
var Crypter512 abstract.Scheme
|
||||
|
||||
func init() {
|
||||
Crypter256 = NewCrypter256(raw.RecommendedRounds)
|
||||
Crypter512 = NewCrypter512(raw.RecommendedRounds)
|
||||
}
|
||||
|
||||
// Returns a Scheme implementing sha256-crypt using the number of rounds
|
||||
// specified.
|
||||
func NewCrypter256(rounds int) abstract.Scheme {
|
||||
return &sha2Crypter{false, rounds}
|
||||
}
|
||||
|
||||
// Returns a Scheme implementing sha512-crypt using the number of rounds
|
||||
// specified.
|
||||
func NewCrypter512(rounds int) abstract.Scheme {
|
||||
return &sha2Crypter{true, rounds}
|
||||
}
|
||||
|
||||
type sha2Crypter struct {
|
||||
sha512 bool
|
||||
rounds int
|
||||
}
|
||||
|
||||
// Changes the default rounds for the crypter. Be warned that this
|
||||
// is a global setting. The default default value is RecommendedRounds.
|
||||
func (c *sha2Crypter) SetRounds(rounds int) error {
|
||||
if rounds < raw.MinimumRounds || rounds > raw.MaximumRounds {
|
||||
return raw.ErrInvalidRounds
|
||||
}
|
||||
|
||||
c.rounds = rounds
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *sha2Crypter) SupportsStub(stub string) bool {
|
||||
if len(stub) < 3 || stub[0] != '$' || stub[2] != '$' {
|
||||
return false
|
||||
}
|
||||
return (stub[1] == '5' && !c.sha512) || (stub[1] == '6' && c.sha512)
|
||||
}
|
||||
|
||||
func (c *sha2Crypter) Hash(password string) (string, error) {
|
||||
cSHA2CryptHashCalls.Add(1)
|
||||
|
||||
stub, err := c.makeStub()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
_, newHash, _, _, err := c.hash(password, stub)
|
||||
return newHash, err
|
||||
}
|
||||
|
||||
func (c *sha2Crypter) Verify(password, hash string) (err error) {
|
||||
cSHA2CryptVerifyCalls.Add(1)
|
||||
|
||||
_, newHash, _, _, err := c.hash(password, hash)
|
||||
if err == nil && !abstract.SecureCompare(hash, newHash) {
|
||||
err = abstract.ErrInvalidPassword
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (c *sha2Crypter) NeedsUpdate(stub string) bool {
|
||||
_, salt, _, rounds, err := raw.Parse(stub)
|
||||
if err != nil {
|
||||
return false // ...
|
||||
}
|
||||
|
||||
return c.needsUpdate(salt, rounds)
|
||||
}
|
||||
|
||||
func (c *sha2Crypter) needsUpdate(salt string, rounds int) bool {
|
||||
return rounds < c.rounds || len(salt) < 16
|
||||
}
|
||||
|
||||
var errInvalidStub = fmt.Errorf("invalid sha2 password stub")
|
||||
|
||||
func (c *sha2Crypter) hash(password, stub string) (oldHash, newHash, salt string, rounds int, err error) {
|
||||
isSHA512, salt, oldHash, rounds, err := raw.Parse(stub)
|
||||
if err != nil {
|
||||
return "", "", "", 0, err
|
||||
}
|
||||
|
||||
if isSHA512 != c.sha512 {
|
||||
return "", "", "", 0, errInvalidStub
|
||||
}
|
||||
|
||||
if c.sha512 {
|
||||
return oldHash, raw.Crypt512(password, salt, rounds), salt, rounds, nil
|
||||
}
|
||||
|
||||
return oldHash, raw.Crypt256(password, salt, rounds), salt, rounds, nil
|
||||
}
|
||||
|
||||
func (c *sha2Crypter) makeStub() (string, error) {
|
||||
ch := "5"
|
||||
if c.sha512 {
|
||||
ch = "6"
|
||||
}
|
||||
|
||||
buf := make([]byte, 12)
|
||||
_, err := rand.Read(buf)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
salt := raw.EncodeBase64(buf)[0:16]
|
||||
|
||||
if c.rounds == raw.DefaultRounds {
|
||||
return fmt.Sprintf("$%s$%s", ch, salt), nil
|
||||
}
|
||||
|
||||
return fmt.Sprintf("$%s$rounds=%d$%s", ch, c.rounds, salt), nil
|
||||
}
|
||||
|
||||
func (c *sha2Crypter) String() string {
|
||||
if c.sha512 {
|
||||
return fmt.Sprintf("sha512-crypt(%d)", c.rounds)
|
||||
} else {
|
||||
return fmt.Sprintf("sha256-crypt(%d)", c.rounds)
|
||||
}
|
||||
}
|
||||
|
||||
// © 2014 Hugo Landau <hlandau@devever.net> BSD License
|
174
vendor/gopkg.in/hlandau/passlib.v1/passlib.go
generated
vendored
Normal file
174
vendor/gopkg.in/hlandau/passlib.v1/passlib.go
generated
vendored
Normal file
|
@ -0,0 +1,174 @@
|
|||
// Package passlib provides a simple password hashing and verification
|
||||
// interface abstracting multiple password hashing schemes.
|
||||
//
|
||||
// After initialisation, most people need concern themselves only with the
|
||||
// functions Hash and Verify, which uses the default context and sensible
|
||||
// defaults.
|
||||
//
|
||||
// Library Initialization
|
||||
//
|
||||
// You should initialise the library before using it with the following line.
|
||||
//
|
||||
// // Call this at application startup.
|
||||
// passlib.UseDefaults(passlib.Defaults20180601)
|
||||
//
|
||||
// See func UseDefaults for details.
|
||||
package passlib // import "gopkg.in/hlandau/passlib.v1"
|
||||
|
||||
import (
|
||||
"gopkg.in/hlandau/easymetric.v1/cexp"
|
||||
"gopkg.in/hlandau/passlib.v1/abstract"
|
||||
)
|
||||
|
||||
var cHashCalls = cexp.NewCounter("passlib.ctx.hashCalls")
|
||||
var cVerifyCalls = cexp.NewCounter("passlib.ctx.verifyCalls")
|
||||
var cSuccessfulVerifyCalls = cexp.NewCounter("passlib.ctx.successfulVerifyCalls")
|
||||
var cFailedVerifyCalls = cexp.NewCounter("passlib.ctx.failedVerifyCalls")
|
||||
var cSuccessfulVerifyCallsWithUpgrade = cexp.NewCounter("passlib.ctx.successfulVerifyCallsWithUpgrade")
|
||||
var cSuccessfulVerifyCallsDeferringUpgrade = cexp.NewCounter("passlib.ctx.successfulVerifyCallsDeferringUpgrade")
|
||||
|
||||
// A password hashing context, that uses a given set of schemes to hash and
|
||||
// verify passwords.
|
||||
type Context struct {
|
||||
// Slice of schemes to use, most preferred first.
|
||||
//
|
||||
// If left uninitialized, a sensible default set of schemes will be used.
|
||||
//
|
||||
// An upgrade hash (see the newHash return value of the Verify method of the
|
||||
// abstract.Scheme interface) will be issued whenever a password is validated
|
||||
// using a scheme which is not the first scheme in this slice.
|
||||
Schemes []abstract.Scheme
|
||||
}
|
||||
|
||||
func (ctx *Context) schemes() []abstract.Scheme {
|
||||
if ctx.Schemes == nil {
|
||||
return DefaultSchemes
|
||||
}
|
||||
|
||||
return ctx.Schemes
|
||||
}
|
||||
|
||||
// Hashes a UTF-8 plaintext password using the context and produces a password hash.
|
||||
//
|
||||
// If stub is "", one is generated automaticaly for the preferred password hashing
|
||||
// scheme; you should specify stub as "" in almost all cases.
|
||||
//
|
||||
// The provided or randomly generated stub is used to deterministically hash
|
||||
// the password. The returned hash is in modular crypt format.
|
||||
//
|
||||
// If the context has not been specifically configured, a sensible default policy
|
||||
// is used. See the fields of Context.
|
||||
func (ctx *Context) Hash(password string) (hash string, err error) {
|
||||
cHashCalls.Add(1)
|
||||
|
||||
return ctx.schemes()[0].Hash(password)
|
||||
}
|
||||
|
||||
// Verifies a UTF-8 plaintext password using a previously derived password hash
|
||||
// and the default context. Returns nil err only if the password is valid.
|
||||
//
|
||||
// If the hash is determined to be deprecated based on the context policy, and
|
||||
// the password is valid, the password is hashed using the preferred password
|
||||
// hashing scheme and returned in newHash. You should use this to upgrade any
|
||||
// stored password hash in your database.
|
||||
//
|
||||
// newHash is empty if the password was not valid or if no upgrade is required.
|
||||
//
|
||||
// You should treat any non-nil err as a password verification error.
|
||||
func (ctx *Context) Verify(password, hash string) (newHash string, err error) {
|
||||
return ctx.verify(password, hash, true)
|
||||
}
|
||||
|
||||
// Like Verify, but does not hash an upgrade password when upgrade is required.
|
||||
func (ctx *Context) VerifyNoUpgrade(password, hash string) error {
|
||||
_, err := ctx.verify(password, hash, false)
|
||||
return err
|
||||
}
|
||||
|
||||
func (ctx *Context) verify(password, hash string, canUpgrade bool) (newHash string, err error) {
|
||||
cVerifyCalls.Add(1)
|
||||
|
||||
for i, scheme := range ctx.schemes() {
|
||||
if !scheme.SupportsStub(hash) {
|
||||
continue
|
||||
}
|
||||
|
||||
err = scheme.Verify(password, hash)
|
||||
if err != nil {
|
||||
cFailedVerifyCalls.Add(1)
|
||||
return "", err
|
||||
}
|
||||
|
||||
cSuccessfulVerifyCalls.Add(1)
|
||||
if i != 0 || scheme.NeedsUpdate(hash) {
|
||||
if canUpgrade {
|
||||
cSuccessfulVerifyCallsWithUpgrade.Add(1)
|
||||
|
||||
// If the scheme is not the first scheme, try and rehash with the
|
||||
// preferred scheme.
|
||||
if newHash, err2 := ctx.Hash(password); err2 == nil {
|
||||
return newHash, nil
|
||||
}
|
||||
} else {
|
||||
cSuccessfulVerifyCallsDeferringUpgrade.Add(1)
|
||||
}
|
||||
}
|
||||
|
||||
return "", nil
|
||||
}
|
||||
|
||||
return "", abstract.ErrUnsupportedScheme
|
||||
}
|
||||
|
||||
// Determines whether a stub or hash needs updating according to the policy of
|
||||
// the context.
|
||||
func (ctx *Context) NeedsUpdate(stub string) bool {
|
||||
for i, scheme := range ctx.schemes() {
|
||||
if scheme.SupportsStub(stub) {
|
||||
return i != 0 || scheme.NeedsUpdate(stub)
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// The default context, which uses sensible defaults. Most users should not
|
||||
// reconfigure this. The defaults may change over time, so you may wish
|
||||
// to reconfigure the context or use a custom context if you want precise
|
||||
// control over the hashes used.
|
||||
var DefaultContext Context
|
||||
|
||||
// Hashes a UTF-8 plaintext password using the default context and produces a
|
||||
// password hash. Chooses the preferred password hashing scheme based on the
|
||||
// configured policy. The default policy is sensible.
|
||||
func Hash(password string) (hash string, err error) {
|
||||
return DefaultContext.Hash(password)
|
||||
}
|
||||
|
||||
// Verifies a UTF-8 plaintext password using a previously derived password hash
|
||||
// and the default context. Returns nil err only if the password is valid.
|
||||
//
|
||||
// If the hash is determined to be deprecated based on policy, and the password
|
||||
// is valid, the password is hashed using the preferred password hashing scheme
|
||||
// and returned in newHash. You should use this to upgrade any stored password
|
||||
// hash in your database.
|
||||
//
|
||||
// newHash is empty if the password was invalid or no upgrade is required.
|
||||
//
|
||||
// You should treat any non-nil err as a password verification error.
|
||||
func Verify(password, hash string) (newHash string, err error) {
|
||||
return DefaultContext.Verify(password, hash)
|
||||
}
|
||||
|
||||
// Like Verify, but never upgrades.
|
||||
func VerifyNoUpgrade(password, hash string) error {
|
||||
return DefaultContext.VerifyNoUpgrade(password, hash)
|
||||
}
|
||||
|
||||
// Uses the default context to determine whether a stub or hash needs updating.
|
||||
func NeedsUpdate(stub string) bool {
|
||||
return DefaultContext.NeedsUpdate(stub)
|
||||
}
|
||||
|
||||
// © 2008-2012 Assurance Technologies LLC. (Python passlib) BSD License
|
||||
// © 2014 Hugo Landau <hlandau@devever.net> BSD License
|
Loading…
Add table
Add a link
Reference in a new issue