Skip to content

Commit 2a87990

Browse files
bfourCopilot
andcommitted
use Argon2 KDF for key derivation
Co-authored-by: Copilot <copilot@github.com>
1 parent 8950391 commit 2a87990

1 file changed

Lines changed: 21 additions & 8 deletions

File tree

src/QuickUnlockKeyProv.cs

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -572,16 +572,29 @@ private static ProtectedBinary DecryptKey(ProtectedString QuickUnlockKey, Protec
572572

573573
private static byte[] AdjustQuickUnlockKey(ProtectedString QuickUnlockKey, byte[] salt)
574574
{
575-
byte[] bUtf8 = QuickUnlockKey.ReadUtf8(); // must be wiped
576-
byte[] derivedKey;
577-
578-
// use standard PBKDF2 to mitigate brute-forcing of short PINs
579-
using (var rfc2898 = new Rfc2898DeriveBytes(bUtf8, salt, 100000))
575+
byte[] bUtf8 = QuickUnlockKey.ReadUtf8();
576+
byte[] derivedKey = null;
577+
578+
try
580579
{
581-
derivedKey = rfc2898.GetBytes(32); // 256 bits required for ChaCha20
580+
KdfParameters kdfParams = new KdfParameters(KeePassLib.Cryptography.KeyDerivation.KdfUuid.Argon2);
581+
582+
// these should be set to values that provide a good balance between security and performance for quick unlock scenarios
583+
kdfParams.SetUInt64(KdfParameters.KeyArgon2Iterations, 3);
584+
kdfParams.SetUInt64(KdfParameters.KeyArgon2Memory, 64 * 1024 * 1024); // memory cost (64 MiB)
585+
kdfParams.SetUInt32(KdfParameters.KeyArgon2Parallelism, 2); // thread count
586+
kdfParams.SetBytes("S", salt);
587+
588+
var argon2 = new KeePassLib.Cryptography.KeyDerivation.Argon2Kdf();
589+
derivedKey = argon2.Generate(bUtf8, kdfParams);
582590
}
583-
584-
MemUtil.ZeroByteArray(bUtf8);
591+
finally
592+
{
593+
// Ensure the plaintext PIN is scrubbed from memory immediately
594+
MemUtil.ZeroByteArray(bUtf8);
595+
}
596+
597+
// The returned derivedKey will naturally be 256 bits (32 bytes)
585598
return derivedKey;
586599
}
587600
}

0 commit comments

Comments
 (0)