HashMetadataValues carries SaltLength and HashLength alongside the type and
the cost parameters, and NeedsRehash ignored both. A hash with a 16-byte
digest or an 8-byte salt verified fine and was judged current forever --
exactly the drift this method exists to catch. Unreachable today, since
every hash ModernUO has written uses the library defaults of 32 and 16, but
that is a property of the current configuration rather than of the check.
The two lengths are the decoded sizes of the base64 segments rather than
entries in the m/t/p list, so they cannot be varied through the existing
theory template; they get their own rows with pinned literals. The
"current defaults" row of that theory is the negative control.
Also name the benchmark behind the 8.5 ms / 10.1 ms figures in the parameter
comment: ModernUO-Benchmarks/Benchmarks/Argon2Hashing.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Accounts corrupted by the pre-fix SetPassword hold argon2(username + password)
tagged with an algorithm whose phrase rule omits the username. Nothing in the
hash distinguishes that from a forgotten password, so the only detection is to
retry with the other phrase on a failed verify -- which doubles the cost of
every failed login, and failed logins are the credential-stuffing surface.
Hence accountSecurity.repairMigratedPasswords, default false: an operator turns
it on for a migration window and off again. Repaired accounts are force-rehashed
because their stored parameters may already be current, in which case NeedsRehash
would decline and the account would verify once and stay broken.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Argon2's PHC string embeds m, t and p, so verification uses the parameters
stored with each account rather than the configured ones -- and verify is the
hot path. CheckPassword only rehashed when the ALGORITHM changed, never when
its cost parameters did, so changing the defaults reached nobody on an
established shard and the change was cosmetic.
IPasswordProtection.NeedsRehash defaults to false, leaving PBKDF2 and the
HashAlgorithm protections untouched; only Argon2 carries cost in its stored
value. Logged at Debug because a restart migrates the whole population at once.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Argon2.Bindings 1.20.0 resolves the Argon2 type from the stored hash, so
existing Argon2i credentials keep verifying after this switch. Without that
bump this change locks out every existing account -- the pinned legacy-hash
test fails on 1.19.0 for exactly that reason.
16 MiB t=1 measures 8.51 ms against the old 8 MiB t=3 Argon2i at 10.11 ms:
cheaper AND stronger. Memory-hardness resists GPU and ASIC cracking;
iterations mostly buy wall-clock, so trade t down for m up. It also stays
below the 16-32 MiB L3 inflection, which starts to matter once hashing moves
off the game loop and contends with the loop's working set.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
### Summary
.NET 8 supports Xoroshiro 256** off the shelf and added Shuffle. Switching to that implementation.
### Developer Notes
* Removed many convenience methods that weren't used.
**Only one functional change**
* Fixes a bug in LogFactory where `Warning` is being logged as `Information`
Non-functional changes:
* Updates/Fixes copyright headers
* Removes namespace scopes for core files.
View with [whitespace off](https://github.com/modernuo/ModernUO/pull/1187/files?w=1).
* Fixes an issue with moving directories across volumes
* Removes usages of WebClient
* Removes usages of Cryptographic Providers
Note: Even though .NET 6 introduces Xoshiro RNG, there is no way to control the seed. I'll do some reconciliation of Xoshiro so it functions closer to the built in one. For the most part, it has parity though.
Benchmarks show there is nothing odd about the implementations, they are within 1ns of each other.
- [X] Removes some string allocations (e.g. split)
- [X] Optimizes some collections
- [X] Converts insensitive to extension methods of built-ins.
- [X] Adds ordinal (case sensitive) string helpers
- [X] Fixes conditionals for in-game commands so they use Ordinal comparisons.
- [X] Replaces ToLower.Contains with InsensitiveContains
- [X] Adds ValueStringBuilder
- [X] Implements ValueStringBuilder in a few places where it makes sense
- [X] Removes the redundant Wrap function and replaces it with an optimized version
- [X] Fixes list conversions in Utility
Closes#351
Bumps release version
- [X] Fixes several bugs
- [X] Updates more ordinal issues
- [X] Cleans up the code a bit
- [X] Turns classes static that should have been
- [X] Changes TcpServer.Instances to a HashSet
Bumps release version