package auth import ( "encoding/hex" "testing" "time" ) // Known-answer test for the hand-rolled PBKDF2-HMAC-SHA256 core, so a typo // in the loop (block index, XOR fold, etc.) fails loudly instead of just // producing a hash that happens to round-trip against itself. func TestPBKDF2Vector(t *testing.T) { got := pbkdf2("password", []byte("salt"), 1, 32) want, _ := hex.DecodeString("120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b") if hex.EncodeToString(got) != hex.EncodeToString(want) { t.Fatalf("pbkdf2(password,salt,1,32) = %x, want %x", got, want) } } func TestHashAndVerifyPassword(t *testing.T) { hash, err := HashPassword("correct horse battery staple") if err != nil { t.Fatal(err) } if !VerifyPassword("correct horse battery staple", hash) { t.Fatal("VerifyPassword rejected the correct password") } if VerifyPassword("wrong password", hash) { t.Fatal("VerifyPassword accepted the wrong password") } } // RFC 4226 Appendix D HOTP test vectors (secret "12345678901234567890", // 6-digit truncation) — TOTP is just HOTP with counter = unixtime/step, so // this pins down the shared HMAC/truncation core. func TestHOTPVectors(t *testing.T) { secret := []byte("12345678901234567890") want := []string{ "755224", "287082", "359152", "969429", "338314", "254676", "287922", "162583", "399871", "520489", } for counter, code := range want { got := hotp(secret, uint64(counter), 6) if got != code { t.Fatalf("hotp(counter=%d) = %s, want %s", counter, got, code) } } } func TestValidateTOTPRoundtrip(t *testing.T) { secret, err := NewTOTPSecret() if err != nil { t.Fatal(err) } code, err := totpAt(secret, time.Now()) if err != nil { t.Fatal(err) } if !ValidateTOTP(secret, code) { t.Fatal("ValidateTOTP rejected a freshly generated code") } if ValidateTOTP(secret, "000000") { t.Fatal("ValidateTOTP accepted an arbitrary wrong code") } } func TestSessionTokenRoundtrip(t *testing.T) { key := []byte("0123456789abcdef0123456789abcdef") tok := NewSessionToken(key, "admin", 3, time.Hour) user, version, ok := ParseSessionToken(key, tok) if !ok || user != "admin" || version != 3 { t.Fatalf("roundtrip failed: user=%q version=%d ok=%v", user, version, ok) } if _, _, ok := ParseSessionToken(key, tok+"tampered"); ok { t.Fatal("ParseSessionToken accepted a tampered token") } otherKey := []byte("ffffffffffffffffffffffffffffffff") if _, _, ok := ParseSessionToken(otherKey, tok); ok { t.Fatal("ParseSessionToken accepted a token signed with a different key") } }