feat(accounts): default to Argon2id at 16 MiB, t=1
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>
This commit is contained in:
parent
1b0bdcf609
commit
1f4952e40e
3 changed files with 27 additions and 4 deletions
|
|
@ -74,4 +74,16 @@ public class PasswordProtectionTest
|
|||
|
||||
Assert.False(passwordProtection.ValidatePassword(encryptedPassword, "Not the same password"));
|
||||
}
|
||||
|
||||
// Produced by ModernUO's shipping default before this change: Argon2i, m=8192, t=3, p=1.
|
||||
// Pinned as a literal so it cannot drift with the configured defaults. Password: "hunter2".
|
||||
private const string LegacyArgon2iHash =
|
||||
"$argon2i$v=19$m=8192,t=3,p=1$LD1XJz7P3wQmIJ+Tu6ScgA$NO5hBABsHQ172C5nDO2X4gWnB4jDef3x6WhLdVE2LFw";
|
||||
|
||||
[Fact]
|
||||
public void Argon2_ValidatesLegacyArgon2iHash()
|
||||
{
|
||||
Assert.True(Argon2PasswordProtection.Instance.ValidatePassword(LegacyArgon2iHash, "hunter2"));
|
||||
Assert.False(Argon2PasswordProtection.Instance.ValidatePassword(LegacyArgon2iHash, "wrong"));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,11 +21,22 @@ public class Argon2PasswordProtection : IPasswordProtection
|
|||
{
|
||||
public static IPasswordProtection Instance = new Argon2PasswordProtection();
|
||||
|
||||
private readonly Argon2PasswordHasher m_PasswordHasher = new(rng: RandomNumberGenerator.Create());
|
||||
// Argon2id over Argon2i: RFC 9106 recommends Argon2i only where side-channel resistance is
|
||||
// required and memory is scarce. 16 MiB at t=1 measures cheaper than the old 8 MiB at t=3
|
||||
// (8.5 ms vs 10.1 ms) while doubling memory-hardness, which is the property that resists GPU
|
||||
// and ASIC cracking; iterations mostly buy wall-clock. p=1 because native argon2 spawns a
|
||||
// thread per lane, which is oversubscription on the 1-2 core hosts this path exists to serve.
|
||||
private readonly Argon2PasswordHasher _passwordHasher = new(
|
||||
time: 1,
|
||||
memory: 16384,
|
||||
parallel: 1,
|
||||
type: Argon2Type.Argon2id,
|
||||
rng: RandomNumberGenerator.Create()
|
||||
);
|
||||
|
||||
public string EncryptPassword(string plainPassword) =>
|
||||
m_PasswordHasher.Hash(plainPassword);
|
||||
_passwordHasher.Hash(plainPassword);
|
||||
|
||||
public bool ValidatePassword(string encryptedPassword, string plainPassword) =>
|
||||
m_PasswordHasher.Verify(encryptedPassword, plainPassword);
|
||||
_passwordHasher.Verify(encryptedPassword, plainPassword);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@
|
|||
<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.19.0" />
|
||||
<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" />
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue