forked from tg123/go-htpasswd
-
Notifications
You must be signed in to change notification settings - Fork 0
/
cryptsha.go
92 lines (75 loc) · 2.24 KB
/
cryptsha.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package htpasswd
import (
"fmt"
"strings"
"github.com/GehirnInc/crypt"
_ "github.com/GehirnInc/crypt/sha256_crypt"
_ "github.com/GehirnInc/crypt/sha512_crypt"
)
type cryptPassword struct {
prefix string
rounds string
salt string
hashed string
}
// Prefixes
const PrefixCryptSha256 = "$5$"
const PrefixCryptSha512 = "$6$"
const Separator = "$"
// Accepts valid passwords
func AcceptCryptSha(src string) (EncodedPasswd, error) {
if !strings.HasPrefix(src, PrefixCryptSha256) && !strings.HasPrefix(src, PrefixCryptSha512) {
return nil, nil
}
prefix := PrefixCryptSha512
if strings.HasPrefix(src, PrefixCryptSha256) {
prefix = PrefixCryptSha256
}
rest := strings.TrimPrefix(src, prefix)
mparts := strings.SplitN(rest, "$", 3)
if len(mparts) < 2 {
return nil, fmt.Errorf("malformed crypt-SHA password: %s", src)
}
var rounds, salt, hashed string
// Do we have a "rounds-component"
if len(mparts) == 3 {
rounds, salt, hashed = mparts[0], mparts[1], mparts[2]
} else {
salt, hashed = mparts[0], mparts[1]
}
if len(salt) > 16 {
salt = salt[0:16]
}
return &cryptPassword{prefix, rounds, salt, hashed}, nil
}
// PK04832_45b047bab2bf:$6$rounds=5000$e4fb4910470fd97e$afWSvXIlcC4KnENaYStPG/ELJ.uBAnG7r/rFz8fkNwpkU.salSCchDjtxyh.qA.fftcd5hmIcem7A4oA76HCE0
// RejectCryptSha known indexes
func RejectCryptSha(src string) (EncodedPasswd, error) {
if !strings.HasPrefix(src, PrefixCryptSha512) && !strings.HasPrefix(src, PrefixCryptSha256) {
return nil, nil
}
return nil, fmt.Errorf("crypt-sha password rejected: %s", src)
}
func shaCrypt(password string, rounds string, salt string, prefix string) string {
var ret string
var sb strings.Builder
sb.WriteString(prefix)
if len(rounds) > 0 {
sb.WriteString(rounds)
sb.WriteString(Separator)
}
sb.WriteString(salt)
totalSalt := sb.String()
if prefix == PrefixCryptSha512 {
crypt := crypt.SHA512.New()
ret, _ = crypt.Generate([]byte(password), []byte(totalSalt))
} else if prefix == PrefixCryptSha256 {
crypt := crypt.SHA256.New()
ret, _ = crypt.Generate([]byte(password), []byte(totalSalt))
}
return ret[len(totalSalt)+1:]
}
func (m *cryptPassword) MatchesPassword(pw string) bool {
hashed := shaCrypt(pw, m.rounds, m.salt, m.prefix)
return constantTimeEquals(hashed, m.hashed)
}