Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

try: general sha1 implementation #1

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ require (
github.com/imdario/mergo v0.3.12
github.com/inhies/go-bytesize v0.0.0-20210819104631-275770b98743
github.com/jarcoal/httpmock v1.0.5
github.com/jsimonetti/pwscheme v0.0.0-20220922140336-67a4d090f150
github.com/jteeuwen/go-bindata v3.0.7+incompatible
github.com/julienschmidt/httprouter v1.3.0
github.com/knadh/koanf v1.4.0
Expand Down Expand Up @@ -216,7 +217,6 @@ require (
github.com/joho/godotenv v1.4.0 // indirect
github.com/jonboulle/clockwork v0.2.2 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/jsimonetti/pwscheme v0.0.0-20220922140336-67a4d090f150 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/kr/pretty v0.3.0 // indirect
Expand Down
10 changes: 3 additions & 7 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1084,8 +1084,6 @@ github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8Hm
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/jsimonetti/pwscheme v0.0.0-20220125093853-4d9895f5db73 h1:ZhC4QngptYaGx53+ph1RjxcH8fkCozBaY+935TNX4i8=
github.com/jsimonetti/pwscheme v0.0.0-20220125093853-4d9895f5db73/go.mod h1:t0Q9JvoMTfTYdAWIk2MF69iz+Qpdk9D+PgVu6fVmaDI=
github.com/jsimonetti/pwscheme v0.0.0-20220922140336-67a4d090f150 h1:ta6N7DaOQEACq28cLa0iRqXIbchByN9Lfll08CT2GBc=
github.com/jsimonetti/pwscheme v0.0.0-20220922140336-67a4d090f150/go.mod h1:SiNTKDgjKQORnazFVHXhpny7UtU0iJOqtxd7R7sCfDI=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
Expand Down Expand Up @@ -1882,8 +1880,7 @@ golang.org/x/crypto v0.0.0-20210920023735-84f357641f63/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220517005047-85d78b3ac167/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8 h1:GIAS/yBem/gq2MUqgNIzUHW7cJMmx3TGZOrnyYaNQ6c=
golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0 h1:a5Yg6ylndHHYJqIPrdq0AhvR6KTvDTAvgBtaidhEevY=
golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
Expand Down Expand Up @@ -2000,8 +1997,7 @@ golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su
golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b h1:ZmngSVLe/wycRns9MKikG9OWIEjGcGAkacif7oYQaUY=
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.0.0-20220921155015-db77216a4ee9 h1:SdDGdqRuKrF2R4XGcnPzcvZ63c/55GvhoHUus0o+BNI=
golang.org/x/net v0.0.0-20220921155015-db77216a4ee9/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
Expand Down Expand Up @@ -2052,8 +2048,8 @@ golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXR
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210317153231-de623e64d2a6/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20220919170432-7a66f970e087 h1:tPwmk4vmvVCMdr98VgL4JH+qZxPL8fqlUOHnyOM8N3w=
golang.org/x/term v0.0.0-20220919170432-7a66f970e087/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
Expand Down
69 changes: 68 additions & 1 deletion hash/hash_comparator.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package hash

import (
"context"
"crypto/sha1"
"crypto/subtle"
"encoding/base64"
"fmt"
Expand Down Expand Up @@ -40,6 +41,8 @@ func Compare(ctx context.Context, password []byte, hash []byte) error {
return CompareSSHA256(ctx, password, hash)
case IsSSHA512Hash(hash):
return CompareSSHA512(ctx, password, hash)
case IsSHA1Hash(hash):
return CompareSHA1(ctx, password, hash)
default:
return errors.WithStack(ErrUnknownHashAlgorithm)
}
Expand Down Expand Up @@ -168,6 +171,33 @@ func CompareSSHA512(_ context.Context, password []byte, hash []byte) error {
return nil
}

func CompareSHA1(_ context.Context, password []byte, hash []byte) error {

// "$md5$pf=e1NBTFR9e1BBU1NXT1JEfQ==$MTIz$q+RdKCgc+ipCAcm5ChQwlQ=="
// pf={SALT}{PASSWORD} salt=123

// Extract the parameters, salt and derived key from the encoded password
pf, salt, hash, err := decodeSHA1Hash(string(hash))
if err != nil {
return err
}

r := strings.NewReplacer("{SALT}", string(salt), "{PASSWORD}", string(password))
arg := []byte(r.Replace(string(pf)))

// @hugo: why did you use hex.EncodeToString here before?
// otherHash := hex.EncodeToString(sha.Sum(nil))
otherHash := sha1.Sum(arg)

// Check that the contents of the hashed passwords are identical. Note
// that we are using the subtle.ConstantTimeCompare() function for this
// to help prevent timing attacks.
if subtle.ConstantTimeCompare(hash, otherHash[:]) == 1 {
return nil
}
return errors.WithStack(ErrMismatchedHashAndPassword)
}

var (
isBcryptHash = regexp.MustCompile(`^\$2[abzy]?\$`)
isArgon2idHash = regexp.MustCompile(`^\$argon2id\$`)
Expand All @@ -177,6 +207,7 @@ var (
isSSHAHash = regexp.MustCompile(`^{SSHA}.*`)
isSSHA256Hash = regexp.MustCompile(`^{SSHA256}.*`)
isSSHA512Hash = regexp.MustCompile(`^{SSHA512}.*`)
isSHA1Hash = regexp.MustCompile(`^\$sha1\$`)
)

func IsBcryptHash(hash []byte) bool {
Expand Down Expand Up @@ -211,9 +242,13 @@ func IsSSHA512Hash(hash []byte) bool {
return isSSHA512Hash.Match(hash)
}

func IsSHA1Hash(hash []byte) bool {
return isSHA1Hash.Match(hash)
}

func IsValidHashFormat(hash []byte) bool {
if IsArgon2iHash(hash) || IsArgon2idHash(hash) || IsBcryptHash(hash) || IsPbkdf2Hash(hash) ||
IsScryptHash(hash) || IsSSHAHash(hash) || IsSSHA256Hash(hash) || IsSSHA512Hash(hash) {
IsScryptHash(hash) || IsSSHAHash(hash) || IsSSHA256Hash(hash) || IsSSHA512Hash(hash) || IsSHA1Hash(hash) {
return true
} else {
return false
Expand Down Expand Up @@ -320,3 +355,35 @@ func decodeScryptHash(encodedHash string) (p *Scrypt, salt, hash []byte, err err

return p, salt, hash, nil
}

// decodeSHA1Hash decodes SHA1 encoded password hash in custom PHC format
// $sha1$pf=<salting-format>$<salt>$<hash>
func decodeSHA1Hash(encodedHash string) (pf, salt, hash []byte, err error) {
parts := strings.Split(encodedHash, "$")

if len(parts) != 5 {
return nil, nil, nil, ErrInvalidHash
}

_, err = fmt.Sscanf(parts[2], "pf=%s", &pf)
if err != nil {
return nil, nil, nil, err
}

pf, err := base64.StdEncoding.Strict().DecodeString(string(pf))
if err != nil {
return nil, nil, nil, err
}

salt, err = base64.StdEncoding.Strict().DecodeString(parts[3])
if err != nil {
return nil, nil, nil, err
}

hash, err = base64.StdEncoding.Strict().DecodeString(parts[4])
if err != nil {
return nil, nil, nil, err
}

return pf, salt, hash, nil
}
3 changes: 3 additions & 0 deletions hash/hasher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,9 @@ func TestPbkdf2Hasher(t *testing.T) {
func TestCompare(t *testing.T) {
assert.Error(t, hash.Compare(context.Background(), []byte("test"), []byte("$unknown$12$o6hx.Wog/wvFSkT/Bp/6DOxCtLRTDj7lm9on9suF/WaCGNVHbkfL6")))

// assert.Nil(t, hash.Compare(context.Background(), []byte("123456"), []byte("$sha1$a40c10cfe4$85396a8a48e3485a0ae374b857bfadf02c8cbf0d"))) // TODO: split hash from our string, add pf format string (b64 encoded)
// assert.Nil(t, hash.CompareSHA1(context.Background(), []byte("123456"), []byte("$sha1$a40c10cfe4$85396a8a48e3485a0ae374b857bfadf02c8cbf0d")))

assert.Nil(t, hash.Compare(context.Background(), []byte("test"), []byte("$2a$12$o6hx.Wog/wvFSkT/Bp/6DOxCtLRTDj7lm9on9suF/WaCGNVHbkfL6")))
assert.Nil(t, hash.CompareBcrypt(context.Background(), []byte("test"), []byte("$2a$12$o6hx.Wog/wvFSkT/Bp/6DOxCtLRTDj7lm9on9suF/WaCGNVHbkfL6")))
assert.Error(t, hash.Compare(context.Background(), []byte("test"), []byte("$2a$12$o6hx.Wog/wvFSkT/Bp/6DOxCtLRTDj7lm9on9suF/WaCGNVHbkfL7")))
Expand Down