diff options
| author | historia <[not public]> | 2026-09-18 05:31:09 -0400 |
|---|---|---|
| committer | historia <[not public]> | 2026-09-18 05:31:09 -0400 |
| commit | 153acb7f644d755c45533b7c5311e3ffa47e8973 (patch) | |
| tree | 7645e6f7b65bc3830b078e3b9336d2e6b199d584 /internal/player/hardening_password_params_test.go | |
| parent | 87d08f0151e643951769e323995f1c5ed89ee200 (diff) | |
| download | thehouseoficarus-153acb7f644d755c45533b7c5311e3ffa47e8973.tar.gz | |
fix: harden engine across casino, economy, concurrency, security, and content
Diffstat (limited to 'internal/player/hardening_password_params_test.go')
| -rw-r--r-- | internal/player/hardening_password_params_test.go | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/internal/player/hardening_password_params_test.go b/internal/player/hardening_password_params_test.go new file mode 100644 index 0000000..4c171f1 --- /dev/null +++ b/internal/player/hardening_password_params_test.go @@ -0,0 +1,62 @@ +package player + +// Regression: Argon2id parameters parsed from a stored hash must be bounded +// before they reach argon2.IDKey. A hand-edited or corrupted account file +// (e.g. argon2id:1:4294967295:...) must fail the check, not request a +// multi-TiB allocation that kills the process. + +import ( + "crypto/sha256" + "encoding/base64" + "encoding/hex" + "testing" +) + +func TestCheckPasswordRejectsOutOfRangeArgonParams(t *testing.T) { + // Enormous memory cost (0xFFFFFFFF KiB) with an otherwise well-formed + // hash: must be rejected before hashing. + huge := "argon2id:1:4294967295:2:AAAAAAAAAAAAAAAAAAAAAA:0011223344556677889900112233445566778899001122334455667788990011" + if CheckPassword("pw", huge) { + t.Fatal("out-of-range Argon2 memory cost was accepted") + } + + // Negative values would wrap through uint32 under a naive conversion. + negative := "argon2id:-1:-1:-1:AAAAAAAAAAAAAAAAAAAAAA:0011223344556677889900112233445566778899001122334455667788990011" + if CheckPassword("pw", negative) { + t.Fatal("negative Argon2 parameters were accepted") + } + + // Absurd time cost is bounded too. + slow := "argon2id:4294967295:65536:2:AAAAAAAAAAAAAAAAAAAAAA:0011223344556677889900112233445566778899001122334455667788990011" + if CheckPassword("pw", slow) { + t.Fatal("out-of-range Argon2 time cost was accepted") + } +} + +func TestCheckPasswordAcceptsNormalAndLegacyHashes(t *testing.T) { + hashed, err := HashPassword("s3cret") + if err != nil { + t.Fatal(err) + } + if !CheckPassword("s3cret", hashed) { + t.Fatal("valid Argon2id hash rejected") + } + if CheckPassword("wrong", hashed) { + t.Fatal("wrong password accepted") + } + + // Legacy single-pass sha256 hashes must keep verifying so old accounts + // can still log in and be upgraded. + salt := []byte("sixteen-byte-slt") + sum := sha256.Sum256(append(append([]byte{}, salt...), []byte("pw")...)) + legacy := "sha256:" + base64.RawStdEncoding.EncodeToString(salt) + ":" + hex.EncodeToString(sum[:]) + if !CheckPassword("pw", legacy) { + t.Fatal("legacy sha256 hash rejected") + } + if CheckPassword("nope", legacy) { + t.Fatal("wrong password accepted against legacy sha256 hash") + } + if !NeedsRehash(legacy) { + t.Fatal("legacy sha256 hash not flagged for rehash") + } +} |
