pax_global_header00006660000000000000000000000064151267366250014527gustar00rootroot0000000000000052 comment=520b8c6c36f278c518deec203c009eca5cd4219a golang-github-jsimonetti-pwscheme-0.0~git20220922.67a4d09/000077500000000000000000000000001512673662500226335ustar00rootroot00000000000000golang-github-jsimonetti-pwscheme-0.0~git20220922.67a4d09/.github/000077500000000000000000000000001512673662500241735ustar00rootroot00000000000000golang-github-jsimonetti-pwscheme-0.0~git20220922.67a4d09/.github/workflows/000077500000000000000000000000001512673662500262305ustar00rootroot00000000000000golang-github-jsimonetti-pwscheme-0.0~git20220922.67a4d09/.github/workflows/go.yml000066400000000000000000000004701512673662500273610ustar00rootroot00000000000000name: Go on: push: branches: [ master ] pull_request: branches: [ master ] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Set up Go uses: actions/setup-go@v2 with: go-version: 1.17 - name: Test run: go test -v ./... golang-github-jsimonetti-pwscheme-0.0~git20220922.67a4d09/LICENSE000066400000000000000000000020731512673662500236420ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2016 Jeroen Simonetti Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. golang-github-jsimonetti-pwscheme-0.0~git20220922.67a4d09/README.md000066400000000000000000000007521512673662500241160ustar00rootroot00000000000000[![GoDoc](https://godoc.org/github.com/jsimonetti/pwscheme?status.svg)](https://godoc.org/github.com/jsimonetti/pwscheme) [![Travis](https://api.travis-ci.org/jsimonetti/pwscheme.svg?branch=master)](https://travis-ci.org/jsimonetti/pwscheme) # pwscheme Golang package defining password schemes Supported schemes - {SSHA} Salted SHA1 - {SSHA256} Salted SHA256 - {SSHA512} Salted SHA512 - {MD5-CRYPT} Crypt with MD5 Docs: https://godoc.org/github.com/jsimonetti/pwscheme golang-github-jsimonetti-pwscheme-0.0~git20220922.67a4d09/go.mod000066400000000000000000000005041512673662500237400ustar00rootroot00000000000000module github.com/jsimonetti/pwscheme go 1.13 require ( golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0 // indirect golang.org/x/net v0.0.0-20220921155015-db77216a4ee9 // indirect golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 // indirect golang.org/x/term v0.0.0-20220919170432-7a66f970e087 // indirect ) golang-github-jsimonetti-pwscheme-0.0~git20220922.67a4d09/go.sum000066400000000000000000000036111512673662500237670ustar00rootroot00000000000000golang.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/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 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/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 h1:h+EGohizhe9XlX18rfpa8k8RAc5XyaeamM+0VHRd4lc= golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 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.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang-github-jsimonetti-pwscheme-0.0~git20220922.67a4d09/md5crypt/000077500000000000000000000000001512673662500244025ustar00rootroot00000000000000golang-github-jsimonetti-pwscheme-0.0~git20220922.67a4d09/md5crypt/md5crypt.go000066400000000000000000000060351512673662500265040ustar00rootroot00000000000000// Package md5crypt provides functions to generate and validate {MD5-CRYPT} styled // password schemes. // The method used is compatible with libc crypt used in /etc/shadow package md5crypt import ( "crypto/md5" "crypto/rand" "crypto/subtle" "errors" "fmt" "strings" ) const itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" var md5CryptSwaps = [16]int{12, 6, 0, 13, 7, 1, 14, 8, 2, 15, 9, 3, 5, 10, 4, 11} var magic = []byte("$1$") // ErrNotMd5cryptPassword occurs when Validate receives a non-SSHA hash var ErrNotMd5cryptPassword = errors.New("string is not a MD5-CRYPT password") // ErrNotMatching occurs when the given password and hash do not match var ErrNotMatching = errors.New("hash does not match password") // ErrSaltLengthInCorrect occurs when the given salt is not of the correct // length var ErrSaltLengthInCorrect = errors.New("salt length incorrect") // Generate encrypts a password with a random salt of definable length and // returns the {MD5-CRYPT} encoding of the password func Generate(password string, length uint8) (string, error) { if length > 8 || length < 1 { return "", ErrSaltLengthInCorrect } salt := make([]byte, length) _, err := rand.Read(salt) if err != nil { return "", err } // we need to reject salts that contain the char $ for strings.Count(string(salt), "$") != 0 { _, err := rand.Read(salt) if err != nil { return "", err } } hash := fmt.Sprintf("{MD5-CRYPT}%s", crypt([]byte(password), salt)) return hash, nil } // Validate compares a given password with a {SSHA} encoded password // Returns true is they match or an error otherwise func Validate(password string, hash string) (bool, error) { if len(hash) < 15 || string(hash[0:14]) != "{MD5-CRYPT}$1$" { return false, ErrNotMd5cryptPassword } data := strings.Split(hash[14:], "$") newhash := crypt([]byte(password), []byte(data[0])) if subtle.ConstantTimeCompare(newhash, []byte(hash[11:])) == 1 { return true, nil } return false, ErrNotMatching } func crypt(password, salt []byte) []byte { d := md5.New() d.Write(password) d.Write(magic) d.Write(salt) d2 := md5.New() d2.Write(password) d2.Write(salt) d2.Write(password) for i, mixin := 0, d2.Sum(nil); i < len(password); i++ { d.Write([]byte{mixin[i%16]}) } for i := len(password); i != 0; i >>= 1 { if i&1 == 0 { d.Write([]byte{password[0]}) } else { d.Write([]byte{0}) } } final := d.Sum(nil) for i := 0; i < 1000; i++ { d2 := md5.New() if i&1 == 0 { d2.Write(final) } else { d2.Write(password) } if i%3 != 0 { d2.Write(salt) } if i%7 != 0 { d2.Write(password) } if i&1 == 0 { d2.Write(password) } else { d2.Write(final) } final = d2.Sum(nil) } result := make([]byte, 0, 22) v := uint(0) bits := uint(0) for _, i := range md5CryptSwaps { v |= (uint(final[i]) << bits) for bits = bits + 8; bits > 6; bits -= 6 { result = append(result, itoa64[v&0x3f]) v >>= 6 } } result = append(result, itoa64[v&0x3f]) return append(append(append(magic, salt...), '$'), result...) } golang-github-jsimonetti-pwscheme-0.0~git20220922.67a4d09/md5crypt/md5crypt_test.go000066400000000000000000000042151512673662500275410ustar00rootroot00000000000000package md5crypt_test import ( "testing" "github.com/jsimonetti/pwscheme/md5crypt" ) func TestValidPassword(t *testing.T) { pass := "test123" hash := "{MD5-CRYPT}$1$UNq3KKXM$hsrKHTk9BaYGZwafpr4K80" if res, err := md5crypt.Validate(pass, hash); err != nil || res != true { t.Errorf("Valid password fails validation: %s", err) } } func TestInValidPassword(t *testing.T) { pass := "test12" hash := "{MD5-CRYPT}$1$UNq3KKXM$hsrKHTk9BaYGZwafpr4K80" if res, err := md5crypt.Validate(pass, hash); res != false { t.Errorf("Invalid password passes validation: %s", err) } } func TestGenerate4(t *testing.T) { pass := "test123" var hash string var err error var res bool if hash, err = md5crypt.Generate(pass, 4); err != nil { t.Errorf("Generate password fails: %s", err) return } if res, err = md5crypt.Validate(pass, hash); err != nil || res != true { t.Errorf("Generated hash can not be validated: %s", err) } } func TestGenerate8(t *testing.T) { pass := "test123" var hash string var err error var res bool if hash, err = md5crypt.Generate(pass, 8); err != nil { t.Errorf("Generate password fails: %s", err) return } if res, err = md5crypt.Validate(pass, hash); err != nil || res != true { t.Errorf("Generated hash can not be validated: %s", err) } } func TestGenerate0(t *testing.T) { if _, err := md5crypt.Generate("", 0); err != md5crypt.ErrSaltLengthInCorrect { t.Errorf("Generated hash with too short salt did not fail") } } func TestGenerate9(t *testing.T) { if _, err := md5crypt.Generate("", 9); err != md5crypt.ErrSaltLengthInCorrect { t.Errorf("Generated hash with too long salt did not fail") } } func TestGenerateManyPasses(t *testing.T) { pass := "foobar" var hash string var err error var res bool errors := 0 for i := 0; i < 1000; i++ { if hash, err = md5crypt.Generate(pass, 8); err != nil { t.Errorf("Generate password fails: %s", err) return } if res, err = md5crypt.Validate(pass, hash); err != nil || res != true { t.Errorf("Generated hash can not be validated: %s", err) errors += 1 } } if errors != 0 { t.Errorf("%d error(s) occurred when running 1000 passes", errors) } } golang-github-jsimonetti-pwscheme-0.0~git20220922.67a4d09/ssha/000077500000000000000000000000001512673662500235715ustar00rootroot00000000000000golang-github-jsimonetti-pwscheme-0.0~git20220922.67a4d09/ssha/ssha.go000066400000000000000000000037461512673662500250700ustar00rootroot00000000000000// Package ssha provides functions to generate and validate {SSHA} styled // password schemes. // The method used is defined in RFC 2307 and uses a salted SHA1 secure hashing // algorithm package ssha import ( "crypto/rand" "crypto/sha1" "crypto/subtle" "encoding/base64" "errors" "fmt" ) // ErrNotSshaPassword occurs when Validate receives a non-SSHA hash var ErrNotSshaPassword = errors.New("string is not a SSHA hashed password") // ErrBase64DecodeFailed occurs when the given hash cannot be decode var ErrBase64DecodeFailed = errors.New("base64 decode of hash failed") // ErrNotMatching occurs when the given password and hash do not match var ErrNotMatching = errors.New("hash does not match password") // Generate encrypts a password with a random salt of definable length and // returns the {SSHA} encoding of the password func Generate(password string, length uint8) (string, error) { salt := make([]byte, length) _, err := rand.Read(salt) if err != nil { return "", err } hash := createHash(password, salt) ret := fmt.Sprintf("{SSHA}%s", base64.StdEncoding.EncodeToString(hash)) return ret, nil } // Validate compares a given password with a {SSHA} encoded password // Returns true is they match or an error otherwise func Validate(password string, hash string) (bool, error) { if len(hash) < 7 || string(hash[0:6]) != "{SSHA}" { return false, ErrNotSshaPassword } data, err := base64.StdEncoding.DecodeString(hash[6:]) if len(data) < 21 || err != nil { return false, ErrBase64DecodeFailed } newhash := createHash(password, data[20:]) hashedpw := base64.StdEncoding.EncodeToString(newhash) if subtle.ConstantTimeCompare([]byte(hashedpw), []byte(hash[6:])) == 1 { return true, nil } return false, ErrNotMatching } // createHash appends password and salt together to a byte array func createHash(password string, salt []byte) []byte { pass := []byte(password) str := append(pass[:], salt[:]...) sum := sha1.Sum(str) result := append(sum[:], salt[:]...) return result } golang-github-jsimonetti-pwscheme-0.0~git20220922.67a4d09/ssha/ssha_test.go000066400000000000000000000033501512673662500261160ustar00rootroot00000000000000package ssha_test import ( "testing" "github.com/jsimonetti/pwscheme/ssha" ) func TestValidPassword(t *testing.T) { pass := "test123" hash := "{SSHA}JFZFs0oHzxbMwkSJmYVeI8MnTDy/276a" if res, err := ssha.Validate(pass, hash); err != nil || res != true { t.Errorf("Valid password fails validation: %s", err) } } func TestInValidPassword(t *testing.T) { pass := "test12" hash := "{SSHA}JFZFs0oHzxbMwkSJmYVeI8MnTDy/276a" if res, err := ssha.Validate(pass, hash); res != false { t.Errorf("Invalid password passes validation: %s", err) } } func TestGenerate4(t *testing.T) { pass := "test123" var hash string var err error var res bool if hash, err = ssha.Generate(pass, 4); err != nil { t.Errorf("Generate password fails: %s", err) return } if res, err = ssha.Validate(pass, hash); err != nil || res != true { t.Errorf("Generated hash can not be validated: %s", err) } } func TestGenerate8(t *testing.T) { pass := "test123" var hash string var err error var res bool if hash, err = ssha.Generate(pass, 8); err != nil { t.Errorf("Generate password fails: %s", err) return } if res, err = ssha.Validate(pass, hash); err != nil || res != true { t.Errorf("Generated hash can not be validated: %s", err) } } func TestGenerateManyPasses(t *testing.T) { pass := "foobar" var hash string var err error var res bool errors := 0 for i := 0; i < 1000; i++ { if hash, err = ssha.Generate(pass, 8); err != nil { t.Errorf("Generate password fails: %s", err) return } if res, err = ssha.Validate(pass, hash); err != nil || res != true { t.Errorf("Generated hash can not be validated: %s", err) errors += 1 } } if errors != 0 { t.Errorf("%d error(s) occurred when running 1000 passes", errors) } } golang-github-jsimonetti-pwscheme-0.0~git20220922.67a4d09/ssha256/000077500000000000000000000000001512673662500240265ustar00rootroot00000000000000golang-github-jsimonetti-pwscheme-0.0~git20220922.67a4d09/ssha256/ssha256.go000066400000000000000000000040131512673662500255460ustar00rootroot00000000000000// Package ssha256 provides functions to generate and validate {SSHA256} styled // password schemes. // The method used is defined in RFC 2307 and uses a salted SHA256 secure hashing // algorithm package ssha256 import ( "crypto/rand" "crypto/sha256" "crypto/subtle" "encoding/base64" "errors" "fmt" ) // ErrNotSshaPassword occurs when Validate receives a non-SSHA256 hash var ErrNotSshaPassword = errors.New("string is not a SSHA256 hashed password") // ErrBase64DecodeFailed occurs when the given hash cannot be decode var ErrBase64DecodeFailed = errors.New("base64 decode of hash failed") // ErrNotMatching occurs when the given password and hash do not match var ErrNotMatching = errors.New("hash does not match password") // Generate encrypts a password with a random salt of definable length and // returns the {SSHA256} encoding of the password func Generate(password string, length uint8) (string, error) { salt := make([]byte, length) _, err := rand.Read(salt) if err != nil { return "", err } hash := createHash(password, salt) ret := fmt.Sprintf("{SSHA256}%s", base64.StdEncoding.EncodeToString(hash)) return ret, nil } // Validate compares a given password with a {SSHA256} encoded password // Returns true is they match or an error otherwise func Validate(password string, hash string) (bool, error) { if len(hash) < 10 || string(hash[0:9]) != "{SSHA256}" { return false, ErrNotSshaPassword } data, err := base64.StdEncoding.DecodeString(hash[9:]) if len(data) < 33 || err != nil { return false, ErrBase64DecodeFailed } newhash := createHash(password, data[32:]) hashedpw := base64.StdEncoding.EncodeToString(newhash) if subtle.ConstantTimeCompare([]byte(hashedpw), []byte(hash[9:])) == 1 { return true, nil } return false, ErrNotMatching } // createHash appends password and salt together to a byte array func createHash(password string, salt []byte) []byte { pass := []byte(password) str := append(pass[:], salt[:]...) sum := sha256.Sum256(str) result := append(sum[:], salt[:]...) return result } golang-github-jsimonetti-pwscheme-0.0~git20220922.67a4d09/ssha256/ssha256_test.go000066400000000000000000000034541512673662500266150ustar00rootroot00000000000000package ssha256_test import ( "testing" "github.com/jsimonetti/pwscheme/ssha256" ) func TestValidPassword(t *testing.T) { pass := "test123" hash := "{SSHA256}czO44OTV17PcF1cRxWrLZLy9xHd7CWyVYplr1rOhuMlx/7IK" if res, err := ssha256.Validate(pass, hash); err != nil || res != true { t.Errorf("Valid password fails validation: %s", err) } } func TestInValidPassword(t *testing.T) { pass := "test12" hash := "{SSHA256}czO44OTV17PcF1cRxWrLZLy9xHd7CWyVYplr1rOhuMlx/7IK" if res, err := ssha256.Validate(pass, hash); res != false { t.Errorf("Invalid password passes validation: %s", err) } } func TestGenerate4(t *testing.T) { pass := "test123" var hash string var err error var res bool if hash, err = ssha256.Generate(pass, 4); err != nil { t.Errorf("Generate password fails: %s", err) return } if res, err = ssha256.Validate(pass, hash); err != nil || res != true { t.Errorf("Generated hash can not be validated: %s", err) } } func TestGenerate8(t *testing.T) { pass := "test123" var hash string var err error var res bool if hash, err = ssha256.Generate(pass, 8); err != nil { t.Errorf("Generate password fails: %s", err) return } if res, err = ssha256.Validate(pass, hash); err != nil || res != true { t.Errorf("Generated hash can not be validated: %s", err) } } func TestGenerateManyPasses(t *testing.T) { pass := "foobar" var hash string var err error var res bool errors := 0 for i := 0; i < 1000; i++ { if hash, err = ssha256.Generate(pass, 8); err != nil { t.Errorf("Generate password fails: %s", err) return } if res, err = ssha256.Validate(pass, hash); err != nil || res != true { t.Errorf("Generated hash can not be validated: %s", err) errors += 1 } } if errors != 0 { t.Errorf("%d error(s) occurred when running 1000 passes", errors) } } golang-github-jsimonetti-pwscheme-0.0~git20220922.67a4d09/ssha512/000077500000000000000000000000001512673662500240215ustar00rootroot00000000000000golang-github-jsimonetti-pwscheme-0.0~git20220922.67a4d09/ssha512/ssha512.go000066400000000000000000000040161512673662500255370ustar00rootroot00000000000000// Package ssha512 provides functions to generate and validate {SSHA512} styled // password schemes. // The method used is defined in RFC 2307 and uses a salted SHA512 secure hashing // algorithm package ssha512 import ( "crypto/rand" "crypto/sha512" "crypto/subtle" "encoding/base64" "errors" "fmt" ) // ErrNotSshaPassword occurs when Validate receives a non-SSHA512 hash var ErrNotSshaPassword = errors.New("string is not a SSHA512 hashed password") // ErrBase64DecodeFailed occurs when the given hash cannot be decode var ErrBase64DecodeFailed = errors.New("base64 decode of hash failed") // ErrNotMatching occurs when the given password and hash do not match var ErrNotMatching = errors.New("hash does not match password") // Generate encrypts a password with a random salt of definable length and // returns the {SSHA512} encoding of the password func Generate(password string, length uint8) (string, error) { salt := make([]byte, length) _, err := rand.Read(salt) if err != nil { return "", err } hash := createHash(password, salt) ret := fmt.Sprintf("{SSHA512}%s", base64.StdEncoding.EncodeToString(hash)) return ret, nil } // Validate compares a given password with a {SSHA512} encoded password // Returns true is they match or an error otherwise func Validate(password string, hash string) (bool, error) { if len(hash) < 10 || string(hash[0:9]) != "{SSHA512}" { return false, ErrNotSshaPassword } data, err := base64.StdEncoding.DecodeString(hash[9:]) if len(data) < 65 || err != nil { return false, ErrBase64DecodeFailed } newhash := createHash(password, data[64:]) hashedpw := base64.StdEncoding.EncodeToString(newhash) if subtle.ConstantTimeCompare([]byte(hashedpw), []byte(hash[9:])) == 1 { return true, nil } return false, ErrNotMatching } // This function appends password and salt together to a byte array func createHash(password string, salt []byte) []byte { pass := []byte(password) str := append(pass[:], salt[:]...) sum := sha512.Sum512(str) result := append(sum[:], salt[:]...) return result } golang-github-jsimonetti-pwscheme-0.0~git20220922.67a4d09/ssha512/ssha512_test.go000066400000000000000000000036041512673662500266000ustar00rootroot00000000000000package ssha512_test import ( "testing" "github.com/jsimonetti/pwscheme/ssha512" ) func TestValidPassword(t *testing.T) { pass := "test123" hash := "{SSHA512}xPUl/px+1cG55rUH4rzcwxdOIPSB2TingLpiJJumN2xyDWN4Ix1WQG3ihnvHaWUE8MYNkvMi5rf0C9NYixHsE6Yh59M=" if res, err := ssha512.Validate(pass, hash); err != nil || res != true { t.Errorf("Valid password fails validation: %s", err) } } func TestInValidPassword(t *testing.T) { pass := "test12" hash := "{SSHA512}xPUl/px+1cG55rUH4rzcwxdOIPSB2TingLpiJJumN2xyDWN4Ix1WQG3ihnvHaWUE8MYNkvMi5rf0C9NYixHsE6Yh59M=" if res, err := ssha512.Validate(pass, hash); res != false { t.Errorf("Invalid password passes validation: %s", err) } } func TestGenerate4(t *testing.T) { pass := "test123" var hash string var err error var res bool if hash, err = ssha512.Generate(pass, 4); err != nil { t.Errorf("Generate password fails: %s", err) return } if res, err = ssha512.Validate(pass, hash); err != nil || res != true { t.Errorf("Generated hash can not be validated: %s", err) } } func TestGenerate8(t *testing.T) { pass := "test123" var hash string var err error var res bool if hash, err = ssha512.Generate(pass, 8); err != nil { t.Errorf("Generate password fails: %s", err) return } if res, err = ssha512.Validate(pass, hash); err != nil || res != true { t.Errorf("Generated hash can not be validated: %s", err) } } func TestGenerateManyPasses(t *testing.T) { pass := "foobar" var hash string var err error var res bool errors := 0 for i := 0; i < 1000; i++ { if hash, err = ssha512.Generate(pass, 8); err != nil { t.Errorf("Generate password fails: %s", err) return } if res, err = ssha512.Validate(pass, hash); err != nil || res != true { t.Errorf("Generated hash can not be validated: %s", err) errors += 1 } } if errors != 0 { t.Errorf("%d error(s) occurred when running 1000 passes", errors) } }