fix (build): broken build on dependency

This commit is contained in:
MickaelK 2024-06-04 00:26:58 +10:00
parent b1da883cff
commit d554c81fa5
12 changed files with 1077 additions and 5 deletions

View file

@ -6,11 +6,12 @@ import (
"encoding/base64"
"fmt"
. "github.com/mickael-kerjean/filestash/server/common"
"github.com/tredoe/osutil/user/crypt"
"github.com/tredoe/osutil/user/crypt/apr1_crypt"
"github.com/tredoe/osutil/user/crypt/md5_crypt"
"github.com/tredoe/osutil/user/crypt/sha256_crypt"
"github.com/tredoe/osutil/user/crypt/sha512_crypt"
"github.com/mickael-kerjean/server/plg_authenticate_htpasswd/vendor/crypt"
"github.com/mickael-kerjean/server/plg_authenticate_htpasswd/vendor/crypt/apr1_crypt"
"github.com/mickael-kerjean/server/plg_authenticate_htpasswd/vendor/crypt/md5_crypt"
"github.com/mickael-kerjean/server/plg_authenticate_htpasswd/vendor/crypt/sha256_crypt"
"github.com/mickael-kerjean/server/plg_authenticate_htpasswd/vendor/crypt/sha512_crypt"
"net/http"
"strings"
)

View file

@ -0,0 +1,8 @@
### Initial author
[Jeramey Crawford](https://github.com/jeramey)
### Other authors
[Jonas mg](https://github.com/tredoe)

View file

@ -0,0 +1,27 @@
Copyright (c) 2012, Jeramey Crawford <jeramey@antihe.ro>
Copyright (c) 2013, Jonas mg
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.
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
HOLDER 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.

View file

@ -0,0 +1,25 @@
crypt
=====
A password hashing library.
The goal of crypt is to bring a library of many common and popular password
hashing algorithms to Go and to provide a simple and consistent interface to
each of them. As every hashing method is implemented in pure Go, this library
should be as portable as Go itself.
All hashing methods come with a test suite which verifies their operation
against itself as well as the output of other password hashing implementations
to ensure compatibility with them.
I hope you find this library to be useful and easy to use!
Note: forked from <https://github.com/jeramey/go-pwhash>
## Installation
go get github.com/tredoe/osutil/user/crypt
## License
The source files are distributed under a BSD-style license that can be found
in the LICENSE file.

View file

@ -0,0 +1,62 @@
// Copyright 2012, Jeramey Crawford <jeramey@antihe.ro>
// Copyright 2013, Jonas mg
// All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file.
// Package apr1_crypt implements the standard Unix MD5-crypt algorithm created
// by Poul-Henning Kamp for FreeBSD, and modified by the Apache project.
//
// The only change from MD5-crypt is the use of the magic constant "$apr1$"
// instead of "$1$". The algorithms are otherwise identical.
package apr1_crypt
import (
"github.com/mickael-kerjean/server/plg_authenticate_htpasswd/vendor/crypt"
"github.com/mickael-kerjean/server/plg_authenticate_htpasswd/vendor/crypt/common"
"github.com/mickael-kerjean/server/plg_authenticate_htpasswd/vendor/crypt/md5_crypt"
)
func init() {
crypt.RegisterCrypt(crypt.APR1, New, MagicPrefix)
}
const (
MagicPrefix = "$apr1$"
SaltLenMin = 1
SaltLenMax = 8
RoundsDefault = 1000
)
var md5Crypt = md5_crypt.New()
func init() {
md5Crypt.SetSalt(GetSalt())
}
type crypter struct{ Salt common.Salt }
// New returns a new crypt.Crypter computing the variant "apr1" of MD5-crypt
func New() crypt.Crypter { return &crypter{common.Salt{}} }
func (c *crypter) Generate(key, salt []byte) (string, error) {
return md5Crypt.Generate(key, salt)
}
func (c *crypter) Verify(hashedKey string, key []byte) error {
return md5Crypt.Verify(hashedKey, key)
}
func (c *crypter) Cost(hashedKey string) (int, error) { return RoundsDefault, nil }
func (c *crypter) SetSalt(salt common.Salt) {}
func GetSalt() common.Salt {
return common.Salt{
MagicPrefix: []byte(MagicPrefix),
SaltLenMin: SaltLenMin,
SaltLenMax: SaltLenMax,
RoundsDefault: RoundsDefault,
}
}

View file

@ -0,0 +1,60 @@
// Copyright 2012, Jeramey Crawford <jeramey@antihe.ro>
// Copyright 2013, Jonas mg
// All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file.
package common
const alphabet = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
// Base64_24Bit is a variant of Base64 encoding, commonly used with password
// hashing algorithms to encode the result of their checksum output.
//
// The algorithm operates on up to 3 bytes at a time, encoding the following
// 6-bit sequences into up to 4 hash64 ASCII bytes.
//
// 1. Bottom 6 bits of the first byte
// 2. Top 2 bits of the first byte, and bottom 4 bits of the second byte.
// 3. Top 4 bits of the second byte, and bottom 2 bits of the third byte.
// 4. Top 6 bits of the third byte.
//
// This encoding method does not emit padding bytes as Base64 does.
func Base64_24Bit(src []byte) (hash []byte) {
if len(src) == 0 {
return []byte{} // TODO: return nil
}
hashSize := (len(src) * 8) / 6
if (len(src) % 6) != 0 {
hashSize += 1
}
hash = make([]byte, hashSize)
dst := hash
for len(src) > 0 {
switch len(src) {
default:
dst[0] = alphabet[src[0]&0x3f]
dst[1] = alphabet[((src[0]>>6)|(src[1]<<2))&0x3f]
dst[2] = alphabet[((src[1]>>4)|(src[2]<<4))&0x3f]
dst[3] = alphabet[(src[2]>>2)&0x3f]
src = src[3:]
dst = dst[4:]
case 2:
dst[0] = alphabet[src[0]&0x3f]
dst[1] = alphabet[((src[0]>>6)|(src[1]<<2))&0x3f]
dst[2] = alphabet[(src[1]>>4)&0x3f]
src = src[2:]
dst = dst[3:]
case 1:
dst[0] = alphabet[src[0]&0x3f]
dst[1] = alphabet[(src[0]>>6)&0x3f]
src = src[1:]
dst = dst[2:]
}
}
return
}

View file

@ -0,0 +1,13 @@
// Copyright 2012, Jeramey Crawford <jeramey@antihe.ro>
// Copyright 2013, Jonas mg
// All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file.
// Package common contains routines used by multiple password hashing
// algorithms.
//
// Generally, you will never import this package directly. Many of the
// *_crypt packages will import this package if they require it.
package common

View file

@ -0,0 +1,105 @@
// Copyright 2012, Jeramey Crawford <jeramey@antihe.ro>
// Copyright 2013, Jonas mg
// All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file.
package common
import (
"crypto/rand"
"errors"
"strconv"
)
var (
ErrSaltPrefix = errors.New("invalid magic prefix")
ErrSaltFormat = errors.New("invalid salt format")
ErrSaltRounds = errors.New("invalid rounds")
)
// Salt represents a salt.
type Salt struct {
MagicPrefix []byte
SaltLenMin int
SaltLenMax int
RoundsMin int
RoundsMax int
RoundsDefault int
}
// Generate generates a random salt of a given length.
//
// The length is set thus:
//
// length > SaltLenMax: length = SaltLenMax
// length < SaltLenMin: length = SaltLenMin
func (s *Salt) Generate(length int) []byte {
if length > s.SaltLenMax {
length = s.SaltLenMax
} else if length < s.SaltLenMin {
length = s.SaltLenMin
}
saltLen := (length * 6 / 8)
if (length*6)%8 != 0 {
saltLen++
}
salt := make([]byte, saltLen)
rand.Read(salt)
out := make([]byte, len(s.MagicPrefix)+length)
copy(out, s.MagicPrefix)
copy(out[len(s.MagicPrefix):], Base64_24Bit(salt))
return out
}
// GenerateWRounds creates a random salt with the random bytes being of the
// length provided, and the rounds parameter set as specified.
//
// The parameters are set thus:
//
// length > SaltLenMax: length = SaltLenMax
// length < SaltLenMin: length = SaltLenMin
//
// rounds < 0: rounds = RoundsDefault
// rounds < RoundsMin: rounds = RoundsMin
// rounds > RoundsMax: rounds = RoundsMax
//
// If rounds is equal to RoundsDefault, then the "rounds=" part of the salt is
// removed.
func (s *Salt) GenerateWRounds(length, rounds int) []byte {
if length > s.SaltLenMax {
length = s.SaltLenMax
} else if length < s.SaltLenMin {
length = s.SaltLenMin
}
if rounds < 0 {
rounds = s.RoundsDefault
} else if rounds < s.RoundsMin {
rounds = s.RoundsMin
} else if rounds > s.RoundsMax {
rounds = s.RoundsMax
}
saltLen := (length * 6 / 8)
if (length*6)%8 != 0 {
saltLen++
}
salt := make([]byte, saltLen)
rand.Read(salt)
roundsText := ""
if rounds != s.RoundsDefault {
roundsText = "rounds=" + strconv.Itoa(rounds) + "$"
}
out := make([]byte, len(s.MagicPrefix)+len(roundsText)+length)
copy(out, s.MagicPrefix)
copy(out[len(s.MagicPrefix):], []byte(roundsText))
copy(out[len(s.MagicPrefix)+len(roundsText):], Base64_24Bit(salt))
return out
}

View file

@ -0,0 +1,108 @@
// Copyright 2013, Jonas mg
// All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file.
// Package crypt provides interface for password crypt functions and collects
// common constants.
package crypt
import (
"errors"
"strings"
"github.com/mickael-kerjean/server/plg_authenticate_htpasswd/vendor/crypt/common"
)
var ErrKeyMismatch = errors.New("hashed value is not the hash of the given password")
// Crypter is the common interface implemented by all crypt functions.
type Crypter interface {
// Generate performs the hashing algorithm, returning a full hash suitable
// for storage and later password verification.
//
// If the salt is empty, a randomly-generated salt will be generated with a
// length of SaltLenMax and number RoundsDefault of rounds.
//
// Any error only can be got when the salt argument is not empty.
Generate(key, salt []byte) (string, error)
// Verify compares a hashed key with its possible key equivalent.
// Returns nil on success, or an error on failure; if the hashed key is
// diffrent, the error is "ErrKeyMismatch".
Verify(hashedKey string, key []byte) error
// Cost returns the hashing cost (in rounds) used to create the given hashed
// key.
//
// When, in the future, the hashing cost of a key needs to be increased in
// order to adjust for greater computational power, this function allows one
// to establish which keys need to be updated.
//
// The algorithms based in MD5-crypt use a fixed value of rounds.
Cost(hashedKey string) (int, error)
// SetSalt sets a different salt. It is used to easily create derivated
// algorithms, i.e. "apr1_crypt" from "md5_crypt".
SetSalt(salt common.Salt)
}
// Crypt identifies a crypt function that is implemented in another package.
type Crypt uint
const (
APR1 Crypt = iota + 1 // import "github.com/mickael-kerjean/server/plg_authenticate_htpasswd/vendor/crypt/apr1_crypt"
MD5 // import "github.com/mickael-kerjean/server/plg_authenticate_htpasswd/vendor/crypt/md5_crypt"
SHA256 // import "github.com/mickael-kerjean/server/plg_authenticate_htpasswd/vendor/crypt/sha256_crypt"
SHA512 // import "github.com/mickael-kerjean/server/plg_authenticate_htpasswd/vendor/crypt/sha512_crypt"
maxCrypt
)
var cryptPrefixes = make([]string, maxCrypt)
var crypts = make([]func() Crypter, maxCrypt)
// RegisterCrypt registers a function that returns a new instance of the given
// crypt function. This is intended to be called from the init function in
// packages that implement crypt functions.
func RegisterCrypt(c Crypt, f func() Crypter, prefix string) {
if c >= maxCrypt {
panic("crypt: RegisterHash of unknown crypt function")
}
crypts[c] = f
cryptPrefixes[c] = prefix
}
// New returns a new crypter.
func New(c Crypt) Crypter {
f := crypts[c]
if f != nil {
return f()
}
panic("crypt: requested crypt function is unavailable")
}
// NewFromHash returns a new Crypter using the prefix in the given hashed key.
func NewFromHash(hashedKey string) Crypter {
var f func() Crypter
if strings.HasPrefix(hashedKey, cryptPrefixes[SHA512]) {
f = crypts[SHA512]
} else if strings.HasPrefix(hashedKey, cryptPrefixes[SHA256]) {
f = crypts[SHA256]
} else if strings.HasPrefix(hashedKey, cryptPrefixes[MD5]) {
f = crypts[MD5]
} else if strings.HasPrefix(hashedKey, cryptPrefixes[APR1]) {
f = crypts[APR1]
} else {
toks := strings.SplitN(hashedKey, "$", 3)
prefix := "$" + toks[1] + "$"
panic("crypt: unknown cryp function from prefix: " + prefix)
}
if f != nil {
return f()
}
panic("crypt: requested cryp function is unavailable")
}

View file

@ -0,0 +1,166 @@
// Copyright 2012, Jeramey Crawford <jeramey@antihe.ro>
// Copyright 2013, Jonas mg
// All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file.
// Package md5_crypt implements the standard Unix MD5-crypt algorithm created by
// Poul-Henning Kamp for FreeBSD.
package md5_crypt
import (
"bytes"
"crypto/md5"
"github.com/mickael-kerjean/server/plg_authenticate_htpasswd/vendor/crypt"
"github.com/mickael-kerjean/server/plg_authenticate_htpasswd/vendor/crypt/common"
)
func init() {
crypt.RegisterCrypt(crypt.MD5, New, MagicPrefix)
}
// NOTE: Cisco IOS only allows salts of length 4.
const (
MagicPrefix = "$1$"
SaltLenMin = 1 // Real minimum is 0, but that isn't useful.
SaltLenMax = 8
RoundsDefault = 1000
)
type crypter struct{ Salt common.Salt }
// New returns a new crypt.Crypter computing the MD5-crypt password hashing.
func New() crypt.Crypter {
return &crypter{GetSalt()}
}
func (c *crypter) Generate(key, salt []byte) (string, error) {
if len(salt) == 0 {
salt = c.Salt.Generate(SaltLenMax)
}
if !bytes.HasPrefix(salt, c.Salt.MagicPrefix) {
return "", common.ErrSaltPrefix
}
saltToks := bytes.Split(salt, []byte{'$'})
if len(saltToks) < 3 {
return "", common.ErrSaltFormat
} else {
salt = saltToks[2]
}
if len(salt) > 8 {
salt = salt[0:8]
}
// Compute alternate MD5 sum with input KEY, SALT, and KEY.
Alternate := md5.New()
Alternate.Write(key)
Alternate.Write(salt)
Alternate.Write(key)
AlternateSum := Alternate.Sum(nil) // 16 bytes
A := md5.New()
A.Write(key)
A.Write(c.Salt.MagicPrefix)
A.Write(salt)
// Add for any character in the key one byte of the alternate sum.
i := len(key)
for ; i > 16; i -= 16 {
A.Write(AlternateSum)
}
A.Write(AlternateSum[0:i])
// The original implementation now does something weird:
// For every 1 bit in the key, the first 0 is added to the buffer
// For every 0 bit, the first character of the key
// This does not seem to be what was intended but we have to follow this to
// be compatible.
for i = len(key); i > 0; i >>= 1 {
if (i & 1) == 0 {
A.Write(key[0:1])
} else {
A.Write([]byte{0})
}
}
Csum := A.Sum(nil)
// In fear of password crackers here comes a quite long loop which just
// processes the output of the previous round again.
// We cannot ignore this here.
for i = 0; i < RoundsDefault; i++ {
C := md5.New()
// Add key or last result.
if (i & 1) != 0 {
C.Write(key)
} else {
C.Write(Csum)
}
// Add salt for numbers not divisible by 3.
if (i % 3) != 0 {
C.Write(salt)
}
// Add key for numbers not divisible by 7.
if (i % 7) != 0 {
C.Write(key)
}
// Add key or last result.
if (i & 1) == 0 {
C.Write(key)
} else {
C.Write(Csum)
}
Csum = C.Sum(nil)
}
out := make([]byte, 0, 23+len(c.Salt.MagicPrefix)+len(salt))
out = append(out, c.Salt.MagicPrefix...)
out = append(out, salt...)
out = append(out, '$')
out = append(out, common.Base64_24Bit([]byte{
Csum[12], Csum[6], Csum[0],
Csum[13], Csum[7], Csum[1],
Csum[14], Csum[8], Csum[2],
Csum[15], Csum[9], Csum[3],
Csum[5], Csum[10], Csum[4],
Csum[11],
})...)
// Clean sensitive data.
A.Reset()
Alternate.Reset()
for i = 0; i < len(AlternateSum); i++ {
AlternateSum[i] = 0
}
return string(out), nil
}
func (c *crypter) Verify(hashedKey string, key []byte) error {
newHash, err := c.Generate(key, []byte(hashedKey))
if err != nil {
return err
}
if newHash != hashedKey {
return crypt.ErrKeyMismatch
}
return nil
}
func (c *crypter) Cost(hashedKey string) (int, error) { return RoundsDefault, nil }
func (c *crypter) SetSalt(salt common.Salt) { c.Salt = salt }
func GetSalt() common.Salt {
return common.Salt{
MagicPrefix: []byte(MagicPrefix),
SaltLenMin: SaltLenMin,
SaltLenMax: SaltLenMax,
RoundsDefault: RoundsDefault,
}
}

View file

@ -0,0 +1,243 @@
// Copyright 2012, Jeramey Crawford <jeramey@antihe.ro>
// Copyright 2013, Jonas mg
// All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file.
// Package sha256_crypt implements Ulrich Drepper's SHA256-crypt password
// hashing algorithm.
//
// The specification for this algorithm can be found here:
// http://www.akkadia.org/drepper/SHA-crypt.txt
package sha256_crypt
import (
"bytes"
"crypto/sha256"
"strconv"
"github.com/mickael-kerjean/server/plg_authenticate_htpasswd/vendor/crypt"
"github.com/mickael-kerjean/server/plg_authenticate_htpasswd/vendor/crypt/common"
)
func init() {
crypt.RegisterCrypt(crypt.SHA256, New, MagicPrefix)
}
const (
MagicPrefix = "$5$"
SaltLenMin = 1
SaltLenMax = 16
RoundsMin = 1000
RoundsMax = 999999999
RoundsDefault = 5000
)
var _rounds = []byte("rounds=")
type crypter struct{ Salt common.Salt }
// New returns a new crypt.Crypter computing the SHA256-crypt password hashing.
func New() crypt.Crypter {
return &crypter{GetSalt()}
}
func (c *crypter) Generate(key, salt []byte) (string, error) {
var rounds int
var isRoundsDef bool
if len(salt) == 0 {
salt = c.Salt.GenerateWRounds(SaltLenMax, RoundsDefault)
}
if !bytes.HasPrefix(salt, c.Salt.MagicPrefix) {
return "", common.ErrSaltPrefix
}
saltToks := bytes.Split(salt, []byte{'$'})
if len(saltToks) < 3 {
return "", common.ErrSaltFormat
}
if bytes.HasPrefix(saltToks[2], _rounds) {
isRoundsDef = true
pr, err := strconv.ParseInt(string(saltToks[2][7:]), 10, 32)
if err != nil {
return "", common.ErrSaltRounds
}
rounds = int(pr)
if rounds < RoundsMin {
rounds = RoundsMin
} else if rounds > RoundsMax {
rounds = RoundsMax
}
salt = saltToks[3]
} else {
rounds = RoundsDefault
salt = saltToks[2]
}
if len(salt) > 16 {
salt = salt[0:16]
}
// Compute alternate SHA256 sum with input KEY, SALT, and KEY.
Alternate := sha256.New()
Alternate.Write(key)
Alternate.Write(salt)
Alternate.Write(key)
AlternateSum := Alternate.Sum(nil) // 32 bytes
A := sha256.New()
A.Write(key)
A.Write(salt)
// Add for any character in the key one byte of the alternate sum.
i := len(key)
for ; i > 32; i -= 32 {
A.Write(AlternateSum)
}
A.Write(AlternateSum[0:i])
// Take the binary representation of the length of the key and for every add
// the alternate sum, for every 0 the key.
for i = len(key); i > 0; i >>= 1 {
if (i & 1) != 0 {
A.Write(AlternateSum)
} else {
A.Write(key)
}
}
Asum := A.Sum(nil)
// Start computation of P byte sequence.
P := sha256.New()
// For every character in the password add the entire password.
for i = 0; i < len(key); i++ {
P.Write(key)
}
Psum := P.Sum(nil)
// Create byte sequence P.
Pseq := make([]byte, 0, len(key))
for i = len(key); i > 32; i -= 32 {
Pseq = append(Pseq, Psum...)
}
Pseq = append(Pseq, Psum[0:i]...)
// Start computation of S byte sequence.
S := sha256.New()
for i = 0; i < (16 + int(Asum[0])); i++ {
S.Write(salt)
}
Ssum := S.Sum(nil)
// Create byte sequence S.
Sseq := make([]byte, 0, len(salt))
for i = len(salt); i > 32; i -= 32 {
Sseq = append(Sseq, Ssum...)
}
Sseq = append(Sseq, Ssum[0:i]...)
Csum := Asum
// Repeatedly run the collected hash value through SHA256 to burn CPU cycles.
for i = 0; i < rounds; i++ {
C := sha256.New()
// Add key or last result.
if (i & 1) != 0 {
C.Write(Pseq)
} else {
C.Write(Csum)
}
// Add salt for numbers not divisible by 3.
if (i % 3) != 0 {
C.Write(Sseq)
}
// Add key for numbers not divisible by 7.
if (i % 7) != 0 {
C.Write(Pseq)
}
// Add key or last result.
if (i & 1) != 0 {
C.Write(Csum)
} else {
C.Write(Pseq)
}
Csum = C.Sum(nil)
}
out := make([]byte, 0, 80)
out = append(out, c.Salt.MagicPrefix...)
if isRoundsDef {
out = append(out, []byte("rounds="+strconv.Itoa(rounds)+"$")...)
}
out = append(out, salt...)
out = append(out, '$')
out = append(out, common.Base64_24Bit([]byte{
Csum[20], Csum[10], Csum[0],
Csum[11], Csum[1], Csum[21],
Csum[2], Csum[22], Csum[12],
Csum[23], Csum[13], Csum[3],
Csum[14], Csum[4], Csum[24],
Csum[5], Csum[25], Csum[15],
Csum[26], Csum[16], Csum[6],
Csum[17], Csum[7], Csum[27],
Csum[8], Csum[28], Csum[18],
Csum[29], Csum[19], Csum[9],
Csum[30], Csum[31],
})...)
// Clean sensitive data.
A.Reset()
Alternate.Reset()
P.Reset()
for i = 0; i < len(Asum); i++ {
Asum[i] = 0
}
for i = 0; i < len(AlternateSum); i++ {
AlternateSum[i] = 0
}
for i = 0; i < len(Pseq); i++ {
Pseq[i] = 0
}
return string(out), nil
}
func (c *crypter) Verify(hashedKey string, key []byte) error {
newHash, err := c.Generate(key, []byte(hashedKey))
if err != nil {
return err
}
if newHash != hashedKey {
return crypt.ErrKeyMismatch
}
return nil
}
func (c *crypter) Cost(hashedKey string) (int, error) {
saltToks := bytes.Split([]byte(hashedKey), []byte{'$'})
if len(saltToks) < 3 {
return 0, common.ErrSaltFormat
}
if !bytes.HasPrefix(saltToks[2], _rounds) {
return RoundsDefault, nil
}
roundToks := bytes.Split(saltToks[2], []byte{'='})
cost, err := strconv.ParseInt(string(roundToks[1]), 10, 0)
return int(cost), err
}
func (c *crypter) SetSalt(salt common.Salt) { c.Salt = salt }
func GetSalt() common.Salt {
return common.Salt{
MagicPrefix: []byte(MagicPrefix),
SaltLenMin: SaltLenMin,
SaltLenMax: SaltLenMax,
RoundsDefault: RoundsDefault,
RoundsMin: RoundsMin,
RoundsMax: RoundsMax,
}
}

View file

@ -0,0 +1,254 @@
// Copyright 2012, Jeramey Crawford <jeramey@antihe.ro>
// Copyright 2013, Jonas mg
// All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file.
// Package sha512_crypt implements Ulrich Drepper's SHA512-crypt password
// hashing algorithm.
//
// The specification for this algorithm can be found here:
// http://www.akkadia.org/drepper/SHA-crypt.txt
package sha512_crypt
import (
"bytes"
"crypto/sha512"
"strconv"
"github.com/mickael-kerjean/server/plg_authenticate_htpasswd/vendor/crypt"
"github.com/mickael-kerjean/server/plg_authenticate_htpasswd/vendor/crypt/common"
)
func init() {
crypt.RegisterCrypt(crypt.SHA512, New, MagicPrefix)
}
const (
MagicPrefix = "$6$"
SaltLenMin = 1
SaltLenMax = 16
RoundsMin = 1000
RoundsMax = 999999999
RoundsDefault = 5000
)
var _rounds = []byte("rounds=")
type crypter struct{ Salt common.Salt }
// New returns a new crypt.Crypter computing the SHA512-crypt password hashing.
func New() crypt.Crypter {
return &crypter{GetSalt()}
}
func (c *crypter) Generate(key, salt []byte) (string, error) {
var rounds int
var isRoundsDef bool
if len(salt) == 0 {
salt = c.Salt.GenerateWRounds(SaltLenMax, RoundsDefault)
}
if !bytes.HasPrefix(salt, c.Salt.MagicPrefix) {
return "", common.ErrSaltPrefix
}
saltToks := bytes.Split(salt, []byte{'$'})
if len(saltToks) < 3 {
return "", common.ErrSaltFormat
}
if bytes.HasPrefix(saltToks[2], _rounds) {
isRoundsDef = true
pr, err := strconv.ParseInt(string(saltToks[2][7:]), 10, 32)
if err != nil {
return "", common.ErrSaltRounds
}
rounds = int(pr)
if rounds < RoundsMin {
rounds = RoundsMin
} else if rounds > RoundsMax {
rounds = RoundsMax
}
salt = saltToks[3]
} else {
rounds = RoundsDefault
salt = saltToks[2]
}
if len(salt) > SaltLenMax {
salt = salt[0:SaltLenMax]
}
// Compute alternate SHA512 sum with input KEY, SALT, and KEY.
Alternate := sha512.New()
Alternate.Write(key)
Alternate.Write(salt)
Alternate.Write(key)
AlternateSum := Alternate.Sum(nil) // 64 bytes
A := sha512.New()
A.Write(key)
A.Write(salt)
// Add for any character in the key one byte of the alternate sum.
i := len(key)
for ; i > 64; i -= 64 {
A.Write(AlternateSum)
}
A.Write(AlternateSum[0:i])
// Take the binary representation of the length of the key and for every add
// the alternate sum, for every 0 the key.
for i = len(key); i > 0; i >>= 1 {
if (i & 1) != 0 {
A.Write(AlternateSum)
} else {
A.Write(key)
}
}
Asum := A.Sum(nil)
// Start computation of P byte sequence.
P := sha512.New()
// For every character in the password add the entire password.
for i = 0; i < len(key); i++ {
P.Write(key)
}
Psum := P.Sum(nil)
// Create byte sequence P.
Pseq := make([]byte, 0, len(key))
for i = len(key); i > 64; i -= 64 {
Pseq = append(Pseq, Psum...)
}
Pseq = append(Pseq, Psum[0:i]...)
// Start computation of S byte sequence.
S := sha512.New()
for i = 0; i < (16 + int(Asum[0])); i++ {
S.Write(salt)
}
Ssum := S.Sum(nil)
// Create byte sequence S.
Sseq := make([]byte, 0, len(salt))
for i = len(salt); i > 64; i -= 64 {
Sseq = append(Sseq, Ssum...)
}
Sseq = append(Sseq, Ssum[0:i]...)
Csum := Asum
// Repeatedly run the collected hash value through SHA512 to burn CPU cycles.
for i = 0; i < rounds; i++ {
C := sha512.New()
// Add key or last result.
if (i & 1) != 0 {
C.Write(Pseq)
} else {
C.Write(Csum)
}
// Add salt for numbers not divisible by 3.
if (i % 3) != 0 {
C.Write(Sseq)
}
// Add key for numbers not divisible by 7.
if (i % 7) != 0 {
C.Write(Pseq)
}
// Add key or last result.
if (i & 1) != 0 {
C.Write(Csum)
} else {
C.Write(Pseq)
}
Csum = C.Sum(nil)
}
out := make([]byte, 0, 123)
out = append(out, c.Salt.MagicPrefix...)
if isRoundsDef {
out = append(out, []byte("rounds="+strconv.Itoa(rounds)+"$")...)
}
out = append(out, salt...)
out = append(out, '$')
out = append(out, common.Base64_24Bit([]byte{
Csum[42], Csum[21], Csum[0],
Csum[1], Csum[43], Csum[22],
Csum[23], Csum[2], Csum[44],
Csum[45], Csum[24], Csum[3],
Csum[4], Csum[46], Csum[25],
Csum[26], Csum[5], Csum[47],
Csum[48], Csum[27], Csum[6],
Csum[7], Csum[49], Csum[28],
Csum[29], Csum[8], Csum[50],
Csum[51], Csum[30], Csum[9],
Csum[10], Csum[52], Csum[31],
Csum[32], Csum[11], Csum[53],
Csum[54], Csum[33], Csum[12],
Csum[13], Csum[55], Csum[34],
Csum[35], Csum[14], Csum[56],
Csum[57], Csum[36], Csum[15],
Csum[16], Csum[58], Csum[37],
Csum[38], Csum[17], Csum[59],
Csum[60], Csum[39], Csum[18],
Csum[19], Csum[61], Csum[40],
Csum[41], Csum[20], Csum[62],
Csum[63],
})...)
// Clean sensitive data.
A.Reset()
Alternate.Reset()
P.Reset()
for i = 0; i < len(Asum); i++ {
Asum[i] = 0
}
for i = 0; i < len(AlternateSum); i++ {
AlternateSum[i] = 0
}
for i = 0; i < len(Pseq); i++ {
Pseq[i] = 0
}
return string(out), nil
}
func (c *crypter) Verify(hashedKey string, key []byte) error {
newHash, err := c.Generate(key, []byte(hashedKey))
if err != nil {
return err
}
if newHash != hashedKey {
return crypt.ErrKeyMismatch
}
return nil
}
func (c *crypter) Cost(hashedKey string) (int, error) {
saltToks := bytes.Split([]byte(hashedKey), []byte{'$'})
if len(saltToks) < 3 {
return 0, common.ErrSaltFormat
}
if !bytes.HasPrefix(saltToks[2], _rounds) {
return RoundsDefault, nil
}
roundToks := bytes.Split(saltToks[2], []byte{'='})
cost, err := strconv.ParseInt(string(roundToks[1]), 10, 0)
return int(cost), err
}
func (c *crypter) SetSalt(salt common.Salt) { c.Salt = salt }
func GetSalt() common.Salt {
return common.Salt{
MagicPrefix: []byte(MagicPrefix),
SaltLenMin: SaltLenMin,
SaltLenMax: SaltLenMax,
RoundsDefault: RoundsDefault,
RoundsMin: RoundsMin,
RoundsMax: RoundsMax,
}
}