From a6489b16b47e8165dfbdd47e4b168f6422a7c602 Mon Sep 17 00:00:00 2001 From: navferty Date: Tue, 15 Jul 2025 22:15:08 +0400 Subject: [PATCH 1/3] #62732 Fix password validation in PasswordHasher`1: add check for upper bound for salt size before allocation an array --- src/Identity/Extensions.Core/src/PasswordHasher.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Identity/Extensions.Core/src/PasswordHasher.cs b/src/Identity/Extensions.Core/src/PasswordHasher.cs index cdd9a1ff3cec..7ede31f94fb6 100644 --- a/src/Identity/Extensions.Core/src/PasswordHasher.cs +++ b/src/Identity/Extensions.Core/src/PasswordHasher.cs @@ -260,7 +260,7 @@ private static bool VerifyHashedPasswordV3(byte[] hashedPassword, string passwor int saltLength = (int)ReadNetworkByteOrder(hashedPassword, 9); // Read the salt: must be >= 128 bits - if (saltLength < 128 / 8) + if (saltLength < 128 / 8 || saltLength + 13 > hashedPassword.Length) { return false; } From 04f08b300e70733df00fe9ec096e039c7cdaa094 Mon Sep 17 00:00:00 2001 From: navferty Date: Thu, 17 Jul 2025 16:18:02 +0400 Subject: [PATCH 2/3] Add test cases for password hash verification Verification should fail if salt size is less that minimum allowed (16 bytes) or greater that entire data lenght --- src/Identity/test/Identity.Test/PasswordHasherTest.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Identity/test/Identity.Test/PasswordHasherTest.cs b/src/Identity/test/Identity.Test/PasswordHasherTest.cs index e31a877e67f5..ba92689fbe99 100644 --- a/src/Identity/test/Identity.Test/PasswordHasherTest.cs +++ b/src/Identity/test/Identity.Test/PasswordHasherTest.cs @@ -112,6 +112,8 @@ public void HashPassword_Version3() [InlineData("AQAAAAAAAAD6AAAAEAhftMyfTJyAAAAAAAAAAAAAAAAAAAih5WsjXaR3PA9M")] // incorrect password [InlineData("AQAAAAIAAAAyAAAAEOMwvh3+FZxqkdMBz2ekgGhwQ4A=")] // too short [InlineData("AQAAAAIAAAAyAAAAEOMwvh3+FZxqkdMBz2ekgGhwQ4B6pZWND6zgESBuWiHwAAAAAAAAAAAA")] // extra data at end + [InlineData("AQAAAAIAAYagAP///wABAgMEBQYHCAkKCwwNDg/Q8A0WMKbtHQJQ2DHCdoEeeFBrgNlldq6vH4qX/CGqGQ==")] // salt length greater than data length + [InlineData("AQAAAAIAAYagAAAACAABAgMEBQYH4qLSh7iNSI12qySxAkyR0XgpXpvNiwqhBJFNLbJKKFw=")] // salt length (8 bytes) less than minimum allowed public void VerifyHashedPassword_FailureCases(string hashedPassword) { // Arrange From edc2fe30d3a401335f6cfd22e46f4db920a2cd0a Mon Sep 17 00:00:00 2001 From: navferty Date: Thu, 17 Jul 2025 23:30:24 +0400 Subject: [PATCH 3/3] Change salt extraction from hashed data using AsSpan, add test case for int.MaxValue --- src/Identity/Extensions.Core/src/PasswordHasher.cs | 5 ++--- src/Identity/test/Identity.Test/PasswordHasherTest.cs | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Identity/Extensions.Core/src/PasswordHasher.cs b/src/Identity/Extensions.Core/src/PasswordHasher.cs index 7ede31f94fb6..a8115f68eefc 100644 --- a/src/Identity/Extensions.Core/src/PasswordHasher.cs +++ b/src/Identity/Extensions.Core/src/PasswordHasher.cs @@ -260,12 +260,11 @@ private static bool VerifyHashedPasswordV3(byte[] hashedPassword, string passwor int saltLength = (int)ReadNetworkByteOrder(hashedPassword, 9); // Read the salt: must be >= 128 bits - if (saltLength < 128 / 8 || saltLength + 13 > hashedPassword.Length) + if (saltLength < 128 / 8) { return false; } - byte[] salt = new byte[saltLength]; - Buffer.BlockCopy(hashedPassword, 13, salt, 0, salt.Length); + byte[] salt = hashedPassword.AsSpan(13, saltLength).ToArray(); // Read the subkey (the rest of the payload): must be >= 128 bits int subkeyLength = hashedPassword.Length - 13 - salt.Length; diff --git a/src/Identity/test/Identity.Test/PasswordHasherTest.cs b/src/Identity/test/Identity.Test/PasswordHasherTest.cs index ba92689fbe99..74cf2d152dad 100644 --- a/src/Identity/test/Identity.Test/PasswordHasherTest.cs +++ b/src/Identity/test/Identity.Test/PasswordHasherTest.cs @@ -113,6 +113,7 @@ public void HashPassword_Version3() [InlineData("AQAAAAIAAAAyAAAAEOMwvh3+FZxqkdMBz2ekgGhwQ4A=")] // too short [InlineData("AQAAAAIAAAAyAAAAEOMwvh3+FZxqkdMBz2ekgGhwQ4B6pZWND6zgESBuWiHwAAAAAAAAAAAA")] // extra data at end [InlineData("AQAAAAIAAYagAP///wABAgMEBQYHCAkKCwwNDg/Q8A0WMKbtHQJQ2DHCdoEeeFBrgNlldq6vH4qX/CGqGQ==")] // salt length greater than data length + [InlineData("AQAAAAEAACcQf////4r8+J3NDEnMWKlHbhJQ6N5oooZ7hUi3cr/qAjd7Lc1Sv6GhorP7Ly0AzCv9PAmKww==")] // salt length is Int32.MaxValue [InlineData("AQAAAAIAAYagAAAACAABAgMEBQYH4qLSh7iNSI12qySxAkyR0XgpXpvNiwqhBJFNLbJKKFw=")] // salt length (8 bytes) less than minimum allowed public void VerifyHashedPassword_FailureCases(string hashedPassword) {