68 lines
1.4 KiB
Go
68 lines
1.4 KiB
Go
package passwords
|
|
|
|
import (
|
|
"crypto/subtle"
|
|
"fmt"
|
|
"strings"
|
|
|
|
randomutil "git.maronato.dev/maronato/goshort/internal/util/random"
|
|
)
|
|
|
|
func GenerateSalt(n int) []byte {
|
|
salt, err := randomutil.GenerateRandomBytes(n)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return salt
|
|
}
|
|
|
|
func AreEqual(key1, key2 []byte) bool {
|
|
return subtle.ConstantTimeCompare(key1, key2) == 1
|
|
}
|
|
|
|
func EncodePasswordHash(algorithm, salt, hash string, params map[string]string) string {
|
|
// Create the param string
|
|
paramStrings := make([]string, len(params))
|
|
idx := 0
|
|
|
|
for key, value := range params {
|
|
paramStrings[idx] = key + "=" + value
|
|
idx++
|
|
}
|
|
|
|
paramString := strings.Join(paramStrings, ",")
|
|
|
|
// Return the encoded hash
|
|
return fmt.Sprintf("%s$%s$%s$%s", algorithm, paramString, salt, hash)
|
|
}
|
|
|
|
const (
|
|
hashlen = 4
|
|
kvpartlen = 2
|
|
)
|
|
|
|
func DecodePasswordHash(encodedHash string) (algorithm, salt, hash string, params map[string]string, err error) {
|
|
// Split the encoded hash into its parts
|
|
parts := strings.Split(encodedHash, "$")
|
|
|
|
if len(parts) != hashlen {
|
|
return "", "", "", nil, ErrInvalidHash
|
|
}
|
|
|
|
params = make(map[string]string)
|
|
|
|
paramsKV := strings.Split(parts[1], ",")
|
|
for _, kv := range paramsKV {
|
|
kvParts := strings.Split(kv, "=")
|
|
if len(kvParts) != kvpartlen {
|
|
return "", "", "", nil, ErrInvalidHash
|
|
}
|
|
|
|
params[kvParts[0]] = kvParts[1]
|
|
}
|
|
|
|
// Return the parts
|
|
return parts[0], parts[2], parts[3], params, nil
|
|
}
|