Browse Source

htpasswd: implement sha256 and sha512 algorithms

Signed-off-by: Nagy Károly Gábriel <k@jpi.io>
pull/2/head
parent
commit
6a24de7687
Signed by: karasz
GPG Key ID: FA002E83BC206F83
  1. 88
      htpasswd/htpasswd.go
  2. 4
      htpasswd/htpasswd_test.go
  3. 8
      htpasswd/htpasswd_testdata

88
htpasswd/htpasswd.go

@ -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))

4
htpasswd/htpasswd_test.go

@ -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 {

8
htpasswd/htpasswd_testdata

@ -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=

Loading…
Cancel
Save