72 lines
1.4 KiB
Go
72 lines
1.4 KiB
Go
package security
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"crypto/sha512"
|
|
"crypto/subtle"
|
|
"encoding/base64"
|
|
"fmt"
|
|
"io"
|
|
"strings"
|
|
|
|
"golang.org/x/crypto/argon2"
|
|
)
|
|
|
|
const (
|
|
argonTime = 3
|
|
argonMemory = 64 * 1024
|
|
argonThreads = 2
|
|
argonSaltLen = 16
|
|
argonKeyLen = 64
|
|
)
|
|
|
|
func HashFileReader(r io.Reader) (string, error) {
|
|
h := sha512.New()
|
|
if _, err := io.Copy(h, r); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// return in b64 encoding
|
|
return base64.StdEncoding.EncodeToString(h.Sum(nil)), nil
|
|
}
|
|
|
|
func HashKey(key string) (string, error) {
|
|
salt := make([]byte, argonSaltLen)
|
|
rand.Read(salt)
|
|
|
|
hash := argon2.IDKey([]byte(key), salt, argonTime, argonMemory, argonThreads, argonKeyLen)
|
|
|
|
// encode internally (NOT in handler)
|
|
b64Salt := base64.RawStdEncoding.EncodeToString(salt)
|
|
b64Hash := base64.RawStdEncoding.EncodeToString(hash)
|
|
|
|
// single stored string
|
|
encoded := fmt.Sprintf("v1:%s:%s", b64Salt, b64Hash)
|
|
|
|
return encoded, nil
|
|
}
|
|
|
|
func CompareKey(key, candidate string) bool {
|
|
parts := strings.Split(candidate, ":")
|
|
if len(parts) != 3 {
|
|
return false
|
|
}
|
|
//version := parts[0]
|
|
b64Salt := parts[1]
|
|
b64Hash := parts[2]
|
|
|
|
salt, err := base64.RawStdEncoding.DecodeString(b64Salt)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
expected, err := base64.RawStdEncoding.DecodeString(b64Hash)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
actual := argon2.IDKey([]byte(key), salt, argonTime, argonMemory, argonThreads, argonKeyLen)
|
|
|
|
return subtle.ConstantTimeCompare(actual, expected) == 1
|
|
}
|