diff --git a/LICENSE.txt b/LICENSE.txt index ade9c16..c11d2f8 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2024 Mr. Gecko's Media (James Coleman). http://mrgeckosmedia.com/ +Copyright (c) 2025 Mr. Gecko's Media (James Coleman). http://mrgeckosmedia.com/ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index e5905bf..e304a34 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,10 @@ This is a libxcrypt compatible password hashing library for the Go language. The go get github.com/GRMrGecko/go-passwd ``` +## Docs + +[https://pkg.go.dev/github.com/GRMrGecko/go-passwd](https://pkg.go.dev/github.com/GRMrGecko/go-passwd) + ## Example ```go @@ -19,7 +23,7 @@ import ( ) func main() { - result, err := passwd.CheckPassword([]byte("$y$j9T$Q3N1jZa3Cp.yNINNDt5dDgYkHU7k$9o7WJJB5F.tTEhZdz6T6LMWY/0C3JkhvmcNyUPvUBlC"), []byte("Test")) + result, err := passwd.SCheckPassword("$y$j9T$Q3N1jZa3Cp.yNINNDt5dDgYkHU7k$9o7WJJB5F.tTEhZdz6T6LMWY/0C3JkhvmcNyUPvUBlC", "Test") if err != nil { log.Fatalln(err) } @@ -28,11 +32,11 @@ func main() { log.Println("Password confirmed, saving new password.") pw := passwd.NewSHA512CryptPasswd() - hash, err := pw.HashPassword([]byte("New Password!!!")) + hash, err := pw.SHashPassword("New Password!!!") if err != nil { log.Fatalln(err) } - log.Println("The new password hash to save is:", string(hash)) + log.Println("The new password hash to save is:", hash) } } @@ -45,10 +49,6 @@ $ ./test 2024/09/07 18:42:35 The new password hash to save is: $6$4Eu/l5e.otcRj0rJ$YAlwxJD9pZY9.Z2TjseCbkXiUIrFU2AXh9DPEm5Z1SagxP..xaQCsz7jAgfW4nmUbLh.o23pEZGvvxPCLltf11 ``` -## Docs - -[https://pkg.go.dev/github.com/GRMrGecko/go-passwd](https://pkg.go.dev/github.com/GRMrGecko/go-passwd) - ## Known issues - It is possible to generate password hashes that are incompatible with libxcrypt by setting a large round count. This may be mitigated in the future by adding an option to disable compatibility and otherwise require compatible parameters to be set. diff --git a/go.mod b/go.mod index 88c4280..c185f0c 100644 --- a/go.mod +++ b/go.mod @@ -7,5 +7,5 @@ toolchain go1.23.1 require ( github.com/openwall/yescrypt-go v1.0.0 github.com/pedroalbanese/gogost v0.0.0-20240430171730-f95129c7a5af - golang.org/x/crypto v0.25.0 + golang.org/x/crypto v0.31.0 ) diff --git a/go.sum b/go.sum index 252b9a7..9f13e96 100644 --- a/go.sum +++ b/go.sum @@ -4,3 +4,5 @@ github.com/pedroalbanese/gogost v0.0.0-20240430171730-f95129c7a5af h1:8jbTN9e84F github.com/pedroalbanese/gogost v0.0.0-20240430171730-f95129c7a5af/go.mod h1:A4x4C7B6z2POO1x5CZzKXZVCOFPfjzxxVUbWl2Thhp0= golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= diff --git a/gost_yes_crypt.go b/gost_yes_crypt.go index 723b2bd..28350ff 100644 --- a/gost_yes_crypt.go +++ b/gost_yes_crypt.go @@ -38,7 +38,7 @@ func (a *GostYesCrypt) SetSCryptParams(N, r int) (err error) { } // Decode SCrypt params. -func (a *GostYesCrypt) DecodeSCriptParams() (N, r int) { +func (a *GostYesCrypt) DecodeSCryptParams() (N, r int) { b64 := []byte(a.Params) if len(b64) != 3 { return @@ -79,3 +79,43 @@ func (a *GostYesCrypt) HashPasswordWithSalt(password []byte, salt []byte) (hash hash, err = a.Hash(password, salt) return } + +// Hash an password using default parameters with Gost Yes Crypt. +func HashGostYesCryptPassword(password []byte) (hash []byte, err error) { + passwd := NewGostYesCryptPasswd() + hash, err = passwd.HashPassword(password) + if err != nil { + return + } + return +} + +// Hash an password with salt using default parameters with Gost Yes Crypt. +func HashGostYesCryptPasswordWithSalt(password []byte, salt []byte) (hash []byte, err error) { + passwd := NewGostYesCryptPasswd() + hash, err = passwd.HashPasswordWithSalt(password, salt) + if err != nil { + return + } + return +} + +// Hash an password string using default parameters with Gost Yes Crypt. +func SHashGostYesCryptPassword(password string) (hash string, err error) { + passwd := NewGostYesCryptPasswd() + hash, err = passwd.SHashPassword(password) + if err != nil { + return + } + return +} + +// Hash an password string with salt using default parameters with Gost Yes Crypt. +func SHashGostYesCryptPasswordWithSalt(password string, salt string) (hash string, err error) { + passwd := NewGostYesCryptPasswd() + hash, err = passwd.SHashPasswordWithSalt(salt, salt) + if err != nil { + return + } + return +} diff --git a/md5_crypt.go b/md5_crypt.go index fe61b44..62ce17a 100644 --- a/md5_crypt.go +++ b/md5_crypt.go @@ -108,3 +108,43 @@ func (a *MD5Crypt) HashPasswordWithSalt(password []byte, salt []byte) (hash []by hash = a.Hash(password, salt) return } + +// Hash an password using default parameters with MD5. +func HashMD5Password(password []byte) (hash []byte, err error) { + passwd := NewMD5CryptPasswd() + hash, err = passwd.HashPassword(password) + if err != nil { + return + } + return +} + +// Hash an password with salt using default parameters with MD5. +func HashMD5PasswordWithSalt(password []byte, salt []byte) (hash []byte, err error) { + passwd := NewMD5CryptPasswd() + hash, err = passwd.HashPasswordWithSalt(password, salt) + if err != nil { + return + } + return +} + +// Hash an password string using default parameters with MD5. +func SHashMD5Password(password string) (hash string, err error) { + passwd := NewMD5CryptPasswd() + hash, err = passwd.SHashPassword(password) + if err != nil { + return + } + return +} + +// Hash an password string with salt using default parameters with MD5. +func SHashMD5PasswordWithSalt(password string, salt string) (hash string, err error) { + passwd := NewMD5CryptPasswd() + hash, err = passwd.SHashPasswordWithSalt(salt, salt) + if err != nil { + return + } + return +} diff --git a/nt_hash.go b/nt_hash.go index 7dc68c2..dc0f1ca 100644 --- a/nt_hash.go +++ b/nt_hash.go @@ -82,3 +82,43 @@ func (a *NTHash) HashPasswordWithSalt(password []byte, salt []byte) (hash []byte hash = a.Hash(password) return } + +// Hash an password using default parameters with NT. +func HashNTPassword(password []byte) (hash []byte, err error) { + passwd := NewNTPasswd() + hash, err = passwd.HashPassword(password) + if err != nil { + return + } + return +} + +// Hash an password with salt using default parameters with NT. +func HashNTPasswordWithSalt(password []byte, salt []byte) (hash []byte, err error) { + passwd := NewNTPasswd() + hash, err = passwd.HashPasswordWithSalt(password, salt) + if err != nil { + return + } + return +} + +// Hash an password string using default parameters with NT. +func SHashNTPassword(password string) (hash string, err error) { + passwd := NewNTPasswd() + hash, err = passwd.SHashPassword(password) + if err != nil { + return + } + return +} + +// Hash an password string with salt using default parameters with NT. +func SHashNTPasswordWithSalt(password string, salt string) (hash string, err error) { + passwd := NewNTPasswd() + hash, err = passwd.SHashPasswordWithSalt(salt, salt) + if err != nil { + return + } + return +} diff --git a/passwd.go b/passwd.go index 61273d2..181a797 100644 --- a/passwd.go +++ b/passwd.go @@ -33,6 +33,8 @@ type PasswdInterface interface { GenerateSalt() ([]byte, error) HashPassword(password []byte) (hash []byte, err error) HashPasswordWithSalt(password []byte, salt []byte) (hash []byte, err error) + SHashPassword(password string) (hash string, err error) + SHashPasswordWithSalt(password string, salt string) (hash string, err error) } // Base structure. @@ -263,6 +265,22 @@ func CheckPassword(hash []byte, password []byte) (bool, error) { return false, nil } +// Check a password hash against a password string. +func SCheckPassword(hash string, password string) (bool, error) { + passwd, err := NewPasswd(hash) + if err != nil { + return false, err + } + newHash, err := passwd.SHashPassword(password) + if err != nil { + return false, err + } + if hash == newHash { + return true, nil + } + return false, nil +} + // Used internally for salt generation. func generateRandomBytes(n uint) ([]byte, error) { b := make([]byte, n) @@ -323,3 +341,22 @@ func (a *Passwd) HashPasswordWithSalt(password []byte, salt []byte) (hash []byte err = errors.New("hash algorithm is not implemented") return } + +// Hash a password string. +func (a *Passwd) SHashPassword(password string) (hash string, err error) { + hashb, err := a.HashPassword([]byte(password)) + hash = string(hashb) + return +} + +// Hash a password string with a custom salt. +func (a *Passwd) SHashPasswordWithSalt(password string, salt string) (hash string, err error) { + var hashb []byte + if a.i != nil { + hashb, err = a.i.HashPasswordWithSalt([]byte(password), []byte(salt)) + } else { + hashb, err = a.HashPasswordWithSalt([]byte(password), []byte(salt)) + } + hash = string(hashb) + return +} diff --git a/pbkdf1_sha1_crypt.go b/pbkdf1_sha1_crypt.go index 856f018..5cc5737 100644 --- a/pbkdf1_sha1_crypt.go +++ b/pbkdf1_sha1_crypt.go @@ -68,3 +68,43 @@ func (a *SHA1Crypt) HashPasswordWithSalt(password []byte, salt []byte) (hash []b hash = a.Hash(password, salt, iterations) return } + +// Hash an password using default parameters with SHA1. +func HashSHA1Password(password []byte) (hash []byte, err error) { + passwd := NewSHA1Passwd() + hash, err = passwd.HashPassword(password) + if err != nil { + return + } + return +} + +// Hash an password with salt using default parameters with SHA1. +func HashSHA1PasswordWithSalt(password []byte, salt []byte) (hash []byte, err error) { + passwd := NewSHA1Passwd() + hash, err = passwd.HashPasswordWithSalt(password, salt) + if err != nil { + return + } + return +} + +// Hash an password string using default parameters with SHA1. +func SHashSHA1Password(password string) (hash string, err error) { + passwd := NewSHA1Passwd() + hash, err = passwd.SHashPassword(password) + if err != nil { + return + } + return +} + +// Hash an password string with salt using default parameters with SHA1. +func SHashSHA1PasswordWithSalt(password string, salt string) (hash string, err error) { + passwd := NewSHA1Passwd() + hash, err = passwd.SHashPasswordWithSalt(salt, salt) + if err != nil { + return + } + return +} diff --git a/s_crypt.go b/s_crypt.go index 037b010..1448750 100644 --- a/s_crypt.go +++ b/s_crypt.go @@ -32,7 +32,7 @@ func (a *SCrypt) SetSCryptParams(N, r, p int) (err error) { } // Decode SCrypt params. -func (a *SCrypt) DecodeSCriptParams() (N, r, p int) { +func (a *SCrypt) DecodeSCryptParams() (N, r, p int) { b64 := []byte(a.Params) if len(b64) != 11 { return @@ -45,7 +45,7 @@ func (a *SCrypt) DecodeSCriptParams() (N, r, p int) { // Hash a password with salt using scrypt standard. func (a *SCrypt) Hash(password []byte, salt []byte) (hash []byte, err error) { - N, r, p := a.DecodeSCriptParams() + N, r, p := a.DecodeSCryptParams() scryptHash, err := yescrypt.ScryptKey(password, salt, 1<