Corrected spelling for SCrypt, added helper functions to make working with the package easier.

This commit is contained in:
GRMrGecko 2025-01-03 11:29:57 -06:00
parent dc9b8fee92
commit 5c67c91dde
14 changed files with 412 additions and 13 deletions

View File

@ -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

View File

@ -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.

2
go.mod
View File

@ -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
)

2
go.sum
View File

@ -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=

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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<<N, r, p, 32)
b64 := SCryptBase64Encode(scryptHash)
@ -59,3 +59,43 @@ func (a *SCrypt) HashPasswordWithSalt(password []byte, salt []byte) (hash []byte
hash, err = a.Hash(password, salt)
return
}
// Hash an password using default parameters with SCrypt.
func HashSCryptPassword(password []byte) (hash []byte, err error) {
passwd := NewSCryptPasswd()
hash, err = passwd.HashPassword(password)
if err != nil {
return
}
return
}
// Hash an password with salt using default parameters with SCrypt.
func HashSCryptPasswordWithSalt(password []byte, salt []byte) (hash []byte, err error) {
passwd := NewSCryptPasswd()
hash, err = passwd.HashPasswordWithSalt(password, salt)
if err != nil {
return
}
return
}
// Hash an password string using default parameters with SCrypt.
func SHashSCryptPassword(password string) (hash string, err error) {
passwd := NewSCryptPasswd()
hash, err = passwd.SHashPassword(password)
if err != nil {
return
}
return
}
// Hash an password string with salt using default parameters with SCrypt.
func SHashSCryptPasswordWithSalt(password string, salt string) (hash string, err error) {
passwd := NewSCryptPasswd()
hash, err = passwd.SHashPasswordWithSalt(salt, salt)
if err != nil {
return
}
return
}

View File

@ -139,3 +139,43 @@ func (a *SHA256Crypt) HashPasswordWithSalt(password []byte, salt []byte) (hash [
hash = a.Hash(password, salt, iterations)
return
}
// Hash an password using default parameters with SHA256.
func HashSHA256Password(password []byte) (hash []byte, err error) {
passwd := NewSHA256CryptPasswd()
hash, err = passwd.HashPassword(password)
if err != nil {
return
}
return
}
// Hash an password with salt using default parameters with SHA256.
func HashSHA256PasswordWithSalt(password []byte, salt []byte) (hash []byte, err error) {
passwd := NewSHA256CryptPasswd()
hash, err = passwd.HashPasswordWithSalt(password, salt)
if err != nil {
return
}
return
}
// Hash an password string using default parameters with SHA256.
func SHashSHA256Password(password string) (hash string, err error) {
passwd := NewSHA256CryptPasswd()
hash, err = passwd.SHashPassword(password)
if err != nil {
return
}
return
}
// Hash an password string with salt using default parameters with SHA256.
func SHashSHA256PasswordWithSalt(password string, salt string) (hash string, err error) {
passwd := NewSHA256CryptPasswd()
hash, err = passwd.SHashPasswordWithSalt(salt, salt)
if err != nil {
return
}
return
}

View File

@ -139,3 +139,43 @@ func (a *SHA512Crypt) HashPasswordWithSalt(password []byte, salt []byte) (hash [
hash = a.Hash(password, salt, iterations)
return
}
// Hash an password using default parameters with SHA512.
func HashSHA512Password(password []byte) (hash []byte, err error) {
passwd := NewSHA512CryptPasswd()
hash, err = passwd.HashPassword(password)
if err != nil {
return
}
return
}
// Hash an password with salt using default parameters with SHA512.
func HashSHA512PasswordWithSalt(password []byte, salt []byte) (hash []byte, err error) {
passwd := NewSHA512CryptPasswd()
hash, err = passwd.HashPasswordWithSalt(password, salt)
if err != nil {
return
}
return
}
// Hash an password string using default parameters with SHA512.
func SHashSHA512Password(password string) (hash string, err error) {
passwd := NewSHA512CryptPasswd()
hash, err = passwd.SHashPassword(password)
if err != nil {
return
}
return
}
// Hash an password string with salt using default parameters with SHA512.
func SHashSHA512PasswordWithSalt(password string, salt string) (hash string, err error) {
passwd := NewSHA512CryptPasswd()
hash, err = passwd.SHashPasswordWithSalt(salt, salt)
if err != nil {
return
}
return
}

View File

@ -176,3 +176,43 @@ func (a *SunMD5) HashPasswordWithSalt(password []byte, salt []byte) (hash []byte
hash = a.Hash(password, salt, iterations)
return
}
// Hash an password using default parameters with Sun MD5.
func HashSunMD5Password(password []byte) (hash []byte, err error) {
passwd := NewSunMD5Passwd()
hash, err = passwd.HashPassword(password)
if err != nil {
return
}
return
}
// Hash an password with salt using default parameters with Sun MD5.
func HashSunMD5PasswordWithSalt(password []byte, salt []byte) (hash []byte, err error) {
passwd := NewSunMD5Passwd()
hash, err = passwd.HashPasswordWithSalt(password, salt)
if err != nil {
return
}
return
}
// Hash an password string using default parameters with Sun MD5.
func SHashSunMD5Password(password string) (hash string, err error) {
passwd := NewSunMD5Passwd()
hash, err = passwd.SHashPassword(password)
if err != nil {
return
}
return
}
// Hash an password string with salt using default parameters with Sun MD5.
func SHashSunMD5PasswordWithSalt(password string, salt string) (hash string, err error) {
passwd := NewSunMD5Passwd()
hash, err = passwd.SHashPasswordWithSalt(salt, salt)
if err != nil {
return
}
return
}

View File

@ -36,7 +36,7 @@ func (a *YesCrypt) SetSCryptParams(N, r int) (err error) {
}
// Decode SCrypt params.
func (a *YesCrypt) DecodeSCriptParams() (N, r int) {
func (a *YesCrypt) DecodeSCryptParams() (N, r int) {
b64 := []byte(a.Params)
if len(b64) != 3 {
return
@ -58,3 +58,43 @@ func (a *YesCrypt) HashPasswordWithSalt(password []byte, salt []byte) (hash []by
hash, err = a.Hash(password, salt)
return
}
// Hash an password using default parameters with YesCrypt.
func HashYesCryptPassword(password []byte) (hash []byte, err error) {
passwd := NewYesCryptPasswd()
hash, err = passwd.HashPassword(password)
if err != nil {
return
}
return
}
// Hash an password with salt using default parameters with YesCrypt.
func HashYesCryptPasswordWithSalt(password []byte, salt []byte) (hash []byte, err error) {
passwd := NewYesCryptPasswd()
hash, err = passwd.HashPasswordWithSalt(password, salt)
if err != nil {
return
}
return
}
// Hash an password string using default parameters with YesCrypt.
func SHashYesCryptPassword(password string) (hash string, err error) {
passwd := NewYesCryptPasswd()
hash, err = passwd.SHashPassword(password)
if err != nil {
return
}
return
}
// Hash an password string with salt using default parameters with YesCrypt.
func SHashYesCryptPasswordWithSalt(password string, salt string) (hash string, err error) {
passwd := NewYesCryptPasswd()
hash, err = passwd.SHashPasswordWithSalt(salt, salt)
if err != nil {
return
}
return
}