htpasswd: implement sha256 and sha512 algorithms
Signed-off-by: Nagy Károly Gábriel <k@jpi.io>
This commit is contained in:
@@ -5,6 +5,8 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
|
"crypto/sha256"
|
||||||
|
"crypto/sha512"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -30,6 +32,10 @@ const (
|
|||||||
HashSHA HashAlgorithm = "sha"
|
HashSHA HashAlgorithm = "sha"
|
||||||
// HashSSHA Salted SHA
|
// HashSSHA Salted SHA
|
||||||
HashSSHA HashAlgorithm = "ssha"
|
HashSSHA HashAlgorithm = "ssha"
|
||||||
|
// HashSHA256 256 variant of SHA
|
||||||
|
HashSHA256 HashAlgorithm = "sha256"
|
||||||
|
// HashSHA512 512 variant of SHA
|
||||||
|
HashSHA512 HashAlgorithm = "sha512"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ParseHtpasswdFile parses a .htpasswd file
|
// ParseHtpasswdFile parses a .htpasswd file
|
||||||
@@ -174,6 +180,10 @@ func verifyPass(pass, hash string, alg HashAlgorithm) error {
|
|||||||
return verifySHA(pass, hash)
|
return verifySHA(pass, hash)
|
||||||
case HashSSHA:
|
case HashSSHA:
|
||||||
return verifySSHA(pass, hash)
|
return verifySSHA(pass, hash)
|
||||||
|
case HashSHA256:
|
||||||
|
return verifySHA256(pass, hash)
|
||||||
|
case HashSHA512:
|
||||||
|
return verifySHA512(pass, hash)
|
||||||
}
|
}
|
||||||
return fmt.Errorf("unsupported hash algorithm %v", alg)
|
return fmt.Errorf("unsupported hash algorithm %v", alg)
|
||||||
}
|
}
|
||||||
@@ -235,6 +245,53 @@ func verifySSHA(password, hashedPassword string) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func verifySHA256(password, hashedPassword string) error {
|
||||||
|
eppS := hashedPassword[3:]
|
||||||
|
hash, err := base64.StdEncoding.DecodeString(eppS)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("cannot base64 decode")
|
||||||
|
}
|
||||||
|
|
||||||
|
sha := sha256.New()
|
||||||
|
_, err = sha.Write([]byte(password))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
sum := sha.Sum(nil)
|
||||||
|
|
||||||
|
if !bytes.Equal(sum, hash) {
|
||||||
|
return fmt.Errorf("wrong password")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifySHA512(password, hashedPassword string) error {
|
||||||
|
eppS := hashedPassword[3:]
|
||||||
|
hash, err := base64.StdEncoding.DecodeString(eppS)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("cannot base64 decode")
|
||||||
|
}
|
||||||
|
|
||||||
|
sha := sha512.New()
|
||||||
|
_, err = sha.Write([]byte(password))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
sum := sha.Sum(nil)
|
||||||
|
|
||||||
|
if !bytes.Equal(sum, hash) {
|
||||||
|
return fmt.Errorf("wrong password")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (pp Passwds) toByte() []byte {
|
func (pp Passwds) toByte() []byte {
|
||||||
pass := []byte{}
|
pass := []byte{}
|
||||||
for name, hash := range pp {
|
for name, hash := range pp {
|
||||||
@@ -254,6 +311,10 @@ func identifyHash(h string) (HashAlgorithm, error) {
|
|||||||
return HashSHA, nil
|
return HashSHA, nil
|
||||||
case strings.HasPrefix(h, "{SSHA}"):
|
case strings.HasPrefix(h, "{SSHA}"):
|
||||||
return HashSSHA, nil
|
return HashSSHA, nil
|
||||||
|
case strings.HasPrefix(h, "$5$"):
|
||||||
|
return HashSHA256, nil
|
||||||
|
case strings.HasPrefix(h, "$6$"):
|
||||||
|
return HashSHA512, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", fmt.Errorf("unsupported hash algorithm")
|
return "", fmt.Errorf("unsupported hash algorithm")
|
||||||
@@ -274,6 +335,12 @@ func createHash(passwd string, algo HashAlgorithm) (string, error) {
|
|||||||
case HashSSHA:
|
case HashSSHA:
|
||||||
prefix = "{SSHA}"
|
prefix = "{SSHA}"
|
||||||
hash, err = hashSSha(passwd)
|
hash, err = hashSSha(passwd)
|
||||||
|
case HashSHA256:
|
||||||
|
prefix = "$5$"
|
||||||
|
hash, err = hashSha256(passwd)
|
||||||
|
case HashSHA512:
|
||||||
|
prefix = "$6$"
|
||||||
|
hash, err = hashSha512(passwd)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@@ -303,6 +370,27 @@ func hashSha(passwd string) (string, error) {
|
|||||||
passwordSum := []byte(s.Sum(nil))
|
passwordSum := []byte(s.Sum(nil))
|
||||||
return base64.StdEncoding.EncodeToString(passwordSum), nil
|
return base64.StdEncoding.EncodeToString(passwordSum), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func hashSha256(passwd string) (string, error) {
|
||||||
|
s := sha256.New()
|
||||||
|
_, err := s.Write([]byte(passwd))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
passwordSum := []byte(s.Sum(nil))
|
||||||
|
return base64.StdEncoding.EncodeToString(passwordSum), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func hashSha512(passwd string) (string, error) {
|
||||||
|
s := sha512.New()
|
||||||
|
_, err := s.Write([]byte(passwd))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
passwordSum := []byte(s.Sum(nil))
|
||||||
|
return base64.StdEncoding.EncodeToString(passwordSum), nil
|
||||||
|
}
|
||||||
|
|
||||||
func hashSSha(passwd string) (string, error) {
|
func hashSSha(passwd string) (string, error) {
|
||||||
s := sha1.New()
|
s := sha1.New()
|
||||||
_, err := s.Write([]byte(passwd))
|
_, err := s.Write([]byte(passwd))
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ func TestCreateUser(t *testing.T) {
|
|||||||
{"bcrypt", "123456@", HashBCrypt, nil},
|
{"bcrypt", "123456@", HashBCrypt, nil},
|
||||||
{"ssha", "123456@", HashSSHA, nil},
|
{"ssha", "123456@", HashSSHA, nil},
|
||||||
{"sha", "123456@", HashSHA, nil},
|
{"sha", "123456@", HashSHA, nil},
|
||||||
|
{"sha256", "123456@", HashSHA256, nil},
|
||||||
|
{"sha512", "123456@", HashSHA512, nil},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
@@ -62,6 +64,8 @@ func TestVerifyPassword(t *testing.T) {
|
|||||||
{"bcrypt", "123456@", nil},
|
{"bcrypt", "123456@", nil},
|
||||||
{"ssha", "123456@", nil},
|
{"ssha", "123456@", nil},
|
||||||
{"sha", "123456@", nil},
|
{"sha", "123456@", nil},
|
||||||
|
{"sha256", "123456@", nil},
|
||||||
|
{"sha512", "123456@", nil},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
bcrypt:$2a$10$9NdvqvFl9Yz9FM2D.i9Na.K1CiNF1ldk9hgRR57lYJiRBUnGt2THq
|
apr1:$apr1$v0FnbGJM$b2P3y1ltZYHakDaHrWx3N1
|
||||||
ssha:{SSHA}7fPHbfKv92vC/IFhKdnEKSTBKubvta9a
|
bcrypt:$2a$10$pBSUext6NDsFYrm8GviW.OFe6SczH91INRC3YmsfE3HJp/fPmRaee
|
||||||
|
ssha:{SSHA}LoTRQgCdeGIeJ3nxDQMCmQSWdnMEsLqj
|
||||||
|
sha512:$6$78RjySv19bx/knbdL6q1cpoV8WblZwc3x+wmPGQUvrSycxc4liKbksvDr9HZj76hgRuZZCyEngP+WEJmePArCQ==
|
||||||
sha:{SHA}YEn9/RmoXLdbyB9TEDJ0OqWoPy8=
|
sha:{SHA}YEn9/RmoXLdbyB9TEDJ0OqWoPy8=
|
||||||
apr1:$apr1$U9.3kynN$MCKs53Oz35J0OYrSxfheW.
|
sha256:$5$ufJ2S16IOhB6XLTGrVLqGQBKv/odjE3rypxnUDLqaS0=
|
||||||
|
|||||||
Reference in New Issue
Block a user