Skip to content

Commit

Permalink
Merge pull request #12 from hunter007/unittest2
Browse files Browse the repository at this point in the history
Add unittest for MustUpdate
  • Loading branch information
hunter007 authored May 26, 2023
2 parents 4a74e1d + 5f50545 commit 1302380
Show file tree
Hide file tree
Showing 16 changed files with 386 additions and 23 deletions.
8 changes: 6 additions & 2 deletions argon2.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,12 @@ func (hasher *argon2Hasher) Verify(password, encoded string) bool {
}

func (hasher *argon2Hasher) MustUpdate(encoded string) bool {
// TODO(zhaowentao): 处理 Verify
return false
pi, err := hasher.Decode(encoded)
if err != nil {
return false
}
p := pi.Others.(*Argon2Params)
return *p != *hasher.params
}

func (hasher *argon2Hasher) Harden(password, encoded string) (string, error) {
Expand Down
36 changes: 36 additions & 0 deletions argon2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,39 @@ func TestArgon2(t *testing.T) {
t.Errorf("Verify() should be false")
}
}

func TestMustUpdateForArgon2(t *testing.T) {
opt := &HasherOption{
Iterations: 1,
Algorithm: argon2Algo,
Params: &Argon2Params{
memory: 32 * 1024,
iterations: 10,
parallelism: 2,
saltLength: 8,
keyLength: 32,
},
}
hasher, _ := NewHasher(opt)
encoded, _ := hasher.Encode(password)

if hasher.MustUpdate(encoded) {
t.Error("should not updated")
}

opt2 := &HasherOption{
Iterations: 1,
Algorithm: argon2Algo,
Params: &Argon2Params{
memory: 32 * 1024,
iterations: 10,
parallelism: 2,
saltLength: 9,
keyLength: 32,
},
}
hasher, _ = NewHasher(opt2)
if !hasher.MustUpdate(encoded) {
t.Error("should updated because of different param")
}
}
20 changes: 16 additions & 4 deletions bcrypt.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ import (

type bcryptHasher struct {
algo string
cost int
}

func (hasher *bcryptHasher) Encode(password string) (string, error) {
return hasher.encode(password, hasher.algo, bcrypt.DefaultCost)
return hasher.encode(password, hasher.algo, hasher.cost)
}

func (hasher *bcryptHasher) encode(password, algo string, cost int) (string, error) {
Expand Down Expand Up @@ -72,8 +73,11 @@ func (hasher *bcryptHasher) Verify(password, encoded string) bool {
}

func (hasher *bcryptHasher) MustUpdate(encoded string) bool {
// TODO(zhaowentao)
return false
pi, err := hasher.Decode(encoded)
if err != nil {
return false
}
return pi.Iterations < hasher.cost
}

func (hasher *bcryptHasher) Harden(password, encoded string) (string, error) {
Expand All @@ -82,5 +86,13 @@ func (hasher *bcryptHasher) Harden(password, encoded string) (string, error) {
}

func newBcryptHasher(opt *HasherOption) (Hasher, error) {
return &bcryptHasher{algo: opt.Algorithm}, nil
cost := bcrypt.DefaultCost
if opt.Iterations > cost {
cost = opt.Iterations
}

return &bcryptHasher{
algo: opt.Algorithm,
cost: cost,
}, nil
}
44 changes: 43 additions & 1 deletion bcrypt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ func TestBcrypt(t *testing.T) {
Salt: "salt",
Iterations: 1,
}
password := "1qasw23"
hasher, err := NewHasher(opt)
if err != nil {
t.Errorf("failed to new %s hasher: %s", opt.Algorithm, err)
Expand Down Expand Up @@ -72,3 +71,46 @@ func TestBcrypt(t *testing.T) {
t.Errorf("wrong algorithm: %s", opt.Algorithm)
}
}

func TestMustUpdateForBcrypt(t *testing.T) {
opt := &HasherOption{
Algorithm: bcryptAlgo,
Salt: "salt",
Iterations: 12,
}
hasher, _ := NewHasher(opt)
encoded, _ := hasher.Encode(password)
if hasher.MustUpdate(encoded) {
t.Error("should not update")
}

opt2 := &HasherOption{
Algorithm: bcryptAlgo,
Salt: "saltsaltsaltsalt",
Iterations: 12,
}
hasher, _ = NewHasher(opt2)
if hasher.MustUpdate(encoded) {
t.Error("should not update because of no use salt")
}

opt3 := &HasherOption{
Algorithm: bcryptAlgo,
Salt: "saltsaltsaltsa",
Iterations: 14,
}
hasher, _ = NewHasher(opt3)
if !hasher.MustUpdate(encoded) {
t.Error("should update because of bigger cost")
}

opt4 := &HasherOption{
Algorithm: bcryptAlgo,
Salt: "saltsaltsaltsa",
Iterations: 11,
}
hasher, _ = NewHasher(opt4)
if hasher.MustUpdate(encoded) {
t.Error("should not update because of smaller cost")
}
}
2 changes: 1 addition & 1 deletion hoption.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"strings"
)

const saltEntropy = 128
const saltEntropy = 64

const (
md5Algo = "md5"
Expand Down
12 changes: 11 additions & 1 deletion md5.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,17 @@ func (hasher *md5Hasher) MustUpdate(encoded string) bool {
if err != nil {
return false
}
return mustUpdateSalt(pi.Salt, saltEntropy)

if pi.Algorithm == unsaltedMd5Algo {
return false
}

ret := mustUpdateSalt(pi.Salt, saltEntropy)
if ret {
return true
}

return len(pi.Salt) < len(hasher.salt)
}

func (hasher *md5Hasher) Harden(password, encoded string) (string, error) {
Expand Down
40 changes: 39 additions & 1 deletion md5_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ func TestUnsaltedMd5(t *testing.T) {
t.Errorf("error should be nil, now %s", err)
}

password := "1qsw23ed"
encoded, err := hasher.Encode(password)
if err != nil {
t.Errorf("failed to Encode(password): %s", err)
Expand All @@ -60,3 +59,42 @@ func TestUnsaltedMd5(t *testing.T) {
t.Errorf("MD5 error")
}
}

func TestMustUpdateForMd5(t *testing.T) {
opt := HasherOption{
Algorithm: unsaltedMd5Algo,
Salt: "",
Iterations: 1,
}
hasher, _ := NewHasher(&opt)
encoded, _ := hasher.Encode(password)

if hasher.MustUpdate(encoded) {
t.Error("should not update")
}

opt1 := HasherOption{
Algorithm: md5Algo,
Salt: "saltsaltsaltsalt",
Iterations: 1,
}
hasher, _ = NewHasher(&opt1)
encoded, _ = hasher.Encode(password)
if hasher.MustUpdate(encoded) {
t.Error("should not update")
}
wrongEncoded := "aa" + encoded
if hasher.MustUpdate(wrongEncoded) {
t.Error("should not update because of wrong encoded")
}

opt2 := HasherOption{
Algorithm: md5Algo,
Salt: "saltsaltsaltsa",
Iterations: 1,
}
hasher, _ = NewHasher(&opt2)
if hasher.MustUpdate(encoded) {
t.Error("should not update because of short salt")
}
}
3 changes: 1 addition & 2 deletions pbkdf2.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,7 @@ func (hasher *pbkdf2Hasher) MustUpdate(encoded string) bool {
}

updateSalt := mustUpdateSalt(pi.Salt, saltEntropy)

return pi.Iterations < hasher.iterCount || updateSalt
return pi.Iterations < hasher.iterCount || updateSalt || len(hasher.salt) > len(pi.Salt)
}

func (hasher *pbkdf2Hasher) Harden(password, encoded string) (string, error) {
Expand Down
93 changes: 90 additions & 3 deletions pbkdf2_test.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,39 @@
package password

import "testing"
import (
"crypto/sha1" // #nosec
"crypto/sha256"
"reflect"
"strings"
"testing"
)

const password = "1qasw23ed"

func TestPbkdf2Sha1Hasher(t *testing.T) {
opt := HasherOption{
Algorithm: pbkdf2Sha1Algo,
Salt: "salt",
Iterations: 10000,
}
password := "1qasw23ed"

hasher, err := NewHasher(&opt)
if err != nil {
t.Errorf("failed to new %s hasher: %s", pbkdf2Sha1Algo, err)
}

pHasher := hasher.(*pbkdf2Hasher)
size, newFunc := pHasher.getSizeAndNew()
if opt.Algorithm == pbkdf2Sha1Algo {
if size != sha1.Size {
t.Error("wrong size")
}

if reflect.ValueOf(newFunc).Pointer() != reflect.ValueOf(sha1.New).Pointer() {
t.Error("wrong newFunc")
}
}

encoded, err := hasher.Encode(password)
if err != nil {
t.Errorf("failed to encode password with %s: %s", pbkdf2Sha1Algo, err)
Expand All @@ -31,12 +51,24 @@ func TestPbkdf2Sha256Hasher(t *testing.T) {
Salt: "salt",
Iterations: 10000,
}
password := "1qasw23ed"

hasher, err := NewHasher(&opt)
if err != nil {
t.Errorf("failed to new %s hasher: %s", pbkdf2Sha256Algo, err)
}

pHasher := hasher.(*pbkdf2Hasher)
size, newFunc := pHasher.getSizeAndNew()
if opt.Algorithm == pbkdf2Sha256Algo {
if size != sha256.Size {
t.Error("wrong size")
}

if reflect.ValueOf(newFunc).Pointer() != reflect.ValueOf(sha256.New).Pointer() {
t.Error("wrong newFunc")
}
}

encoded, err := hasher.Encode(password)
if err != nil {
t.Errorf("failed to encode password with %s: %s", pbkdf2Sha256Algo, err)
Expand All @@ -47,10 +79,65 @@ func TestPbkdf2Sha256Hasher(t *testing.T) {
t.Error("Decode(wrongEncoded) should error")
}

pp := strings.SplitN(encoded, sep, 4)
pp[1] = "aa"
wrongEncoded2 := strings.Join(pp, sep)
if _, err = hasher.Decode(wrongEncoded2); err == nil {
t.Error("Decode(wrongEncoded2) should error")
}

if hasher.Verify(password, wrongEncoded) {
t.Error("Verify(password, wrongEncoded) error")
}
if !hasher.Verify(password, encoded) {
t.Errorf("Algo %s error", pbkdf2Sha256Algo)
}
}

func TestMustUpdateForPbkdf2Sha256(t *testing.T) {
opt := HasherOption{
Algorithm: pbkdf2Sha256Algo,
Salt: "saltsaltsalt",
Iterations: 10000,
}

hasher, _ := NewHasher(&opt)
encoded, err := hasher.Encode(password)
if err != nil {
t.Errorf("failed to encode password with %s: %s", pbkdf2Sha256Algo, err)
}

if hasher.MustUpdate(encoded) {
t.Error("should not update")
}

opt2 := HasherOption{
Algorithm: pbkdf2Sha256Algo,
Salt: "saltsaltsalt",
Iterations: 10001,
}
hasher2, _ := NewHasher(&opt2)
if !hasher2.MustUpdate(encoded) {
t.Error("should update because of Iterations")
}

opt3 := HasherOption{
Algorithm: pbkdf2Sha256Algo,
Salt: "saltsaltsaltsaltsalt11",
Iterations: 10000,
}
hasher3, _ := NewHasher(&opt3)
if !hasher3.MustUpdate(encoded) {
t.Error("should update because of Salt")
}

opt4 := HasherOption{
Algorithm: pbkdf2Sha256Algo,
Salt: "saltsaltsalt",
Iterations: 9000,
}
hasher4, _ := NewHasher(&opt4)
if hasher4.MustUpdate(encoded) {
t.Error("should not update because of less Iterations")
}
}
6 changes: 5 additions & 1 deletion scrypt.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,11 @@ func (hasher *scryptHasher) Verify(password, encoded string) bool {
}

func (hasher *scryptHasher) MustUpdate(encoded string) bool {
return false
pi, err := hasher.Decode(encoded)
if err != nil {
return false
}
return mustUpdateSalt(pi.Salt, saltEntropy) || len(pi.Salt) < len(hasher.salt)
}

func (hasher *scryptHasher) Harden(password, encoded string) (string, error) {
Expand Down
Loading

0 comments on commit 1302380

Please sign in to comment.