Skip to content

Commit 5e8fd3a

Browse files
committed
优化 argon2
1 parent 7582611 commit 5e8fd3a

File tree

4 files changed

+185
-93
lines changed

4 files changed

+185
-93
lines changed

passhash/argon2/argon2.go

Lines changed: 56 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,36 @@ import (
1010
"crypto/subtle"
1111
"encoding/base64"
1212

13-
"golang.org/x/crypto/argon2"
13+
"github.com/deatil/go-cryptobin/kdf/argon2"
1414
)
1515

16-
// 配置
17-
type Opt struct {
16+
// Argon2 Type enum
17+
type Argon2Type uint
18+
19+
func (typ Argon2Type) String() string {
20+
switch typ {
21+
case Argon2d:
22+
return "argon2d"
23+
case Argon2i:
24+
return "argon2i"
25+
case Argon2id:
26+
return "argon2id"
27+
case Argon2:
28+
return "argon2"
29+
default:
30+
return "unknown multiple value " + strconv.Itoa(int(typ))
31+
}
32+
}
33+
34+
const (
35+
Argon2d Argon2Type = iota
36+
Argon2i
37+
Argon2id
38+
Argon2
39+
)
40+
41+
// Argon2 options
42+
type Opts struct {
1843
SaltLen int
1944
Time uint32
2045
Memory uint32
@@ -23,11 +48,11 @@ type Opt struct {
2348
}
2449

2550
var (
26-
// 默认类型
27-
defaultType = "argon2id"
51+
// default Type
52+
defaultType = Argon2id
2853

29-
// 默认配置
30-
defaultOpt = Opt{
54+
// default Options
55+
defaultOpts = Opts{
3156
SaltLen: 32,
3257
Time: 1,
3358
Memory: 64 * 1024,
@@ -36,18 +61,18 @@ var (
3661
}
3762
)
3863

39-
// 生成密钥
64+
// Generate Salted Hash
4065
func GenerateSaltedHash(random io.Reader, password string) (string, error) {
41-
return GenerateSaltedHashWithTypeAndOpt(random, password, defaultType, defaultOpt)
66+
return GenerateSaltedHashWithTypeAndOpts(random, password, defaultType, defaultOpts)
4267
}
4368

44-
// 生成密钥带类型
45-
func GenerateSaltedHashWithType(random io.Reader, password string, typ string) (string, error) {
46-
return GenerateSaltedHashWithTypeAndOpt(random, password, typ, defaultOpt)
69+
// Generate Salted Hash with type
70+
func GenerateSaltedHashWithType(random io.Reader, password string, typ Argon2Type) (string, error) {
71+
return GenerateSaltedHashWithTypeAndOpts(random, password, typ, defaultOpts)
4772
}
4873

49-
// 生成密钥带类型和设置
50-
func GenerateSaltedHashWithTypeAndOpt(random io.Reader, password string, typ string, opt Opt) (string, error) {
74+
// Generate Salted Hash with type and opts
75+
func GenerateSaltedHashWithTypeAndOpts(random io.Reader, password string, typ Argon2Type, opt Opts) (string, error) {
5176
if len(password) == 0 {
5277
return "", errors.New("go-cryptobin/argon2: Password length cannot be 0")
5378
}
@@ -62,18 +87,24 @@ func GenerateSaltedHashWithTypeAndOpt(random io.Reader, password string, typ str
6287

6388
var unencodedPassword []byte
6489
switch typ {
65-
case "argon2id":
90+
case Argon2id:
6691
unencodedPassword = argon2.IDKey(
6792
[]byte(password), []byte(salt),
6893
argon2Time, argon2Memory,
6994
argon2Threads, argon2KeyLen,
7095
)
71-
case "argon2i", "argon2":
96+
case Argon2i, Argon2:
7297
unencodedPassword = argon2.Key(
7398
[]byte(password), []byte(salt),
7499
argon2Time, argon2Memory,
75100
argon2Threads, argon2KeyLen,
76101
)
102+
case Argon2d:
103+
unencodedPassword = argon2.DKey(
104+
[]byte(password), []byte(salt),
105+
argon2Time, argon2Memory,
106+
argon2Threads, argon2KeyLen,
107+
)
77108
default:
78109
return "", errors.New("go-cryptobin/argon2: Invalid Hash Type")
79110
}
@@ -82,7 +113,7 @@ func GenerateSaltedHashWithTypeAndOpt(random io.Reader, password string, typ str
82113

83114
hash := fmt.Sprintf(
84115
"%s$%d$%d$%d$%d$%s$%s",
85-
typ, argon2Time,
116+
typ.String(), argon2Time,
86117
argon2Memory, argon2Threads,
87118
argon2KeyLen, salt,
88119
encodedPassword,
@@ -91,7 +122,7 @@ func GenerateSaltedHashWithTypeAndOpt(random io.Reader, password string, typ str
91122
return hash, nil
92123
}
93124

94-
// 验证密钥
125+
// Compare Hash With Password
95126
func CompareHashWithPassword(hash, password string) (bool, error) {
96127
if len(hash) == 0 || len(password) == 0 {
97128
return false, errors.New("go-cryptobin/argon2: Arguments cannot be zero length")
@@ -124,6 +155,12 @@ func CompareHashWithPassword(hash, password string) (bool, error) {
124155
uint32(time), uint32(memory),
125156
uint8(threads), uint32(keyLen),
126157
)
158+
case "argon2d":
159+
calculatedKey = argon2.DKey(
160+
[]byte(password), salt,
161+
uint32(time), uint32(memory),
162+
uint8(threads), uint32(keyLen),
163+
)
127164
default:
128165
return false, errors.New("go-cryptobin/argon2: Invalid Password Hash")
129166
}
@@ -135,6 +172,7 @@ func CompareHashWithPassword(hash, password string) (bool, error) {
135172
return true, nil
136173
}
137174

175+
// generate salt with length
138176
func generateSalt(random io.Reader, length int) (string, error) {
139177
unencodedSalt := make([]byte, length)
140178

passhash/argon2/argon2_test.go

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ func Test_GenerateSaltedHash(t *testing.T) {
2727
t.Errorf("GenerateSaltedHash() = %v, want %v", err, tt.wantErr)
2828
return
2929
}
30+
3031
if len(hashSegments) != tt.hashSegments {
3132
t.Errorf("GenerateSaltedHash() had %d segments. Want %d", len(hashSegments), tt.hashSegments)
3233
}
@@ -52,6 +53,7 @@ func Test_CompareHashWithPassword(t *testing.T) {
5253
{"Should Work 2", `argon2$4$32768$4$32$/WN2BY5NDzVlHYgw3pqahA==$oLGdDy23gAgbQXmphVVPG0Uax+XbfeUfH/TCpQbEHfc=`, `Y&jEA)_m7q@jb@J"<sXrS]HH"zU`, true, false},
5354
{"Should Not Work 4", `argon2$4$32768$4$32$/WN2BY5NDzVlHYgw3pqahA==$XLGdDy23gAgbQXmphVVPG0Uax+XbfeUfH/TCpQbEHfc=`, `Y&XEA)_m7q@jb@J"<sXrS]HH"zU`, false, true},
5455
{"Should Not Work 5", `argon2$32768$4$32$/WN2BY5NDzVlHYgw3pqahA==$XLGdDy23gAgbQXmphVVPG0Uax+XbfeUfH/TCpQbEHfc=`, `Y&XEA)_m7q@jb@J"<sXrS]HH"zU`, false, true},
56+
{"Should Work 3", `argon2d$1$65536$4$32$9oPeGkhyrfkDBbrGO8Kp4QEurO7dXuJz7V02/4xzzUY=$dlWao4wXOuKsBESejJsfcCwqA+g7/jc5tKK+z7yxdBE=`, `Y&jEA)_m7q@jb@J"<sXrS]HH"zU`, true, false},
5557
}
5658
for _, tt := range tests {
5759
t.Run(tt.name, func(t *testing.T) {
@@ -72,18 +74,22 @@ func Test_CompareHashWithPassword(t *testing.T) {
7274
func Test_GenerateSaltedHashWithType(t *testing.T) {
7375
tests := []struct {
7476
name string
75-
typ string
77+
typ Argon2Type
7678
password string
7779
hashSegments int
7880
hashLength int
7981
wantErr bool
8082
}{
81-
{"Should Work", "argon2id", "Password1", 7, 111, false},
82-
{"Should Not Work", "argon2id", "", 1, 0, true},
83-
{"Should Work 2", "argon2id", "gS</5Tu>3@(<FCtY", 7, 111, false},
84-
{"Should Work 3", "argon2id", `Y&jEA)_m7q@jb@J"<sXrS]HH"zU`, 7, 111, false},
85-
{"Should Work 31", "argon2i", `Y&jEA)_m7q@jb@J"<sXrS]HH"zU`, 7, 110, false},
86-
{"Should Not Work 2", "argon2i", "", 1, 0, true},
83+
{"Should Work", Argon2id, "Password1", 7, 111, false},
84+
{"Should Not Work", Argon2id, "", 1, 0, true},
85+
{"Should Work 2", Argon2id, "gS</5Tu>3@(<FCtY", 7, 111, false},
86+
{"Should Work 3", Argon2id, `Y&jEA)_m7q@jb@J"<sXrS]HH"zU`, 7, 111, false},
87+
{"Should Work 31", Argon2i, `Y&jEA)_m7q@jb@J"<sXrS]HH"zU`, 7, 110, false},
88+
{"Should Not Work 2", Argon2i, "", 1, 0, true},
89+
{"Should Work 5", Argon2d, `Y&jEA)_m7q@jb@J"<sXrS]HH"zU`, 7, 110, false},
90+
{"Should Not Work 3", Argon2d, "", 1, 0, true},
91+
{"Should Work 6", Argon2, `Y&jEA)_m7q@jb@J"<sXrS]HH"zU`, 7, 109, false},
92+
{"Should Not Work 6", Argon2, "", 1, 0, true},
8793
}
8894
for _, tt := range tests {
8995
t.Run(tt.name, func(t *testing.T) {

passhash/argon2fmt/argon2fmt.go

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,30 @@ import (
1313
"github.com/deatil/go-cryptobin/kdf/argon2"
1414
)
1515

16-
// 配置
17-
type Opt struct {
16+
// Argon2 Type enum
17+
type Argon2Type uint
18+
19+
func (typ Argon2Type) String() string {
20+
switch typ {
21+
case Argon2d:
22+
return "argon2d"
23+
case Argon2i:
24+
return "argon2i"
25+
case Argon2id:
26+
return "argon2id"
27+
default:
28+
return "unknown multiple value " + strconv.Itoa(int(typ))
29+
}
30+
}
31+
32+
const (
33+
Argon2d Argon2Type = iota
34+
Argon2i
35+
Argon2id
36+
)
37+
38+
// Argon2 options
39+
type Opts struct {
1840
SaltLen int
1941
Time uint32
2042
Memory uint32
@@ -23,11 +45,11 @@ type Opt struct {
2345
}
2446

2547
var (
26-
// 默认类型
27-
defaultType = "argon2id"
48+
// default Type
49+
defaultType = Argon2id
2850

29-
// 默认配置
30-
defaultOpt = Opt{
51+
// default Options
52+
defaultOpts = Opts{
3153
SaltLen: 32,
3254
Time: 1,
3355
Memory: 64 * 1024,
@@ -36,18 +58,18 @@ var (
3658
}
3759
)
3860

39-
// 生成密钥
61+
// Generate Salted Hash
4062
func GenerateSaltedHash(random io.Reader, password string) (string, error) {
41-
return GenerateSaltedHashWithTypeAndOpt(random, password, defaultType, defaultOpt)
63+
return GenerateSaltedHashWithTypeAndOpts(random, password, defaultType, defaultOpts)
4264
}
4365

44-
// 生成密钥带类型
45-
func GenerateSaltedHashWithType(random io.Reader, password string, typ string) (string, error) {
46-
return GenerateSaltedHashWithTypeAndOpt(random, password, typ, defaultOpt)
66+
// Generate Salted Hash with type
67+
func GenerateSaltedHashWithType(random io.Reader, password string, typ Argon2Type) (string, error) {
68+
return GenerateSaltedHashWithTypeAndOpts(random, password, typ, defaultOpts)
4769
}
4870

49-
// 生成密钥带类型和设置
50-
func GenerateSaltedHashWithTypeAndOpt(random io.Reader, password string, typ string, opt Opt) (string, error) {
71+
// Generate Salted Hash with type and opts
72+
func GenerateSaltedHashWithTypeAndOpts(random io.Reader, password string, typ Argon2Type, opt Opts) (string, error) {
5173
if len(password) == 0 {
5274
return "", errors.New("go-cryptobin/argon2fmt: Password length cannot be 0")
5375
}
@@ -65,19 +87,19 @@ func GenerateSaltedHashWithTypeAndOpt(random io.Reader, password string, typ str
6587

6688
var unencodedPassword []byte
6789
switch typ {
68-
case "argon2id":
90+
case Argon2id:
6991
unencodedPassword = argon2.IDKey(
7092
[]byte(password), salt,
7193
argon2Time, argon2Memory,
7294
argon2Threads, argon2KeyLen,
7395
)
74-
case "argon2i":
96+
case Argon2i:
7597
unencodedPassword = argon2.Key(
7698
[]byte(password), salt,
7799
argon2Time, argon2Memory,
78100
argon2Threads, argon2KeyLen,
79101
)
80-
case "argon2d":
102+
case Argon2d:
81103
unencodedPassword = argon2.DKey(
82104
[]byte(password), salt,
83105
argon2Time, argon2Memory,
@@ -100,7 +122,7 @@ func GenerateSaltedHashWithTypeAndOpt(random io.Reader, password string, typ str
100122
return hash, nil
101123
}
102124

103-
// 验证密钥
125+
// Compare Hash With Password
104126
func CompareHashWithPassword(hash, password string) (bool, error) {
105127
if len(hash) == 0 || len(password) == 0 {
106128
return false, errors.New("go-cryptobin/argon2fmt: Arguments cannot be zero length")
@@ -179,6 +201,7 @@ func CompareHashWithPassword(hash, password string) (bool, error) {
179201
return true, nil
180202
}
181203

204+
// generate salt with length
182205
func generateSalt(random io.Reader, length int) ([]byte, error) {
183206
salt := make([]byte, length)
184207
_, err := io.ReadFull(random, salt)

0 commit comments

Comments
 (0)