72 lines
1.3 KiB
Go
72 lines
1.3 KiB
Go
package main
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"crypto/subtle"
|
|
"encoding/base64"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"golang.org/x/crypto/argon2"
|
|
)
|
|
|
|
const (
|
|
memory = 64 * 1024 // 64 MB
|
|
iterations = 3
|
|
parallelism = 2
|
|
saltLength = 16
|
|
keyLength = 32
|
|
)
|
|
|
|
func generateSalt() ([]byte, error) {
|
|
salt := make([]byte, saltLength)
|
|
_, err := rand.Read(salt)
|
|
return salt, err
|
|
}
|
|
|
|
func verifyPassword(password, encodedHash string) bool {
|
|
|
|
parts := strings.Split(encodedHash, "$")
|
|
|
|
params := parts[3]
|
|
salt := parts[4]
|
|
hash := parts[5]
|
|
|
|
var memory uint32
|
|
var iterations uint32
|
|
var parallelism uint8
|
|
|
|
fmt.Sscanf(params, "m=%d,t=%d,p=%d", &memory, &iterations, ¶llelism)
|
|
|
|
saltBytes, _ := base64.RawStdEncoding.DecodeString(salt)
|
|
hashBytes, _ := base64.RawStdEncoding.DecodeString(hash)
|
|
|
|
comparisonHash := argon2.IDKey(
|
|
[]byte(password),
|
|
saltBytes,
|
|
iterations,
|
|
memory,
|
|
parallelism,
|
|
uint32(len(hashBytes)),
|
|
)
|
|
|
|
return subtle.ConstantTimeCompare(hashBytes, comparisonHash) == 1
|
|
}
|
|
|
|
func hashPassword(password string, salt []byte) string {
|
|
hash := argon2.IDKey(
|
|
[]byte(password),
|
|
salt,
|
|
iterations,
|
|
memory,
|
|
parallelism,
|
|
keyLength,
|
|
)
|
|
|
|
b64Salt := base64.RawStdEncoding.EncodeToString(salt)
|
|
b64Hash := base64.RawStdEncoding.EncodeToString(hash)
|
|
|
|
return fmt.Sprintf("$argon2id$v=19$m=%d,t=%d,p=%d$%s$%s",
|
|
memory, iterations, parallelism, b64Salt, b64Hash)
|
|
}
|