diff --git a/src/libraries/System.Security.Cryptography.Csp/ref/System.Security.Cryptography.Csp.cs b/src/libraries/System.Security.Cryptography.Csp/ref/System.Security.Cryptography.Csp.cs
index ce402e6d386bd8..a992ffcf0392fb 100644
--- a/src/libraries/System.Security.Cryptography.Csp/ref/System.Security.Cryptography.Csp.cs
+++ b/src/libraries/System.Security.Cryptography.Csp/ref/System.Security.Cryptography.Csp.cs
@@ -144,13 +144,17 @@ public partial class PasswordDeriveBytes : System.Security.Cryptography.DeriveBy
{
public PasswordDeriveBytes(byte[] password, byte[]? salt) { }
public PasswordDeriveBytes(byte[] password, byte[]? salt, System.Security.Cryptography.CspParameters? cspParams) { }
+ [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The hash implementation might be removed. Ensure the referenced hash algorithm is not trimmed.")]
public PasswordDeriveBytes(byte[] password, byte[]? salt, string hashName, int iterations) { }
+ [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The hash implementation might be removed. Ensure the referenced hash algorithm is not trimmed.")]
public PasswordDeriveBytes(byte[] password, byte[]? salt, string hashName, int iterations, System.Security.Cryptography.CspParameters? cspParams) { }
public PasswordDeriveBytes(string strPassword, byte[]? rgbSalt) { }
public PasswordDeriveBytes(string strPassword, byte[]? rgbSalt, System.Security.Cryptography.CspParameters? cspParams) { }
+ [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The hash implementation might be removed. Ensure the referenced hash algorithm is not trimmed.")]
public PasswordDeriveBytes(string strPassword, byte[]? rgbSalt, string strHashName, int iterations) { }
+ [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The hash implementation might be removed. Ensure the referenced hash algorithm is not trimmed.")]
public PasswordDeriveBytes(string strPassword, byte[]? rgbSalt, string strHashName, int iterations, System.Security.Cryptography.CspParameters? cspParams) { }
- public string HashName { get { throw null; } set { } }
+ public string HashName { get { throw null; } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The hash implementation might be removed. Ensure the referenced hash algorithm is not trimmed.")] set { } }
public int IterationCount { get { throw null; } set { } }
public byte[]? Salt { get { throw null; } set { } }
[System.Runtime.Versioning.SupportedOSPlatformAttribute("windows")]
diff --git a/src/libraries/System.Security.Cryptography.Csp/src/ILLink/ILLink.Suppressions.xml b/src/libraries/System.Security.Cryptography.Csp/src/ILLink/ILLink.Suppressions.xml
deleted file mode 100644
index 0129976fe94ba4..00000000000000
--- a/src/libraries/System.Security.Cryptography.Csp/src/ILLink/ILLink.Suppressions.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
- ILLink
- IL2026
- member
- M:System.Security.Cryptography.PasswordDeriveBytes.set_HashName(System.String)
-
-
-
\ No newline at end of file
diff --git a/src/libraries/System.Security.Cryptography.Csp/src/System/Security/Cryptography/PasswordDeriveBytes.cs b/src/libraries/System.Security.Cryptography.Csp/src/System/Security/Cryptography/PasswordDeriveBytes.cs
index ee79a76f05cdf9..10e52dcf33fbea 100644
--- a/src/libraries/System.Security.Cryptography.Csp/src/System/Security/Cryptography/PasswordDeriveBytes.cs
+++ b/src/libraries/System.Security.Cryptography.Csp/src/System/Security/Cryptography/PasswordDeriveBytes.cs
@@ -14,6 +14,8 @@ namespace System.Security.Cryptography
[EditorBrowsable(EditorBrowsableState.Never)]
public partial class PasswordDeriveBytes : DeriveBytes
{
+ private const string HashAlgorithmUnreferencedCodeMessage = "The hash implementation might be removed. Ensure the referenced hash algorithm is not trimmed.";
+
private int _extraCount;
private int _prefix;
private int _iterations;
@@ -30,22 +32,30 @@ public partial class PasswordDeriveBytes : DeriveBytes
public PasswordDeriveBytes(byte[] password, byte[]? salt) : this(password, salt, new CspParameters()) { }
+ [RequiresUnreferencedCode(HashAlgorithmUnreferencedCodeMessage)]
public PasswordDeriveBytes(string strPassword, byte[]? rgbSalt, string strHashName, int iterations) :
this(strPassword, rgbSalt, strHashName, iterations, new CspParameters()) { }
+ [RequiresUnreferencedCode(HashAlgorithmUnreferencedCodeMessage)]
public PasswordDeriveBytes(byte[] password, byte[]? salt, string hashName, int iterations) :
this(password, salt, hashName, iterations, new CspParameters()) { }
#pragma warning restore CA1416
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "The correct hash algorithm is being preserved by the DynamicDependency.")]
+ [DynamicDependency(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor, typeof(SHA1CryptoServiceProvider))]
public PasswordDeriveBytes(string strPassword, byte[]? rgbSalt, CspParameters? cspParams) :
this(strPassword, rgbSalt, "SHA1", 100, cspParams) { }
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "The correct hash algorithm is being preserved by the DynamicDependency.")]
+ [DynamicDependency(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor, typeof(SHA1CryptoServiceProvider))]
public PasswordDeriveBytes(byte[] password, byte[]? salt, CspParameters? cspParams) :
this(password, salt, "SHA1", 100, cspParams) { }
+ [RequiresUnreferencedCode(HashAlgorithmUnreferencedCodeMessage)]
public PasswordDeriveBytes(string strPassword, byte[]? rgbSalt, string strHashName, int iterations, CspParameters? cspParams) :
this((new UTF8Encoding(false)).GetBytes(strPassword), rgbSalt, strHashName, iterations, cspParams) { }
+ [RequiresUnreferencedCode(HashAlgorithmUnreferencedCodeMessage)]
public PasswordDeriveBytes(byte[] password, byte[]? salt, string hashName, int iterations, CspParameters? cspParams)
{
IterationCount = iterations;
@@ -58,6 +68,7 @@ public PasswordDeriveBytes(byte[] password, byte[]? salt, string hashName, int i
public string HashName
{
get { return _hashName!; }
+ [RequiresUnreferencedCode(HashAlgorithmUnreferencedCodeMessage)]
set
{
if (_baseValue != null)
diff --git a/src/libraries/System.Security.Cryptography.Csp/tests/TrimmingTests/PasswordDeriveBytesTest.cs b/src/libraries/System.Security.Cryptography.Csp/tests/TrimmingTests/PasswordDeriveBytesTest.cs
new file mode 100644
index 00000000000000..4fb327b499d53d
--- /dev/null
+++ b/src/libraries/System.Security.Cryptography.Csp/tests/TrimmingTests/PasswordDeriveBytesTest.cs
@@ -0,0 +1,43 @@
+using System;
+using System.Globalization;
+using System.Linq;
+using System.Security.Cryptography;
+
+///
+/// Tests that using PasswordDeriveBytes without specifying a hash algorithm name
+/// works correctly in a trimmed application.
+///
+class Program
+{
+ static int Main()
+ {
+ string testPassword = "PasswordGoesHere";
+ byte[] testSalt = new byte[] { 9, 5, 5, 5, 1, 2, 1, 2 };
+
+ byte[] expected = HexToByteArray("12F2497EC3EB78B0EA32AABFD8B9515FBC800BEEB6316A4DDF4EA62518341488A116DA3BBC26C685");
+
+ using (var deriveBytes = new PasswordDeriveBytes(testPassword, testSalt))
+ {
+ byte[] output = deriveBytes.GetBytes(expected.Length);
+ if (output.SequenceEqual(expected))
+ {
+ return 100;
+ }
+ }
+
+ return -1;
+ }
+
+ private static byte[] HexToByteArray(string hexString)
+ {
+ byte[] bytes = new byte[hexString.Length / 2];
+
+ for (int i = 0; i < hexString.Length; i += 2)
+ {
+ ReadOnlySpan s = hexString.AsSpan(i, 2);
+ bytes[i / 2] = byte.Parse(s, NumberStyles.HexNumber, null);
+ }
+
+ return bytes;
+ }
+}
diff --git a/src/libraries/System.Security.Cryptography.Csp/tests/TrimmingTests/System.Security.Cryptography.Csp.TrimmingTests.proj b/src/libraries/System.Security.Cryptography.Csp/tests/TrimmingTests/System.Security.Cryptography.Csp.TrimmingTests.proj
new file mode 100644
index 00000000000000..64b290af04e8bc
--- /dev/null
+++ b/src/libraries/System.Security.Cryptography.Csp/tests/TrimmingTests/System.Security.Cryptography.Csp.TrimmingTests.proj
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+