-
Notifications
You must be signed in to change notification settings - Fork 0
/
argon2.go
59 lines (46 loc) · 1.38 KB
/
argon2.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
package main
import (
"crypto/rand"
"crypto/subtle"
"encoding/base64"
"fmt"
"strings"
"golang.org/x/crypto/argon2"
)
type argon2Config struct {
time uint32
memory uint32
threads uint8
keyLen uint32
}
func generateArgonHash(c *argon2Config, password string) (string, error) {
salt := make([]byte, 16)
if _, err := rand.Read(salt); err != nil {
return "", err
}
hash := argon2.IDKey([]byte(password), salt, c.time, c.memory, c.threads, c.keyLen)
b64Salt := base64.RawStdEncoding.EncodeToString(salt)
b64Hash := base64.RawStdEncoding.EncodeToString(hash)
format := "$argon2id$v=%d$m=%d,t=%d,p=%d$%s$%s"
full := fmt.Sprintf(format, argon2.Version, c.memory, c.time, c.threads, b64Salt, b64Hash)
return full, nil
}
func compareWithArgonHash(password, hash string) (bool, error) {
parts := strings.Split(hash, "$")
c := &argon2Config{}
_, err := fmt.Sscanf(parts[3], "m=%d,t=%d,p=%d", &c.memory, &c.time, &c.threads)
if err != nil {
return false, err
}
salt, err := base64.RawStdEncoding.DecodeString(parts[4])
if err != nil {
return false, err
}
decodedHash, err := base64.RawStdEncoding.DecodeString(parts[5])
if err != nil {
return false, err
}
c.keyLen = uint32(len(decodedHash))
comparisonHash := argon2.IDKey([]byte(password), salt, c.time, c.memory, c.threads, c.keyLen)
return (subtle.ConstantTimeCompare(decodedHash, comparisonHash) == 1), nil
}