> ⚠️ **Rollback hazard — one-way door once logins are taken.** Serialization is unchanged, so a save > written by this build still *loads* on the previous one. Its contents do not survive the trip: on > its first successful login each account is rehashed to `$argon2id$`, and the previous build ships > Argon2.Bindings 1.19.0, whose `Verify` is gated by the verifier's own configured type and answers > `false` for an `$argon2id$` hash. **After a shard running this build has accepted logins, do not > roll back past this commit** — every account that logged in is locked out on the older binary, and > the only recovery is rolling forward again or resetting passwords by hand. Roll back only from a > save taken before the first post-deploy login. Requires [Argon2.Bindings 1.20.0](https://github.com/modernuo/Argon2.Bindings/pull/14), now published. ## What - Consume `Argon2.Bindings` 1.20.0, which resolves the Argon2 type from the stored PHC string rather than from the verifier's own configuration. - Default to **Argon2id, m=16384, t=1, p=1** — 8.51 ms against the old Argon2i 8 MiB t=3 at 10.11 ms. Cheaper *and* stronger. - Rehash on a successful login whenever the stored parameters are stale, not only when the algorithm changes. - Fix `SetPassword`, which derived the password phrase from the outgoing algorithm while storing it under the incoming one. ## Why **Verification was gated by the verifier's configured type.** `Verify` passed the instance's own `ArgonType` to native `argon2_verify`, whose `decode_string` rejects a disagreeing `$argon2i$`/`$argon2id$` prefix and returns `DECODING_FAIL` — folded into `false`, the same answer as a wrong password. Switching the default type would have locked out every existing account, and `VerifyAndUpdate` could not have migrated them either: it delegates to the same type-fixed `Verify` and never compared `ArgonType`. Fixed upstream in 1.20.0. The pinned legacy-`$argon2i$` test here fails on 1.19.0 for exactly that reason, which is what makes the package bump load-bearing rather than incidental. **Changing the defaults would otherwise have reached nobody.** Argon2's PHC string embeds `m`, `t` and `p`, so verification uses the parameters stored with each account, not the configured ones — and verification is the hot path. `CheckPassword` only rehashed when the *algorithm* changed, never when its cost parameters did, so on an established shard the new defaults would have applied to new accounts only. `IPasswordProtection.NeedsRehash` closes that: it defaults to `false`, so PBKDF2 and the `HashAlgorithm` protections are untouched — only Argon2 carries its cost inside the stored value. **`SetPassword` picked the phrase rule from the wrong algorithm.** SHA1 and SHA2 salt the phrase with the username; Argon2 and PBKDF2 do not. It chose the rule from the *outgoing* algorithm while storing under the *incoming* one, so any algorithm change wrote a credential its own next verify could not reproduce. It now assigns `PasswordAlgorithm` first and derives the phrase from that. Note this ordering is load-bearing and invisible — `UpgradingAlgorithm_DoesNotLockTheAccountOut` is what pins it. ## Cost Verification is re-derivation, so these are login numbers. A full login calls `CheckPassword` twice — `AccountLogin` (0x80) then `GameLogin` (0x91): **~20 ms before, ~17 ms after**, plus a one-time ~8.5 ms rehash on each account's migrating login. That cost is still paid on the game loop. Moving hashing off-loop is deliberately **not** in this PR — it needs a pending-auth state in the login handlers, bounding of in-flight hashes, and login rate limiting.
63 lines
4.6 KiB
XML
63 lines
4.6 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="Current">
|
|
<PropertyGroup>
|
|
<RootNamespace>Server</RootNamespace>
|
|
<AssemblyName>UOContent</AssemblyName>
|
|
<Product>ModernUO Content</Product>
|
|
<OutDir>..\..\Distribution\Assemblies</OutDir>
|
|
<PublishDir>..\..\Distribution\Assemblies</PublishDir>
|
|
<Configurations>Debug;Release;Analyze</Configurations>
|
|
</PropertyGroup>
|
|
<Target Name="CleanPub" AfterTargets="Clean">
|
|
<Message Text="UOContent: Removing distribution assemblies..." />
|
|
<Delete Files="..\..\Distribution\Assemblies\Argon2.Bindings.dll" ContinueOnError="true" />
|
|
<Delete Files="..\..\Distribution\Assemblies\libargon2.dll" ContinueOnError="true" />
|
|
<Delete Files="..\..\Distribution\Assemblies\BouncyCastle.Cryptography.dll" ContinueOnError="true" />
|
|
<Delete Files="..\..\Distribution\Assemblies\MailKit.dll" ContinueOnError="true" />
|
|
<Delete Files="..\..\Distribution\Assemblies\MimeKit.dll" ContinueOnError="true" />
|
|
<Delete Files="..\..\Distribution\Assemblies\Microsoft.Toolkit.HighPerformance.dll" ContinueOnError="true" />
|
|
<Delete Files="..\..\Distribution\Assemblies\CommunityToolkit.HighPerformance.dll" ContinueOnError="true" />
|
|
<Delete Files="..\..\Distribution\Assemblies\Microsoft.Extensions.FileSystemGlobbing.dll" ContinueOnError="true" />
|
|
<Delete Files="..\..\Distribution\Assemblies\Serilog.dll" ContinueOnError="true" />
|
|
<Delete Files="..\..\Distribution\Assemblies\Serilog.Sinks.Async.dll" ContinueOnError="true" />
|
|
<Delete Files="..\..\Distribution\Assemblies\Serilog.Sinks.Console.dll" ContinueOnError="true" />
|
|
<Delete Files="..\..\Distribution\Assemblies\System.Security.Cryptography.Pkcs.dll" ContinueOnError="true" />
|
|
<Delete Files="..\..\Distribution\Assemblies\$(AssemblyName).dll" ContinueOnError="true" />
|
|
<Delete Files="..\..\Distribution\Assemblies\ref\$(AssemblyName).dll" ContinueOnError="true" />
|
|
<Delete Files="..\..\Distribution\Assemblies\$(AssemblyName).deps.json" ContinueOnError="true" />
|
|
<Delete Files="..\..\Distribution\Assemblies\$(AssemblyName).pdb" ContinueOnError="true" />
|
|
<Delete Files="..\..\Distribution\Assemblies\LibDeflate.Bindings.dll" ContinueOnError="true" />
|
|
<Delete Files="..\..\Distribution\Assemblies\libdeflate.dll" ContinueOnError="true" />
|
|
<Delete Files="..\..\Distribution\Assemblies\libdeflate.dylib" ContinueOnError="true" />
|
|
<Delete Files="..\..\Distribution\Assemblies\ZstdNet.dll" ContinueOnError="true" />
|
|
<Delete Files="..\..\Distribution\Assemblies\libzstd.dll" ContinueOnError="true" />
|
|
<Delete Files="..\..\Distribution\Assemblies\ModernUO.Serialization.Annotations.dll" ContinueOnError="true" />
|
|
<Delete Files="..\..\Distribution\Assemblies\ModernUO.CodeGeneratedEvents.Annotations.dll" ContinueOnError="true" />
|
|
<Delete Files="..\..\Distribution\Assemblies\ModernUO.CodeGeneratedEvents.Generator.dll" ContinueOnError="true" />
|
|
</Target>
|
|
<ItemGroup>
|
|
<ProjectReference Include="..\Logger\Logger.csproj" />
|
|
<ProjectReference Include="..\Server\Server.csproj" Private="false" PrivateAssets="All" IncludeAssets="None">
|
|
<IncludeInPackage>false</IncludeInPackage>
|
|
</ProjectReference>
|
|
<PackageReference Include="LibDeflate.Bindings" Version="1.0.4" />
|
|
<PackageReference Include="System.IO.Hashing" Version="10.0.10" />
|
|
<PackageReference Include="MailKit" Version="4.17.0" />
|
|
<PackageReference Include="Microsoft.Extensions.FileSystemGlobbing" Version="10.0.10" />
|
|
<PackageReference Include="CommunityToolkit.HighPerformance" Version="8.4.2" />
|
|
<PackageReference Include="Argon2.Bindings" Version="1.20.0" />
|
|
<PackageReference Include="ModernUO.CodeGeneratedEvents.Annotations" Version="1.0.0" />
|
|
<PackageReference Include="ModernUO.CodeGeneratedEvents.Generator" Version="1.0.3.2" PrivateAssets="all" />
|
|
<PackageReference Include="ZstdNet" Version="1.5.7" />
|
|
|
|
<PackageReference Include="ModernUO.Serialization.Annotations" Version="2.14.2" />
|
|
<PackageReference Include="ModernUO.Serialization.Generator" Version="2.14.3" />
|
|
<PackageReference Update="Serilog" Version="4.4.0" />
|
|
</ItemGroup>
|
|
<ItemGroup>
|
|
<AdditionalFiles Include="Migrations/*.v*.json" />
|
|
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
|
|
<_Parameter1>UOContent.Tests</_Parameter1>
|
|
</AssemblyAttribute>
|
|
</ItemGroup>
|
|
</Project>
|