-
Notifications
You must be signed in to change notification settings - Fork 54
/
scram.go
66 lines (58 loc) · 1.48 KB
/
scram.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
package auth
import (
"crypto/hmac"
"crypto/rand"
"crypto/sha256"
"fmt"
)
const (
clientChallengeSize = 64
serverChallengeSize = 48
saltSize = 16
clientProofSize = 32
)
func checkSalt(salt []byte) error {
if len(salt) != saltSize {
return fmt.Errorf("invalid salt size %d - expected %d", len(salt), saltSize)
}
return nil
}
func checkServerChallenge(serverChallenge []byte) error {
if len(serverChallenge) != serverChallengeSize {
return fmt.Errorf("invalid server challenge size %d - expected %d", len(serverChallenge), serverChallengeSize)
}
return nil
}
func clientChallenge() []byte {
r := make([]byte, clientChallengeSize)
if _, err := rand.Read(r); err != nil {
panic(err)
}
return r
}
func clientProof(key, salt, serverChallenge, clientChallenge []byte) ([]byte, error) {
if len(key) != clientProofSize {
return nil, fmt.Errorf("invalid key size %d - expected %d", len(key), clientProofSize)
}
sig := _hmac(_sha256(key), salt, serverChallenge, clientChallenge)
if len(sig) != clientProofSize {
return nil, fmt.Errorf("invalid sig size %d - expected %d", len(key), clientProofSize)
}
// xor sig and key into sig (inline: no further allocation).
for i, v := range key {
sig[i] ^= v
}
return sig, nil
}
func _sha256(p []byte) []byte {
hash := sha256.New()
hash.Write(p)
return hash.Sum(nil)
}
func _hmac(key []byte, prms ...[]byte) []byte {
hash := hmac.New(sha256.New, key)
for _, p := range prms {
hash.Write(p)
}
return hash.Sum(nil)
}