86 lines
2.1 KiB
Go
86 lines
2.1 KiB
Go
package auth
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/base64"
|
|
"errors"
|
|
"fmt"
|
|
"testing"
|
|
|
|
"golang.org/x/crypto/argon2"
|
|
)
|
|
|
|
// Assertion helpers. Failures are fatal: most tests below are sequential
|
|
// protocol exchanges where continuing past a failure only produces noise.
|
|
|
|
func noErr(t *testing.T, err error, ctx string) {
|
|
t.Helper()
|
|
if err != nil {
|
|
t.Fatalf("%s: unexpected error: %v", ctx, err)
|
|
}
|
|
}
|
|
|
|
func hasErr(t *testing.T, err error, ctx string) {
|
|
t.Helper()
|
|
if err == nil {
|
|
t.Fatalf("%s: expected error, got nil", ctx)
|
|
}
|
|
}
|
|
|
|
func errIs(t *testing.T, err, target error, ctx string) {
|
|
t.Helper()
|
|
if !errors.Is(err, target) {
|
|
t.Fatalf("%s: got %v, want %v", ctx, err, target)
|
|
}
|
|
}
|
|
|
|
func eq[T comparable](t *testing.T, got, want T, ctx string) {
|
|
t.Helper()
|
|
if got != want {
|
|
t.Fatalf("%s: got %v, want %v", ctx, got, want)
|
|
}
|
|
}
|
|
|
|
func eqBytes(t *testing.T, got, want []byte, ctx string) {
|
|
t.Helper()
|
|
if !bytes.Equal(got, want) {
|
|
t.Fatalf("%s: got %x, want %x", ctx, got, want)
|
|
}
|
|
}
|
|
|
|
func isTrue(t *testing.T, v bool, ctx string) {
|
|
t.Helper()
|
|
if !v {
|
|
t.Fatalf("%s: got false, want true", ctx)
|
|
}
|
|
}
|
|
|
|
// Test KDF cost. Parameter handling is verified independently of parameter
|
|
// magnitude, so every test that does not measure defaults uses these.
|
|
const (
|
|
testArgonTime = 1
|
|
testArgonMemory = 8 * 1024
|
|
testArgonThreads = 1
|
|
)
|
|
|
|
var cheapArgon = []Option{
|
|
WithTime(testArgonTime),
|
|
WithMemory(testArgonMemory),
|
|
WithThreads(testArgonThreads),
|
|
}
|
|
|
|
// rawB64 encodes n zero bytes in the PHC alphabet.
|
|
func rawB64(n int) string {
|
|
return base64.RawStdEncoding.EncodeToString(make([]byte, n))
|
|
}
|
|
|
|
// phcFor builds a PHC record with an arbitrary salt and digest length, which
|
|
// HashPassword cannot produce.
|
|
func phcFor(password string, salt []byte, keyLen uint32) string {
|
|
digest := argon2.IDKey([]byte(password), salt, testArgonTime, testArgonMemory, testArgonThreads, keyLen)
|
|
return fmt.Sprintf("$argon2id$v=%d$m=%d,t=%d,p=%d$%s$%s",
|
|
argon2.Version, testArgonMemory, testArgonTime, testArgonThreads,
|
|
base64.RawStdEncoding.EncodeToString(salt),
|
|
base64.RawStdEncoding.EncodeToString(digest))
|
|
}
|