Skip to content

Commit

Permalink
iplement hash pasword tests
Browse files Browse the repository at this point in the history
  • Loading branch information
erudenko committed Jun 30, 2023
1 parent ee96982 commit 244f553
Show file tree
Hide file tree
Showing 7 changed files with 356 additions and 154 deletions.
52 changes: 52 additions & 0 deletions jwt/argon_hash_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package jwt_test

import (
"encoding/base64"
"testing"

"github.com/madappgang/identifo/v2/jwt"
"github.com/madappgang/identifo/v2/model"
"github.com/stretchr/testify/assert"
)

func TestArgonHash(t *testing.T) {
p := "password111213"
params := model.DefaultPasswordHashArgonParams
salt := []byte("I am a salt!!!")
pepper := []byte("I am a pepper!!!")

hash := jwt.PasswordHashArgon2i(p, params, salt, pepper)

assert.NotEmpty(t, hash)
assert.Contains(t, hash, "$argon2i$")
assert.Contains(t, hash, "$v=")
assert.Contains(t, hash, "$m=")
assert.Contains(t, hash, ",t=")
assert.Contains(t, hash, ",p=")
assert.Contains(t, hash, base64.RawStdEncoding.EncodeToString(salt))
}

func TestArgonValidatePassword(t *testing.T) {
p := "password111213"
params := model.DefaultPasswordHashArgonParams
salt := []byte("I am a salt!!!")
pepper := []byte("I am a pepper!!!")

hash := jwt.PasswordHashArgon2i(p, params, salt, pepper)

assert.NotEmpty(t, hash)
assert.Contains(t, hash, "$argon2i$")
assert.Contains(t, hash, "$v=")

match, err := jwt.PasswordMatchArgon2i("password111213", hash, pepper)
assert.NoError(t, err)
assert.True(t, match)

match, err = jwt.PasswordMatchArgon2i("!password111213", hash, pepper)
assert.NoError(t, err)
assert.False(t, match)

match, err = jwt.PasswordMatchArgon2i("", hash, pepper)
assert.NoError(t, err)
assert.False(t, match)
}
8 changes: 5 additions & 3 deletions jwt/bcrypt_hash.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package jwt
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"

"github.com/madappgang/identifo/v2/model"
"golang.org/x/crypto/bcrypt"
Expand All @@ -14,20 +13,23 @@ import (
// we do:
// hashedPassword = hmac(sha256(password), pepper)
// bcrypt(hashedPassword, cost)
func PasswordHashBcrypt(password string, params model.PasswordHashBcryptParams, salt, pepper []byte) (string, error) {
func PasswordHashBcrypt(password string, params model.PasswordHashBcryptParams, pepper []byte) (string, error) {
passwordHmac := hmac.New(sha256.New, pepper) // we use sha256 to pepper the password
passwordHmac.Write([]byte(password))
bs, err := bcrypt.GenerateFromPassword(passwordHmac.Sum(nil), bcrypt.DefaultCost)
if err != nil {
return "", err
}
return base64.RawStdEncoding.EncodeToString(bs), nil
return string(bs), nil
}

// PasswordMatchBcrypt check if password and hash matches
func PasswordMatchBcrypt(password, hash string, pepper []byte) (bool, error) {
passwordHmac := hmac.New(sha256.New, pepper) // we use sha256 to pepper the password
passwordHmac.Write([]byte(password))
err := bcrypt.CompareHashAndPassword([]byte(hash), passwordHmac.Sum(nil))
if err == bcrypt.ErrMismatchedHashAndPassword {
return false, nil
}
return err == nil, err
}
46 changes: 46 additions & 0 deletions jwt/bcrypt_hash_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package jwt_test

import (
"encoding/base64"
"testing"

"github.com/madappgang/identifo/v2/jwt"
"github.com/madappgang/identifo/v2/model"
"github.com/stretchr/testify/assert"
)

func TestBcryptHash(t *testing.T) {
p := "password111213"
params := model.DefaultPasswordHashBcryptParams
pepper := []byte("I am a pepper!!!")

hash, err := jwt.PasswordHashBcrypt(p, params, pepper)

assert.NoError(t, err)
assert.NotEmpty(t, hash)
assert.Contains(t, hash, "$2a$")
assert.NotContains(t, hash, base64.RawStdEncoding.EncodeToString(pepper))
}

func TestBCryptValidatePassword(t *testing.T) {
p := "password111213"
params := model.DefaultPasswordHashBcryptParams
pepper := []byte("I am a pepper!!!")

hash, err := jwt.PasswordHashBcrypt(p, params, pepper)

assert.NoError(t, err)
assert.NotEmpty(t, hash)

match, err := jwt.PasswordMatchBcrypt("password111213", hash, pepper)
assert.NoError(t, err)
assert.True(t, match)

match, err = jwt.PasswordMatchBcrypt("password111213", hash, append(pepper, []byte("1")...))
assert.NoError(t, err)
assert.False(t, match)

match, err = jwt.PasswordMatchBcrypt("!password111213", hash, pepper)
assert.NoError(t, err)
assert.False(t, match)
}
2 changes: 1 addition & 1 deletion jwt/hash.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func PasswordHash(password string, params model.PasswordHashParams, pepper []byt
if params.Bcrypt == nil {
err = ErrorHashParamsMissing
} else {
hash, err = PasswordHashBcrypt(password, *params.Bcrypt, salt, pepper)
hash, err = PasswordHashBcrypt(password, *params.Bcrypt, pepper)
}
default:
err = ErrorUnknownPasswordHashType
Expand Down
96 changes: 96 additions & 0 deletions jwt/hash_test.go
Original file line number Diff line number Diff line change
@@ -1 +1,97 @@
package jwt_test

import (
"encoding/base64"
"testing"

"github.com/madappgang/identifo/v2/jwt"
"github.com/madappgang/identifo/v2/model"
"github.com/stretchr/testify/assert"
)

func TestHash(t *testing.T) {
p := "password111213"
params := model.DefaultPasswordHashParams
pepper := []byte("I am a pepper!!!")

hash, err := jwt.PasswordHash(p, params, pepper)

assert.NoError(t, err)
assert.NotEmpty(t, hash)
assert.Contains(t, hash, "$argon2i$")
assert.Contains(t, hash, "$v=")
assert.Contains(t, hash, "$m=")
assert.Contains(t, hash, ",t=")
assert.Contains(t, hash, ",p=")
}

func TestOtherHash(t *testing.T) {
p := "password111213"
params := model.PasswordHashParams{
Type: model.PasswordHashBcrypt,
SaltLength: 16,
Bcrypt: &model.DefaultPasswordHashBcryptParams,
}
pepper := []byte("I am a pepper!!!")

hash, err := jwt.PasswordHash(p, params, pepper)

assert.NoError(t, err)
assert.NotEmpty(t, hash)
assert.Contains(t, hash, "$2a$")
assert.NotContains(t, hash, base64.RawStdEncoding.EncodeToString(pepper))
}

func TestInvalidHashAlg(t *testing.T) {
p := "password111213"
params := model.PasswordHashParams{
Type: "whatever",
SaltLength: 16,
Bcrypt: &model.DefaultPasswordHashBcryptParams,
}
pepper := []byte("I am a pepper!!!")

hash, err := jwt.PasswordHash(p, params, pepper)

assert.Error(t, err)
assert.Equal(t, err, jwt.ErrorUnknownPasswordHashType)
assert.Empty(t, hash)
}

func TestInvalidHashParams(t *testing.T) {
p := "password111213"
params := model.PasswordHashParams{
Type: model.PasswordHashArgon2i,
SaltLength: 16,
}
pepper := []byte("I am a pepper!!!")

hash, err := jwt.PasswordHash(p, params, pepper)

assert.Error(t, err)
assert.Equal(t, err, jwt.ErrorHashParamsMissing)
assert.Empty(t, hash)
}

func TestPasswordMatch(t *testing.T) {
p := "password111213"
params := model.DefaultPasswordHashParams
pepper := []byte("I am a pepper!!!")

hash, err := jwt.PasswordHash(p, params, pepper)

assert.NoError(t, err)
assert.NotEmpty(t, hash)

match, err := jwt.PasswordMatch(p, hash, pepper)
assert.NoError(t, err)
assert.True(t, match)

match, err = jwt.PasswordMatch("!"+p, hash, pepper)
assert.NoError(t, err)
assert.False(t, match)

match, err = jwt.PasswordMatch(p, hash, append(pepper, []byte("!")...))
assert.NoError(t, err)
assert.False(t, match)
}
Loading

0 comments on commit 244f553

Please sign in to comment.