xs/vendor/gopkg.in/hlandau/passlib.v1/hash/sha2crypt/raw/sha2crypt.go
Russ Magee caac02a77b 1/2 Updated Makefile to allow VENDOR flag (adds -vendor to version string)
2/2 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
2020-01-29 13:55:38 -08:00

187 lines
5.3 KiB
Go

// 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