Files
minilb/pkg/passwd/passwd.go

117 lines
2.6 KiB
Go

package passwd
import (
"bytes"
"crypto/sha256"
"crypto/sha512"
"encoding/hex"
"fmt"
"math/rand"
"strings"
"time"
)
var rnd *rand.Rand
const (
sha256Prefix = "sha256pwd"
sha512Prefix = "sha512pwd"
saltSize = 12
)
func init() {
src := rand.NewSource(time.Now().UnixNano())
rnd = rand.New(src)
}
func MakeSHA256Hash(passwd []byte) string {
var res string
salt := hex.EncodeToString(randomBytes(saltSize))
passwdString := hex.EncodeToString(passwd)
passwdString = fmt.Sprintf("%s%s", passwdString, salt)
hasher := sha256.New()
hasher.Write([]byte(passwdString))
checksum := hex.EncodeToString(hasher.Sum(nil))
res = fmt.Sprintf("%s:%s:%s", sha256Prefix, salt, checksum)
return res
}
func MakeSHA512Hash(passwd []byte) string {
var res string
salt := hex.EncodeToString(randomBytes(saltSize))
passwdString := hex.EncodeToString(passwd)
passwdString = fmt.Sprintf("%s%s", passwdString, salt)
hasher := sha512.New()
hasher.Write([]byte(passwdString))
checksum := hex.EncodeToString(hasher.Sum(nil))
res = fmt.Sprintf("%s:%s:%s", sha512Prefix, salt, checksum)
return res
}
func PasswordMatchCompat(passwd []byte, hash string) bool {
if strings.HasPrefix(hash, sha256Prefix) || strings.HasPrefix(hash, sha512Prefix) {
return PasswordMatch(passwd, hash)
}
if bytes.Equal(passwd, []byte(hash)) {
return true
}
return false
}
func PasswordMatch(passwd []byte, hash string) bool {
hashComponents := strings.Split(hash, ":")
if len(hashComponents) != 3 {
return false
}
method := hashComponents[0]
salt := hashComponents[1]
controlChecksum := hashComponents[2]
switch method {
case sha256Prefix:
passwdString := hex.EncodeToString(passwd)
passwdString = fmt.Sprintf("%s%s", passwdString, salt)
hasher := sha256.New()
hasher.Write([]byte(passwdString))
checksum := hex.EncodeToString(hasher.Sum(nil))
if checksum != controlChecksum {
return false
}
case sha512Prefix:
passwdString := hex.EncodeToString(passwd)
passwdString = fmt.Sprintf("%s%s", passwdString, salt)
hasher := sha512.New()
hasher.Write([]byte(passwdString))
checksum := hex.EncodeToString(hasher.Sum(nil))
if checksum != controlChecksum {
return false
}
default:
return false
}
return true
}
func randomString(n int) string {
const letters = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
arr := make([]byte, n)
lettersArrayLen := len(letters)
for i := range arr {
arr[i] = letters[rnd.Intn(lettersArrayLen)]
}
return string(arr)
}
func randomBytes(n int) []byte {
arr := make([]byte, n)
for i := range arr {
arr[i] = byte(rnd.Intn(256) & 0xFF)
}
return arr
}