-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpassword.go
More file actions
86 lines (73 loc) · 3.18 KB
/
password.go
File metadata and controls
86 lines (73 loc) · 3.18 KB
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
package faroe
import (
"context"
"crypto/rand"
"crypto/subtle"
"errors"
"fmt"
)
func (server *ServerStruct) hashPassword(algorithm PasswordHashAlgorithmInterface, secret string) ([]byte, []byte, error) {
salt := make([]byte, algorithm.SaltSize())
_, _ = rand.Read(salt)
server.passwordHashingSemaphore.Acquire(context.Background(), 1)
hash, err := algorithm.Hash(secret, salt)
server.passwordHashingSemaphore.Release(1)
if err != nil {
return nil, nil, fmt.Errorf("failed to hash secret with %s: %s", algorithm.Id(), err.Error())
}
return hash, salt, nil
}
func (server *ServerStruct) verifyPasswordAgainstHash(algorithm PasswordHashAlgorithmInterface, password string, hash []byte, salt []byte) (bool, error) {
server.passwordHashingSemaphore.Acquire(context.Background(), 1)
hashed, err := algorithm.Hash(password, salt)
server.passwordHashingSemaphore.Release(1)
if err != nil {
return false, fmt.Errorf("failed to hash secret with %s: %s", algorithm.Id(), err.Error())
}
equaled := subtle.ConstantTimeCompare(hashed, hash) == 1
return equaled, nil
}
func (server *ServerStruct) hashUserPassword(userPassword string) ([]byte, string, []byte, error) {
algorithm := server.userPasswordHashAlgorithms[0]
hash, salt, err := server.hashPassword(algorithm, userPassword)
if err != nil {
return nil, "", nil, fmt.Errorf("failed to hash user password: %s", err.Error())
}
return hash, algorithm.Id(), salt, nil
}
func (server *ServerStruct) verifyUserPassword(password string, passwordHash []byte, hashAlgorithmId string, passwordSalt []byte) (bool, error) {
for _, algorithm := range server.userPasswordHashAlgorithms {
if algorithm.Id() == hashAlgorithmId {
valid, err := server.verifyPasswordAgainstHash(algorithm, password, passwordHash, passwordSalt)
if err != nil {
return false, fmt.Errorf("failed to verify user password against hash: %s", err.Error())
}
return valid, nil
}
}
return false, errHashAlgorithmNotSupported
}
func (server *ServerStruct) hashTemporaryPassword(temporaryPassword string) ([]byte, string, []byte, error) {
hash, salt, err := server.hashPassword(server.temporaryPasswordHashAlgorithm, temporaryPassword)
if err != nil {
return nil, "", nil, fmt.Errorf("failed to hash user password with %s: %s", server.temporaryPasswordHashAlgorithm.Id(), err.Error())
}
return hash, server.temporaryPasswordHashAlgorithm.Id(), salt, nil
}
func (server *ServerStruct) verifyTemporaryPassword(temporaryPassword string, temporaryPasswordHash []byte, hashAlgorithmId string, temporaryPasswordSalt []byte) (bool, error) {
if server.temporaryPasswordHashAlgorithm.Id() != hashAlgorithmId {
return false, errHashAlgorithmNotSupported
}
valid, err := server.verifyPasswordAgainstHash(server.temporaryPasswordHashAlgorithm, temporaryPassword, temporaryPasswordHash, temporaryPasswordSalt)
if err != nil {
return false, fmt.Errorf("failed to verify temporary password against hash: %s", err.Error())
}
return valid, nil
}
var errHashAlgorithmNotSupported = errors.New("hash algorithm not supported")
type PasswordHashAlgorithmInterface interface {
// A unique identifier of this algorithm.
Id() string
SaltSize() int
Hash(password string, salt []byte) ([]byte, error)
}