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/password.go | |
| parent | 87d08f0151e643951769e323995f1c5ed89ee200 (diff) | |
| download | thehouseoficarus-153acb7f644d755c45533b7c5311e3ffa47e8973.tar.gz | |
fix: harden engine across casino, economy, concurrency, security, and content
Diffstat (limited to 'internal/player/password.go')
| -rw-r--r-- | internal/player/password.go | 25 |
1 files changed, 25 insertions, 0 deletions
diff --git a/internal/player/password.go b/internal/player/password.go index 9be39fb..5a43e1b 100644 --- a/internal/player/password.go +++ b/internal/player/password.go @@ -31,6 +31,23 @@ const ( argonSaltLen = 16 ) +// Sanity bounds applied to Argon2id parameters parsed from a stored hash. +// HashPassword always writes the constants above, but a hand-edited or +// corrupted account file can carry arbitrary numbers; without these bounds a +// value like 4294967295 (or a negative that wraps through uint32) makes +// argon2.IDKey request a multi-TiB allocation and kills the process instead of +// failing the login. Anything outside these ranges is rejected before hashing. +const ( + argonMinTime = 1 + argonMaxTime = 8 + argonMinMemory = 8 * 1024 // KiB (8 MiB) + argonMaxMemory = 256 * 1024 // KiB (256 MiB) + argonMinThreads = 1 + argonMaxThreads = 16 + argonMinKeyLen = 16 + argonMaxKeyLen = 64 +) + // hashLimiter bounds concurrent Argon2id computations. Each hash costs // ~64 MiB and tens of milliseconds, so an unbounded burst of logins (or // login attempts) would spike memory and CPU in parallel. Password work @@ -81,6 +98,14 @@ func CheckPassword(password, stored string) bool { if errT != nil || errM != nil || errP != nil || errSalt != nil || errKey != nil { return false } + if t < argonMinTime || t > argonMaxTime || + m < argonMinMemory || m > argonMaxMemory || + p < argonMinThreads || p > argonMaxThreads || + len(expected) < argonMinKeyLen || len(expected) > argonMaxKeyLen { + // Out-of-range parameters: fail the check instead of trusting the + // stored values and requesting an enormous allocation. + return false + } acquireHashSlot() key := argon2.IDKey([]byte(password), salt, uint32(t), uint32(m), uint8(p), uint32(len(expected))) releaseHashSlot() |
