1 package crypto
2
3 import (
4 "crypto/sha512"
5 "encoding/hex"
6
7 "github.com/xdg-go/pbkdf2"
8
9 "edge-infra.dev/pkg/lib/crypto/randomizer"
10 "edge-infra.dev/pkg/lib/crypto/validation"
11 )
12
13 type pbkdf2Credential struct {
14 plainTextPwd string
15 hashedPwd []byte
16 iterations int
17 salt []byte
18 }
19
20 func (pwd pbkdf2Credential) Salt() ([]byte, error) {
21 return pwd.salt, nil
22 }
23
24 func (pwd pbkdf2Credential) Iterations() (int, error) {
25 return pwd.iterations, nil
26 }
27
28 func (pwd pbkdf2Credential) HashFunction() string {
29 return string(pbkdf2Type)
30 }
31
32 func (pwd pbkdf2Credential) HashType() string {
33 return pbkdf2Type.Type()
34 }
35
36 func (pwd pbkdf2Credential) Hashed() []byte {
37 return pwd.hashedPwd
38 }
39
40 func (pwd pbkdf2Credential) Plain() string {
41 return pwd.plainTextPwd
42 }
43
44
45 func GenerateRandomPbkdf2Password(minLength, maxLength, iterations, saltLength, keyLength int) (Credential, error) {
46 if err := validation.ValidatePwdBounds(minLength, maxLength); err != nil {
47 return nil, err
48 }
49
50 pwdLen, err := randomizer.RandomPassLength(minLength, maxLength)
51 if err != nil {
52 return nil, err
53 }
54
55 if err := validation.ValidateSaltLength(saltLength); err != nil {
56 return nil, err
57 }
58
59 if err := validation.ValidateIterationLen(iterations); err != nil {
60 return nil, err
61 }
62
63 if err = validation.ValidateKeyLen(keyLength, saltLength); err != nil {
64 return nil, err
65 }
66
67 pwd, err := randomizer.GenerateRandomPlainPwd(pwdLen)
68 if err != nil {
69 return nil, err
70 }
71
72 salt, err := randomizer.GenerateRandomSalt(saltLength)
73 if err != nil {
74 return nil, err
75 }
76
77 hashedPwd := hashPbkdf2([]byte(pwd), []byte(salt), iterations, keyLength)
78 return pbkdf2Credential{plainTextPwd: pwd, hashedPwd: hashedPwd, iterations: iterations, salt: []byte(salt)}, nil
79 }
80
81 func GeneratePbkdf2Password(pwd string, iterations, saltLength, keyLength int) (Credential, error) {
82 if err := validation.ValidatePwdLen(len(pwd)); err != nil {
83 return nil, err
84 }
85
86 if err := validation.ValidateSaltLength(saltLength); err != nil {
87 return nil, err
88 }
89
90 if err := validation.ValidateIterationLen(iterations); err != nil {
91 return nil, err
92 }
93
94 if err := validation.ValidateKeyLen(keyLength, saltLength); err != nil {
95 return nil, err
96 }
97
98 salt, err := randomizer.GenerateRandomSalt(saltLength)
99 if err != nil {
100 return nil, err
101 }
102
103 hashedPwd := hashPbkdf2([]byte(pwd), []byte(salt), iterations, keyLength)
104 return pbkdf2Credential{plainTextPwd: pwd, hashedPwd: hashedPwd, iterations: iterations, salt: []byte(salt)}, nil
105 }
106
107 func hashPbkdf2(pwd, salt []byte, iterations, keyLength int) []byte {
108 return pbkdf2.Key(pwd, salt, iterations, keyLength, sha512.New)
109 }
110
111 func ComparePbkdf2HashAndPassword(hash, salt []byte, pwd string, iterations, keyLength int) bool {
112 pwdHash := hashPbkdf2([]byte(pwd), salt, iterations, keyLength)
113 return hex.EncodeToString(pwdHash) == hex.EncodeToString(hash)
114 }
115
View as plain text