From f4d3143773c90fdfdc84fe557483780c86275aa6 Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Wed, 15 Apr 2026 13:42:41 -0700 Subject: [PATCH 01/21] Add OWASP-aligned PBKDF2 iteration guidance and password hashing context - CA5387/CA5388: Add tip noting the 100K analyzer threshold may not keep pace with hardware; link to OWASP Password Storage Cheat Sheet for current recommendations. - SYSLIB0041: Replace vague 'more secure values' with explicit guidance to consult OWASP and prefer Rfc2898DeriveBytes.Pbkdf2 one-shot API. - cryptography-model.md: Add tip about PBKDF2 best practices and mention of alternative algorithms (Argon2id, bcrypt, scrypt) via third-party libraries, linking to OWASP for current guidance. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/fundamentals/code-analysis/quality-rules/ca5387.md | 3 +++ docs/fundamentals/code-analysis/quality-rules/ca5388.md | 3 +++ docs/fundamentals/syslib-diagnostics/syslib0041.md | 5 ++++- docs/standard/security/cryptography-model.md | 3 +++ 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/fundamentals/code-analysis/quality-rules/ca5387.md b/docs/fundamentals/code-analysis/quality-rules/ca5387.md index 5637c9177094c..8fd5b8f05ea23 100644 --- a/docs/fundamentals/code-analysis/quality-rules/ca5387.md +++ b/docs/fundamentals/code-analysis/quality-rules/ca5387.md @@ -34,6 +34,9 @@ This rule is similar to [CA5388](ca5388.md), but analysis determines that the it Set the iteration count greater than or equal with 100,000 before calling . +> [!TIP] +> While the analyzer enforces a minimum of 100,000 iterations, this threshold might not keep pace with hardware improvements. Consult the [OWASP Password Storage Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html) for up-to-date recommendations. For password storage scenarios, use the highest iteration count your performance budget allows. Also consider using (the one-shot static method) with or higher. + ## When to suppress warnings It's safe to suppress a warning if you need to use a smaller iteration count for compatibility with existing data. diff --git a/docs/fundamentals/code-analysis/quality-rules/ca5388.md b/docs/fundamentals/code-analysis/quality-rules/ca5388.md index e05228ffd8854..0ae56db807ce5 100644 --- a/docs/fundamentals/code-analysis/quality-rules/ca5388.md +++ b/docs/fundamentals/code-analysis/quality-rules/ca5388.md @@ -34,6 +34,9 @@ This rule is similar to [CA5387](ca5387.md), but analysis can't determine if the Set the iteration count greater than or equal with 100k before calling explicitly. +> [!TIP] +> While the analyzer enforces a minimum of 100,000 iterations, this threshold might not keep pace with hardware improvements. Consult the [OWASP Password Storage Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html) for up-to-date recommendations. For password storage scenarios, use the highest iteration count your performance budget allows. Also consider using (the one-shot static method) with or higher. + ## When to suppress warnings It's safe to suppress warnings from this rule if: diff --git a/docs/fundamentals/syslib-diagnostics/syslib0041.md b/docs/fundamentals/syslib-diagnostics/syslib0041.md index e073b5317f094..a74c1a2d01540 100644 --- a/docs/fundamentals/syslib-diagnostics/syslib0041.md +++ b/docs/fundamentals/syslib-diagnostics/syslib0041.md @@ -21,7 +21,10 @@ The following constructor Use a different constructor overload where you can explicitly specify the iteration count (the default is 1000) and hash algorithm name (the default is ). -If you're using the default iteration count or default hash algorithm, consider moving to more secure values—that is, a larger iteration count or a newer hash algorithm. +If you're using the default iteration count or default hash algorithm, move to more secure values—that is, a much larger iteration count and a newer hash algorithm such as or higher. + +> [!IMPORTANT] +> Consult the [OWASP Password Storage Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html) for current recommended iteration counts, and use the highest value your performance budget allows. Prefer the one-shot static method as recommended by [SYSLIB0060](syslib0060.md). ## Suppress a warning diff --git a/docs/standard/security/cryptography-model.md b/docs/standard/security/cryptography-model.md index 69e5bdff94d5a..fbabe92801c42 100644 --- a/docs/standard/security/cryptography-model.md +++ b/docs/standard/security/cryptography-model.md @@ -83,6 +83,9 @@ Here is a list of recommended algorithms by application: - Generating a key from a password: - +> [!TIP] +> .NET's built-in password-based key derivation uses the PBKDF2 algorithm. When using PBKDF2, specify or higher, and use the highest iteration count your performance budget allows. Consult the [OWASP Password Storage Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html) for current iteration count recommendations and for guidance on alternative algorithms (such as Argon2id, bcrypt, or scrypt) that are available through third-party libraries. + ## See also - [Cryptographic Services](cryptographic-services.md) From 3e12992ee31858114df261ad5ca6744aa1c85728 Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Wed, 15 Apr 2026 13:44:59 -0700 Subject: [PATCH 02/21] Modernize AES encryption snippets and add CBC mode warnings - Replace hardcoded AES keys with aes.GenerateKey() in encrypt snippets and command-line key input in decrypt snippets (C# and VB). - Add [!IMPORTANT] callouts to encrypting-data.md and decrypting-data.md warning that AES-CBC (the default) lacks authentication and is vulnerable to padding oracle attacks; link to vulnerabilities-cbc-mode.md and recommend AesGcm or Encrypt-then-MAC patterns. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/standard/security/decrypting-data.md | 3 +++ docs/standard/security/encrypting-data.md | 8 ++++++-- .../decrypting-data/csharp/aes-decrypt.cs | 9 ++++----- .../decrypting-data/vb/aes-decrypt.vb | 7 ++++--- .../encrypting-data/csharp/aes-encrypt.cs | 14 ++++++++------ .../encrypting-data/vb/aes-encrypt.vb | 19 ++++++++----------- 6 files changed, 33 insertions(+), 27 deletions(-) diff --git a/docs/standard/security/decrypting-data.md b/docs/standard/security/decrypting-data.md index 8097ffb2a87b3..474aa0e072006 100644 --- a/docs/standard/security/decrypting-data.md +++ b/docs/standard/security/decrypting-data.md @@ -19,6 +19,9 @@ Decryption is the reverse operation of encryption. For secret-key encryption, yo ## Symmetric decryption +> [!IMPORTANT] +> Symmetric decryption with CBC mode (the default for `Aes.Create()`) is vulnerable to padding oracle attacks if the ciphertext integrity isn't verified before decryption. Always verify data integrity (for example, by using an HMAC) before attempting to decrypt, or use authenticated encryption such as . For more information, see [Timing vulnerabilities with CBC-mode symmetric decryption using padding](vulnerabilities-cbc-mode.md). + The decryption of data encrypted with symmetric algorithms is similar to the process used to encrypt data with symmetric algorithms. The class is used with symmetric cryptography classes provided by .NET to decrypt data read from any managed stream object. The following example illustrates how to create a new instance of the default implementation class for the algorithm. The instance is used to perform decryption on a object. This example first creates a new instance of the implementation class. It reads the initialization vector (IV) value from a managed stream variable, `fileStream`. Next it instantiates a object and initializes it to the value of the `fileStream` instance. The method from the instance is passed the IV value and the same key that was used for encryption. diff --git a/docs/standard/security/encrypting-data.md b/docs/standard/security/encrypting-data.md index ce3f1e37c5b6e..6ecff6c8aa9d1 100644 --- a/docs/standard/security/encrypting-data.md +++ b/docs/standard/security/encrypting-data.md @@ -19,6 +19,9 @@ Symmetric encryption and asymmetric encryption are performed using different pro ## Symmetric encryption +> [!IMPORTANT] +> The `Aes.Create()` method defaults to CBC mode without built-in authentication. CBC mode without integrity verification is vulnerable to padding oracle attacks. For production scenarios, use authenticated encryption such as where available, or apply an Encrypt-then-MAC pattern using . For more information, see [Timing vulnerabilities with CBC-mode symmetric decryption using padding](vulnerabilities-cbc-mode.md). + The managed symmetric cryptography classes are used with a special stream class called a that encrypts data read into the stream. The **CryptoStream** class is initialized with a managed stream class, a class that implements the interface (created from a class that implements a cryptographic algorithm), and a enumeration that describes the type of access permitted to the **CryptoStream**. The **CryptoStream** class can be initialized using any class that derives from the class, including , , and . Using these classes, you can perform symmetric encryption on a variety of stream objects. The following example illustrates how to create a new instance of the default implementation class for the algorithm. The instance is used to perform encryption on a **CryptoStream** class. In this example, the **CryptoStream** is initialized with a stream object called `fileStream` that can be any type of managed stream. The **CreateEncryptor** method from the **Aes** class is passed the key and IV that are used for encryption. In this case, the default key and IV generated from `aes` are used. @@ -42,13 +45,14 @@ The following example shows the entire process of creating a stream, encrypting :::code language="csharp" source="snippets/encrypting-data/csharp/aes-encrypt.cs"::: :::code language="vb" source="snippets/encrypting-data/vb/aes-encrypt.vb"::: -The code encrypts the stream using the AES symmetric algorithm, and writes IV and then encrypted "Hello World!" to the stream. If the code is successful, it creates an encrypted file named *TestData.txt* and displays the following text to the console: +The code encrypts the stream using the AES symmetric algorithm, and writes IV and then encrypted "Hello World!" to the stream. If the code is successful, it creates an encrypted file named *TestData.txt* and displays the key in hexadecimal: ```console The file was encrypted. +Key (hex): 1A2B3C... ``` -You can decrypt the file by using the symmetric decryption example in [Decrypting Data](decrypting-data.md). That example and this example specify the same key. +You can decrypt the file by using the symmetric decryption example in [Decrypting Data](decrypting-data.md), passing the hex key as a command-line argument. However, if an exception is raised, the code displays the following text to the console: diff --git a/docs/standard/security/snippets/decrypting-data/csharp/aes-decrypt.cs b/docs/standard/security/snippets/decrypting-data/csharp/aes-decrypt.cs index 3223c39267d73..014eafffc3dce 100644 --- a/docs/standard/security/snippets/decrypting-data/csharp/aes-decrypt.cs +++ b/docs/standard/security/snippets/decrypting-data/csharp/aes-decrypt.cs @@ -18,11 +18,10 @@ numBytesToRead -= n; } - byte[] key = - { - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 - }; + // The key must match the key used during encryption. + // In production, retrieve the key from a secure key management + // system rather than hardcoding it in source code. + byte[] key = Convert.FromHexString(args[0]); using (CryptoStream cryptoStream = new( fileStream, diff --git a/docs/standard/security/snippets/decrypting-data/vb/aes-decrypt.vb b/docs/standard/security/snippets/decrypting-data/vb/aes-decrypt.vb index 1634e13334237..08183c81ffc37 100644 --- a/docs/standard/security/snippets/decrypting-data/vb/aes-decrypt.vb +++ b/docs/standard/security/snippets/decrypting-data/vb/aes-decrypt.vb @@ -4,9 +4,10 @@ Imports System.Security.Cryptography Module Module1 Sub Main() - ' Decryption key must be the same value that was used - ' to encrypt the stream. - Dim key As Byte() = {&H1, &H2, &H3, &H4, &H5, &H6, &H7, &H8, &H9, &H10, &H11, &H12, &H13, &H14, &H15, &H16} + ' The key must match the key used during encryption. + ' In production, retrieve the key from a secure key management + ' system rather than hardcoding it in source code. + Dim key As Byte() = Convert.FromHexString(Environment.GetCommandLineArgs()(1)) Try ' Create a file stream. diff --git a/docs/standard/security/snippets/encrypting-data/csharp/aes-encrypt.cs b/docs/standard/security/snippets/encrypting-data/csharp/aes-encrypt.cs index 66e3199dec9d5..6f64ecbcefccf 100644 --- a/docs/standard/security/snippets/encrypting-data/csharp/aes-encrypt.cs +++ b/docs/standard/security/snippets/encrypting-data/csharp/aes-encrypt.cs @@ -2,16 +2,17 @@ try { + string keyHex; + using (FileStream fileStream = new("TestData.txt", FileMode.OpenOrCreate)) { using (Aes aes = Aes.Create()) { - byte[] key = - { - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 - }; - aes.Key = key; + // Generate a cryptographically secure random key. + // In production, use a key management system or derive from a + // password using Rfc2898DeriveBytes.Pbkdf2 with a high iteration count. + aes.GenerateKey(); + keyHex = Convert.ToHexString(aes.Key); byte[] iv = aes.IV; fileStream.Write(iv, 0, iv.Length); @@ -33,6 +34,7 @@ } Console.WriteLine("The file was encrypted."); + Console.WriteLine($"Key (hex): {keyHex}"); } catch (Exception ex) { diff --git a/docs/standard/security/snippets/encrypting-data/vb/aes-encrypt.vb b/docs/standard/security/snippets/encrypting-data/vb/aes-encrypt.vb index 50ab081abdba7..2c351ae10e626 100644 --- a/docs/standard/security/snippets/encrypting-data/vb/aes-encrypt.vb +++ b/docs/standard/security/snippets/encrypting-data/vb/aes-encrypt.vb @@ -5,20 +5,19 @@ Imports System.Security.Cryptography Module Module1 Sub Main() Try + Dim keyHex As String + ' Create a file stream Using fileStream As New FileStream("TestData.txt", FileMode.OpenOrCreate) ' Create a new instance of the default Aes implementation class ' and configure encryption key. Using aes As Aes = Aes.Create() - 'Encryption key used to encrypt the stream. - 'The same value must be used to encrypt and decrypt the stream. - Dim key As Byte() = { - &H1, &H2, &H3, &H4, &H5, &H6, &H7, &H8, - &H9, &H10, &H11, &H12, &H13, &H14, &H15, &H16 - } - - aes.Key = key + ' Generate a cryptographically secure random key. + ' In production, use a key management system or derive from a + ' password using Rfc2898DeriveBytes.Pbkdf2 with a high iteration count. + aes.GenerateKey() + keyHex = Convert.ToHexString(aes.Key) ' Stores IV at the beginning of the file. ' This information will be used for decryption. @@ -41,11 +40,9 @@ Module Module1 End Using End Using - 'Inform the user that the message was written - 'to the stream. Console.WriteLine("The text was encrypted.") + Console.WriteLine($"Key (hex): {keyHex}") Catch - 'Inform the user that an exception was raised. Console.WriteLine("The encryption failed.") Throw End Try From 457c5df2963f5af3cf098617e35c163d017cb604 Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Wed, 15 Apr 2026 13:46:01 -0700 Subject: [PATCH 03/21] Replace 1024-bit RSA and PKCS#1 v1.5 with 2048-bit RSA and OAEP - encrypting-data.md: Replace inline 1024-bit RSA modulus and PKCS#1 v1.5 padding with RSA.Create(2048) and RSAEncryptionPadding.OaepSHA256. Add [!IMPORTANT] callout explaining why OAEP is preferred over PKCS#1 v1.5. - decrypting-data.md: Update asymmetric decryption example to use RSA.Create(2048) and RSAEncryptionPadding.OaepSHA256. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/standard/security/decrypting-data.md | 18 +++--- docs/standard/security/encrypting-data.md | 77 +++++------------------ 2 files changed, 25 insertions(+), 70 deletions(-) diff --git a/docs/standard/security/decrypting-data.md b/docs/standard/security/decrypting-data.md index 474aa0e072006..96a83802cd43b 100644 --- a/docs/standard/security/decrypting-data.md +++ b/docs/standard/security/decrypting-data.md @@ -55,26 +55,26 @@ The following example illustrates the decryption of two arrays of bytes that rep ```vb 'Create a new instance of the RSA class. -Dim rsa As RSA = RSA.Create() +Dim rsa As RSA = RSA.Create(2048) ' Export the public key information and send it to a third party. ' Wait for the third party to encrypt some data and send it back. -'Decrypt the symmetric key and IV. -symmetricKey = rsa.Decrypt(encryptedSymmetricKey, RSAEncryptionPadding.Pkcs1) -symmetricIV = rsa.Decrypt(encryptedSymmetricIV, RSAEncryptionPadding.Pkcs1) +'Decrypt the symmetric key and IV using OAEP padding. +symmetricKey = rsa.Decrypt(encryptedSymmetricKey, RSAEncryptionPadding.OaepSHA256) +symmetricIV = rsa.Decrypt(encryptedSymmetricIV, RSAEncryptionPadding.OaepSHA256) ``` ```csharp -//Create a new instance of the RSA class. -RSA rsa = RSA.Create(); +// Create a new instance of the RSA class with at least 2048-bit key size. +RSA rsa = RSA.Create(2048); // Export the public key information and send it to a third party. // Wait for the third party to encrypt some data and send it back. -//Decrypt the symmetric key and IV. -symmetricKey = rsa.Decrypt(encryptedSymmetricKey, RSAEncryptionPadding.Pkcs1); -symmetricIV = rsa.Decrypt(encryptedSymmetricIV , RSAEncryptionPadding.Pkcs1); +// Decrypt the symmetric key and IV using OAEP padding. +symmetricKey = rsa.Decrypt(encryptedSymmetricKey, RSAEncryptionPadding.OaepSHA256); +symmetricIV = rsa.Decrypt(encryptedSymmetricIV, RSAEncryptionPadding.OaepSHA256); ``` ## See also diff --git a/docs/standard/security/encrypting-data.md b/docs/standard/security/encrypting-data.md index 6ecff6c8aa9d1..2b97fd711a0cd 100644 --- a/docs/standard/security/encrypting-data.md +++ b/docs/standard/security/encrypting-data.md @@ -64,7 +64,10 @@ The encryption failed. Asymmetric algorithms are usually used to encrypt small amounts of data such as the encryption of a symmetric key and IV. Typically, an individual performing asymmetric encryption uses the public key generated by another party. The class is provided by .NET for this purpose. -The following example uses public key information to encrypt a symmetric key and IV. Two byte arrays are initialized that represents the public key of a third party. An object is initialized to these values. Next, the **RSAParameters** object (along with the public key it represents) is imported into an **RSA** instance using the method. Finally, the private key and IV created by an class are encrypted. This example requires systems to have 128-bit encryption installed. +The following example uses public key information to encrypt a symmetric key and IV. An key pair is generated with a minimum key size of 2048 bits. The public key from one party is used to encrypt the symmetric key and IV generated by an instance, using OAEP padding with SHA-256 for security. + +> [!IMPORTANT] +> Use (or higher) instead of . PKCS#1 v1.5 padding is vulnerable to Bleichenbacher-style attacks. Additionally, use RSA key sizes of at least 2048 bits. ```vb Imports System @@ -73,34 +76,15 @@ Imports System.Security.Cryptography Module Module1 Sub Main() - 'Initialize the byte arrays to the public key information. - Dim modulus As Byte() = {214, 46, 220, 83, 160, 73, 40, 39, 201, 155, 19, 202, 3, 11, 191, 178, 56, 74, 90, 36, 248, 103, 18, 144, 170, 163, 145, 87, 54, 61, 34, 220, 222, 207, 137, 149, 173, 14, 92, 120, 206, 222, 158, 28, 40, 24, 30, 16, 175, 108, 128, 35, 230, 118, 40, 121, 113, 125, 216, 130, 11, 24, 90, 48, 194, 240, 105, 44, 76, 34, 57, 249, 228, 125, 80, 38, 9, 136, 29, 117, 207, 139, 168, 181, 85, 137, 126, 10, 126, 242, 120, 247, 121, 8, 100, 12, 201, 171, 38, 226, 193, 180, 190, 117, 177, 87, 143, 242, 213, 11, 44, 180, 113, 93, 106, 99, 179, 68, 175, 211, 164, 116, 64, 148, 226, 254, 172, 147} - - Dim exponent As Byte() = {1, 0, 1} - - 'Create values to store encrypted symmetric keys. - Dim encryptedSymmetricKey() As Byte - Dim encryptedSymmetricIV() As Byte - - 'Create a new instance of the default RSA implementation class. - Dim rsa As RSA = RSA.Create() - - 'Create a new instance of the RSAParameters structure. - Dim rsaKeyInfo As New RSAParameters() - - 'Set rsaKeyInfo to the public key values. - rsaKeyInfo.Modulus = modulus - rsaKeyInfo.Exponent = exponent - - 'Import key parameters into rsa - rsa.ImportParameters(rsaKeyInfo) + 'Create a new RSA key pair with at least 2048-bit key size. + Dim rsa As RSA = RSA.Create(2048) 'Create a new instance of the default Aes implementation class. Dim aes As Aes = Aes.Create() - 'Encrypt the symmetric key and IV. - encryptedSymmetricKey = rsa.Encrypt(aes.Key, RSAEncryptionPadding.Pkcs1) - encryptedSymmetricIV = rsa.Encrypt(aes.IV, RSAEncryptionPadding.Pkcs1) + 'Encrypt the symmetric key and IV using OAEP padding. + Dim encryptedSymmetricKey As Byte() = rsa.Encrypt(aes.Key, RSAEncryptionPadding.OaepSHA256) + Dim encryptedSymmetricIV As Byte() = rsa.Encrypt(aes.IV, RSAEncryptionPadding.OaepSHA256) End Sub End Module @@ -114,44 +98,15 @@ class Class1 { static void Main() { - //Initialize the byte arrays to the public key information. - byte[] modulus = - { - 214,46,220,83,160,73,40,39,201,155,19,202,3,11,191,178,56, - 74,90,36,248,103,18,144,170,163,145,87,54,61,34,220,222, - 207,137,149,173,14,92,120,206,222,158,28,40,24,30,16,175, - 108,128,35,230,118,40,121,113,125,216,130,11,24,90,48,194, - 240,105,44,76,34,57,249,228,125,80,38,9,136,29,117,207,139, - 168,181,85,137,126,10,126,242,120,247,121,8,100,12,201,171, - 38,226,193,180,190,117,177,87,143,242,213,11,44,180,113,93, - 106,99,179,68,175,211,164,116,64,148,226,254,172,147 - }; - - byte[] exponent = { 1, 0, 1 }; - - //Create values to store encrypted symmetric keys. - byte[] encryptedSymmetricKey; - byte[] encryptedSymmetricIV; - - //Create a new instance of the RSA class. - RSA rsa = RSA.Create(); - - //Create a new instance of the RSAParameters structure. - RSAParameters rsaKeyInfo = new RSAParameters(); - - //Set rsaKeyInfo to the public key values. - rsaKeyInfo.Modulus = modulus; - rsaKeyInfo.Exponent = exponent; - - //Import key parameters into rsa. - rsa.ImportParameters(rsaKeyInfo); - - //Create a new instance of the default Aes implementation class. + // Create a new RSA key pair with at least 2048-bit key size. + RSA rsa = RSA.Create(2048); + + // Create a new instance of the default Aes implementation class. Aes aes = Aes.Create(); - //Encrypt the symmetric key and IV. - encryptedSymmetricKey = rsa.Encrypt(aes.Key, RSAEncryptionPadding.Pkcs1); - encryptedSymmetricIV = rsa.Encrypt(aes.IV, RSAEncryptionPadding.Pkcs1); + // Encrypt the symmetric key and IV using OAEP padding. + byte[] encryptedSymmetricKey = rsa.Encrypt(aes.Key, RSAEncryptionPadding.OaepSHA256); + byte[] encryptedSymmetricIV = rsa.Encrypt(aes.IV, RSAEncryptionPadding.OaepSHA256); } } ``` From b70d56b43fbdbdca482c44b0315c300e69756b9e Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Wed, 15 Apr 2026 13:47:32 -0700 Subject: [PATCH 04/21] Add deprecation warnings for legacy crypto algorithms and APIs - walkthrough-encrypting-and-decrypting-strings.md: Add [!WARNING] banner that TripleDES is weak; recommend AES with AesGcm. Replace outdated [!IMPORTANT] that endorsed 3DES/Rijndael over DES. - cryptographic-services.md: Add [!WARNING] callouts for DES/3DES deprecation and ECB mode insecurity. Add warning against MD5/SHA-1 for security-sensitive use. - how-to-access-hardware-encryption-devices.md: Add [!WARNING] noting legacy RSACryptoServiceProvider, RNGCryptoServiceProvider, and SHA-1 usage; recommend modern APIs. - how-to-encrypt-xml-elements-with-symmetric-keys.md: Add [!NOTE] about XML Encryption 1.0 CBC mode limitation; recommend Encrypt-then-Sign and link to vulnerabilities-cbc-mode.md. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/standard/security/cryptographic-services.md | 9 +++++++++ .../how-to-access-hardware-encryption-devices.md | 3 +++ .../how-to-encrypt-xml-elements-with-symmetric-keys.md | 3 +++ .../walkthrough-encrypting-and-decrypting-strings.md | 5 ++++- 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/docs/standard/security/cryptographic-services.md b/docs/standard/security/cryptographic-services.md index f0b4a955fa7c9..bc1f3a4b64551 100644 --- a/docs/standard/security/cryptographic-services.md +++ b/docs/standard/security/cryptographic-services.md @@ -67,8 +67,14 @@ Secret-key encryption is also referred to as symmetric encryption because the sa A type of secret-key algorithm called a block cipher is used to encrypt one block of data at a time. Block ciphers such as Data Encryption Standard (DES), TripleDES, and Advanced Encryption Standard (AES) cryptographically transform an input block of *n* bytes into an output block of encrypted bytes. If you want to encrypt or decrypt a sequence of bytes, you have to do it block by block. Because *n* is small (8 bytes for DES and TripleDES; 16 bytes [the default], 24 bytes, or 32 bytes for AES), data values that are larger than *n* have to be encrypted one block at a time. Data values that are smaller than *n* have to be expanded to *n* in order to be processed. +> [!WARNING] +> DES and TripleDES (3DES) are deprecated and should not be used for new development. Use instead, ideally with an authenticated encryption mode such as GCM (). + One simple form of block cipher is called the electronic codebook (ECB) mode. ECB mode is not considered secure, because it does not use an initialization vector to initialize the first plaintext block. For a given secret key *k*, a simple block cipher that does not use an initialization vector will encrypt the same input block of plaintext into the same output block of ciphertext. Therefore, if you have duplicate blocks in your input plaintext stream, you will have duplicate blocks in your output ciphertext stream. These duplicate output blocks alert unauthorized users to the weak encryption used the algorithms that might have been employed, and the possible modes of attack. The ECB cipher mode is therefore quite vulnerable to analysis, and ultimately, key discovery. +> [!WARNING] +> ECB mode must not be used for encryption. Use CBC mode with integrity verification, or preferably an authenticated mode such as GCM or CCM. + The block cipher classes that are provided in the base class library use a default chaining mode called cipher-block chaining (CBC), although you can change this default if you want. CBC ciphers overcome the problems associated with ECB ciphers by using an initialization vector (IV) to encrypt the first block of plaintext. Each subsequent block of plaintext undergoes a bitwise exclusive OR (`XOR`) operation with the previous ciphertext block before it is encrypted. Each ciphertext block is therefore dependent on all previous blocks. When this system is used, common message headers that might be known to an unauthorized user cannot be used to reverse-engineer a key. @@ -172,6 +178,9 @@ None of the previous methods will prevent someone from reading Alice's messages, .NET also provides and . But the MD5 and SHA-1 algorithms have been found to be insecure, and SHA-2 is now recommended instead. SHA-2 includes SHA256, SHA384, and SHA512. +> [!WARNING] +> Do not use MD5 or SHA-1 for any security-sensitive purpose, including data integrity, digital signatures, or certificate validation. Use SHA-256 or higher from the SHA-2 family. + ## Random Number Generation Random number generation is integral to many cryptographic operations. For example, cryptographic keys need to be as random as possible so that it is infeasible to reproduce them. Cryptographic random number generators must generate output that is computationally infeasible to predict with a probability that is better than one half. Therefore, any method of predicting the next output bit must not perform better than random guessing. The classes in .NET use random number generators to generate cryptographic keys. diff --git a/docs/standard/security/how-to-access-hardware-encryption-devices.md b/docs/standard/security/how-to-access-hardware-encryption-devices.md index f44ae4c55c1ab..3e8628f4c338f 100644 --- a/docs/standard/security/how-to-access-hardware-encryption-devices.md +++ b/docs/standard/security/how-to-access-hardware-encryption-devices.md @@ -17,6 +17,9 @@ helpviewer_keywords: > [!NOTE] > This article applies to Windows. +> [!WARNING] +> This article uses legacy APIs ( and ) that are obsolete in .NET 6 and later. For new code, use and instead. The code sample also uses SHA-1 for signing, which is insecure—use SHA-256 or higher. + You can use the class to access hardware encryption devices. For example, you can use this class to integrate your application with a smart card, a hardware random number generator, or a hardware implementation of a particular cryptographic algorithm. The class creates a cryptographic service provider (CSP) that accesses a properly installed hardware encryption device. You can verify the availability of a CSP by inspecting the following registry key using the Registry Editor (Regedit.exe): HKEY_LOCAL_MACHINE\Software\Microsoft\Cryptography\Defaults\Provider. diff --git a/docs/standard/security/how-to-encrypt-xml-elements-with-symmetric-keys.md b/docs/standard/security/how-to-encrypt-xml-elements-with-symmetric-keys.md index ab9da75ee4c3b..e002d55265d71 100644 --- a/docs/standard/security/how-to-encrypt-xml-elements-with-symmetric-keys.md +++ b/docs/standard/security/how-to-encrypt-xml-elements-with-symmetric-keys.md @@ -20,6 +20,9 @@ ms.assetid: d8461a44-aa2c-4ef4-b3e4-ab7cbaaee1b5 You can use the classes in the namespace to encrypt an element within an XML document. XML Encryption allows you to store or transport sensitive XML, without worrying about the data being easily read. This procedure encrypts an XML element using the Advanced Encryption Standard (AES) algorithm. +> [!NOTE] +> The XML Encryption 1.0 standard uses CBC mode by default, which doesn't provide authentication. For scenarios that require strong integrity guarantees, consider using an Encrypt-then-Sign approach or using XML Encryption 1.1 with AES-GCM where supported. For more information, see [Timing vulnerabilities with CBC-mode symmetric decryption using padding](vulnerabilities-cbc-mode.md). + For information about how to decrypt an XML element that was encrypted using this procedure, see [How to: Decrypt XML Elements with Symmetric Keys](how-to-decrypt-xml-elements-with-symmetric-keys.md). When you use a symmetric algorithm like AES to encrypt XML data, you must use the same key to encrypt and decrypt the XML data. The example in this procedure assumes that the encrypted XML will be decrypted using the same key, and that the encrypting and decrypting parties agree on the algorithm and key to use. This example does not store or encrypt the AES key within the encrypted XML. diff --git a/docs/visual-basic/programming-guide/language-features/strings/walkthrough-encrypting-and-decrypting-strings.md b/docs/visual-basic/programming-guide/language-features/strings/walkthrough-encrypting-and-decrypting-strings.md index ff39a40dfee8b..fd802eac091b0 100644 --- a/docs/visual-basic/programming-guide/language-features/strings/walkthrough-encrypting-and-decrypting-strings.md +++ b/docs/visual-basic/programming-guide/language-features/strings/walkthrough-encrypting-and-decrypting-strings.md @@ -11,6 +11,9 @@ ms.assetid: 1f51e40a-2f88-43e2-a83e-28a0b5c0d6fd --- # Walkthrough: Encrypting and Decrypting Strings in Visual Basic +> [!WARNING] +> The TripleDES (3DES) algorithm demonstrated in this walkthrough is considered weak by modern standards and should not be used for new development. Use with authenticated encryption (such as ) instead. For current guidance, see [.NET cryptography model](../../../../standard/security/cryptography-model.md) and the [OWASP Cryptographic Storage Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html). + This walkthrough shows you how to use the class to encrypt and decrypt strings using the Triple Data Encryption Standard (3DES) algorithm. The first step is to create a simple wrapper class that encapsulates the 3DES algorithm and stores the encrypted data as a base-64 encoded string. Then, that wrapper is used to securely store private user data in a publicly accessible text file. You can use encryption to protect user secrets (for example, passwords) and to make credentials unreadable by unauthorized users. This can protect an authorized user's identity from being stolen, which protects the user's assets and provides non-repudiation. Encryption can also protect a user's data from being accessed by unauthorized users. @@ -18,7 +21,7 @@ This walkthrough shows you how to use the [!IMPORTANT] -> The Rijndael (now referred to as Advanced Encryption Standard [AES]) and Triple Data Encryption Standard (3DES) algorithms provide greater security than DES because they are more computationally intensive. For more information, see and . +> The Triple Data Encryption Standard (3DES) and DES algorithms are deprecated. Use the Advanced Encryption Standard (AES) for new encryption scenarios. For more information, see . ### To create the encryption wrapper From 62c2f8e0948fbde0b1cf46730c713721c8d5ccf9 Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Wed, 15 Apr 2026 14:02:53 -0700 Subject: [PATCH 05/21] Fix correctness bugs in crypto code samples - CryptoWalkThru DecryptFile: Read 4 bytes (not 3) for each 4-byte length field to match what EncryptFile writes. - Cryptographic signatures: Align C# and VB samples to both use Encoding.UTF8 (was ASCII in C#) and ExportParameters(false) (was True in VB, leaking private key unnecessarily). Also fix matching inline code in cryptographic-signatures.md. - DPAPI sample (C# and VB): Replace misleading UnicodeEncoding.ASCII with Encoding.ASCII throughout. Replace obsolete RNGCryptoServiceProvider with RandomNumberGenerator.Fill. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../security/cryptographic-signatures.md | 4 ++-- .../csharp/Program.cs | 2 +- .../cryptographic-signatures/vb/Program.vb | 2 +- .../CryptoWalkThru/cs/Form1.cs | 4 ++-- .../VS_Snippets_CLR/DPAPI-HowTO/cs/sample.cs | 17 ++++++++--------- .../VS_Snippets_CLR/DPAPI-HowTO/vb/sample.vb | 19 ++++++++----------- 6 files changed, 22 insertions(+), 26 deletions(-) diff --git a/docs/standard/security/cryptographic-signatures.md b/docs/standard/security/cryptographic-signatures.md index f04882f7d9584..6a47d8bc080a1 100644 --- a/docs/standard/security/cryptographic-signatures.md +++ b/docs/standard/security/cryptographic-signatures.md @@ -49,7 +49,7 @@ Module Program ' Generate signature Using rsa As RSA = RSA.Create() - sharedParameters = rsa.ExportParameters(True) + sharedParameters = rsa.ExportParameters(False) Dim rsaFormatter As New RSAPKCS1SignatureFormatter(rsa) rsaFormatter.SetHashAlgorithm(NameOf(SHA256)) @@ -67,7 +67,7 @@ using System.Text; using SHA256 alg = SHA256.Create(); -byte[] data = Encoding.ASCII.GetBytes("Hello, from the .NET Docs!"); +byte[] data = Encoding.UTF8.GetBytes("Hello, from the .NET Docs!"); byte[] hash = alg.ComputeHash(data); RSAParameters sharedParameters; diff --git a/docs/standard/security/snippets/cryptographic-signatures/csharp/Program.cs b/docs/standard/security/snippets/cryptographic-signatures/csharp/Program.cs index 1cb8ec594af59..f0fd583608172 100644 --- a/docs/standard/security/snippets/cryptographic-signatures/csharp/Program.cs +++ b/docs/standard/security/snippets/cryptographic-signatures/csharp/Program.cs @@ -3,7 +3,7 @@ using SHA256 alg = SHA256.Create(); -byte[] data = Encoding.ASCII.GetBytes("Hello, from the .NET Docs!"); +byte[] data = Encoding.UTF8.GetBytes("Hello, from the .NET Docs!"); byte[] hash = alg.ComputeHash(data); RSAParameters sharedParameters; diff --git a/docs/standard/security/snippets/cryptographic-signatures/vb/Program.vb b/docs/standard/security/snippets/cryptographic-signatures/vb/Program.vb index 717b393e287c6..825d316c851bf 100644 --- a/docs/standard/security/snippets/cryptographic-signatures/vb/Program.vb +++ b/docs/standard/security/snippets/cryptographic-signatures/vb/Program.vb @@ -14,7 +14,7 @@ Module Program ' Generate signature Using rsa As RSA = RSA.Create() - sharedParameters = rsa.ExportParameters(True) + sharedParameters = rsa.ExportParameters(False) Dim rsaFormatter As New RSAPKCS1SignatureFormatter(rsa) rsaFormatter.SetHashAlgorithm(NameOf(SHA256)) diff --git a/samples/snippets/csharp/VS_Snippets_CLR/CryptoWalkThru/cs/Form1.cs b/samples/snippets/csharp/VS_Snippets_CLR/CryptoWalkThru/cs/Form1.cs index ac287caa88f3c..6e0a851b38c7c 100644 --- a/samples/snippets/csharp/VS_Snippets_CLR/CryptoWalkThru/cs/Form1.cs +++ b/samples/snippets/csharp/VS_Snippets_CLR/CryptoWalkThru/cs/Form1.cs @@ -206,9 +206,9 @@ private void DecryptFile(FileInfo file) using (var inFs = new FileStream(file.FullName, FileMode.Open)) { inFs.Seek(0, SeekOrigin.Begin); - inFs.Read(LenK, 0, 3); + inFs.Read(LenK, 0, 4); inFs.Seek(4, SeekOrigin.Begin); - inFs.Read(LenIV, 0, 3); + inFs.Read(LenIV, 0, 4); // Convert the lengths to integer values. int lenK = BitConverter.ToInt32(LenK, 0); diff --git a/samples/snippets/csharp/VS_Snippets_CLR/DPAPI-HowTO/cs/sample.cs b/samples/snippets/csharp/VS_Snippets_CLR/DPAPI-HowTO/cs/sample.cs index 335f0103d116a..4817a38ad5e06 100644 --- a/samples/snippets/csharp/VS_Snippets_CLR/DPAPI-HowTO/cs/sample.cs +++ b/samples/snippets/csharp/VS_Snippets_CLR/DPAPI-HowTO/cs/sample.cs @@ -19,21 +19,21 @@ public static void Run() /////////////////////////////// // Create the original data to be encrypted (The data length should be a multiple of 16). - byte[] toEncrypt = UnicodeEncoding.ASCII.GetBytes("ThisIsSomeData16"); + byte[] toEncrypt = Encoding.ASCII.GetBytes("ThisIsSomeData16"); - Console.WriteLine($"Original data: {UnicodeEncoding.ASCII.GetString(toEncrypt)}"); + Console.WriteLine($"Original data: {Encoding.ASCII.GetString(toEncrypt)}"); Console.WriteLine("Encrypting..."); // Encrypt the data in memory. EncryptInMemoryData(toEncrypt, MemoryProtectionScope.SameLogon); - Console.WriteLine($"Encrypted data: {UnicodeEncoding.ASCII.GetString(toEncrypt)}"); + Console.WriteLine($"Encrypted data: {Encoding.ASCII.GetString(toEncrypt)}"); Console.WriteLine("Decrypting..."); // Decrypt the data in memory. DecryptInMemoryData(toEncrypt, MemoryProtectionScope.SameLogon); - Console.WriteLine($"Decrypted data: {UnicodeEncoding.ASCII.GetString(toEncrypt)}"); + Console.WriteLine($"Decrypted data: {Encoding.ASCII.GetString(toEncrypt)}"); /////////////////////////////// // @@ -42,7 +42,7 @@ public static void Run() /////////////////////////////// // Create the original data to be encrypted - toEncrypt = UnicodeEncoding.ASCII.GetBytes("This is some data of any length."); + toEncrypt = Encoding.ASCII.GetBytes("This is some data of any length."); // Create a file. FileStream fStream = new FileStream("Data.dat", FileMode.OpenOrCreate); @@ -51,7 +51,7 @@ public static void Run() byte[] entropy = CreateRandomEntropy(); Console.WriteLine(); - Console.WriteLine($"Original data: {UnicodeEncoding.ASCII.GetString(toEncrypt)}"); + Console.WriteLine($"Original data: {Encoding.ASCII.GetString(toEncrypt)}"); Console.WriteLine("Encrypting and writing to disk..."); // Encrypt a copy of the data to the stream. @@ -69,7 +69,7 @@ public static void Run() fStream.Close(); - Console.WriteLine($"Decrypted data: {UnicodeEncoding.ASCII.GetString(decryptData)}"); + Console.WriteLine($"Decrypted data: {Encoding.ASCII.GetString(decryptData)}"); } catch (Exception e) { @@ -104,9 +104,8 @@ public static byte[] CreateRandomEntropy() // Create a byte array to hold the random value. byte[] entropy = new byte[16]; - // Create a new instance of the RNGCryptoServiceProvider. // Fill the array with a random value. - new RNGCryptoServiceProvider().GetBytes(entropy); + RandomNumberGenerator.Fill(entropy); // Return the array. return entropy; diff --git a/samples/snippets/visualbasic/VS_Snippets_CLR/DPAPI-HowTO/vb/sample.vb b/samples/snippets/visualbasic/VS_Snippets_CLR/DPAPI-HowTO/vb/sample.vb index 1b2ea95b3e31c..6f4dfb7e8ccb2 100644 --- a/samples/snippets/visualbasic/VS_Snippets_CLR/DPAPI-HowTO/vb/sample.vb +++ b/samples/snippets/visualbasic/VS_Snippets_CLR/DPAPI-HowTO/vb/sample.vb @@ -22,21 +22,21 @@ Public Module MemoryProtectionSample ' '''''''''''''''''''''''''''''''''''' ' Create the original data to be encrypted (The data length should be a multiple of 16). - Dim toEncrypt As Byte() = UnicodeEncoding.ASCII.GetBytes("ThisIsSomeData16") + Dim toEncrypt As Byte() = Encoding.ASCII.GetBytes("ThisIsSomeData16") - Console.WriteLine("Original data: " + UnicodeEncoding.ASCII.GetString(toEncrypt)) + Console.WriteLine("Original data: " + Encoding.ASCII.GetString(toEncrypt)) Console.WriteLine("Encrypting...") ' Encrypt the data in memory. EncryptInMemoryData(toEncrypt, MemoryProtectionScope.SameLogon) - Console.WriteLine("Encrypted data: " + UnicodeEncoding.ASCII.GetString(toEncrypt)) + Console.WriteLine("Encrypted data: " + Encoding.ASCII.GetString(toEncrypt)) Console.WriteLine("Decrypting...") ' Decrypt the data in memory. DecryptInMemoryData(toEncrypt, MemoryProtectionScope.SameLogon) - Console.WriteLine("Decrypted data: " + UnicodeEncoding.ASCII.GetString(toEncrypt)) + Console.WriteLine("Decrypted data: " + Encoding.ASCII.GetString(toEncrypt)) '''''''''''''''''''''''''''''''''''' @@ -45,7 +45,7 @@ Public Module MemoryProtectionSample ' '''''''''''''''''''''''''''''''''''' ' Create the original data to be encrypted - toEncrypt = UnicodeEncoding.ASCII.GetBytes("This is some data of any length.") + toEncrypt = Encoding.ASCII.GetBytes("This is some data of any length.") ' Create a file. Dim fStream As New FileStream("Data.dat", FileMode.OpenOrCreate) @@ -54,7 +54,7 @@ Public Module MemoryProtectionSample Dim entropy As Byte() = CreateRandomEntropy() Console.WriteLine() - Console.WriteLine("Original data: " + UnicodeEncoding.ASCII.GetString(toEncrypt)) + Console.WriteLine("Original data: " + Encoding.ASCII.GetString(toEncrypt)) Console.WriteLine("Encrypting and writing to disk...") ' Encrypt a copy of the data to the stream. @@ -72,7 +72,7 @@ Public Module MemoryProtectionSample fStream.Close() - Console.WriteLine("Decrypted data: " + UnicodeEncoding.ASCII.GetString(decryptData)) + Console.WriteLine("Decrypted data: " + Encoding.ASCII.GetString(decryptData)) Catch e As Exception @@ -115,11 +115,8 @@ Public Module MemoryProtectionSample ' Create a byte array to hold the random value. Dim entropy(15) As Byte - ' Create a new instance of the RNGCryptoServiceProvider. ' Fill the array with a random value. - Dim RNG As New RNGCryptoServiceProvider() - - RNG.GetBytes(entropy) + RandomNumberGenerator.Fill(entropy) ' Return the array. Return entropy From acfaaeba56ef638416d9a7950b24b1341c30048c Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Wed, 15 Apr 2026 18:39:27 -0700 Subject: [PATCH 06/21] Address PR review feedback - Add ai-usage: ai-assisted frontmatter to all 11 modified articles. - Change FileMode.OpenOrCreate to FileMode.Create in encrypt samples to avoid trailing bytes from previous runs breaking decryption. - Add argument validation with usage message to both C# and VB decrypt samples so they fail clearly without a hex key argument. - Update decrypting-data.md narrative to explain the key is passed as a hex command-line argument from the encrypt sample output. - CryptoWalkThru: Replace Read with ReadExactly for the length fields and remove unnecessary Seek calls since stream is already at position 0 after open. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/fundamentals/code-analysis/quality-rules/ca5387.md | 1 + docs/fundamentals/code-analysis/quality-rules/ca5388.md | 1 + docs/fundamentals/syslib-diagnostics/syslib0041.md | 1 + docs/standard/security/cryptographic-services.md | 1 + docs/standard/security/cryptographic-signatures.md | 1 + docs/standard/security/cryptography-model.md | 1 + docs/standard/security/decrypting-data.md | 5 +++-- docs/standard/security/encrypting-data.md | 1 + .../security/how-to-access-hardware-encryption-devices.md | 1 + .../how-to-encrypt-xml-elements-with-symmetric-keys.md | 1 + .../snippets/decrypting-data/csharp/aes-decrypt.cs | 6 ++++++ .../security/snippets/decrypting-data/vb/aes-decrypt.vb | 8 +++++++- .../snippets/encrypting-data/csharp/aes-encrypt.cs | 2 +- .../security/snippets/encrypting-data/vb/aes-encrypt.vb | 2 +- .../walkthrough-encrypting-and-decrypting-strings.md | 3 ++- .../csharp/VS_Snippets_CLR/CryptoWalkThru/cs/Form1.cs | 6 ++---- 16 files changed, 31 insertions(+), 10 deletions(-) diff --git a/docs/fundamentals/code-analysis/quality-rules/ca5387.md b/docs/fundamentals/code-analysis/quality-rules/ca5387.md index 8fd5b8f05ea23..5604407b4551f 100644 --- a/docs/fundamentals/code-analysis/quality-rules/ca5387.md +++ b/docs/fundamentals/code-analysis/quality-rules/ca5387.md @@ -2,6 +2,7 @@ title: "CA5387: Do not use weak key derivation function with insufficient iteration count (code analysis)" description: Provides information about code analysis rule CA5387, including causes, how to fix violations, and when to suppress it. ms.date: 05/08/2020 +ai-usage: ai-assisted author: LLLXXXCCC ms.author: linche f1_keywords: diff --git a/docs/fundamentals/code-analysis/quality-rules/ca5388.md b/docs/fundamentals/code-analysis/quality-rules/ca5388.md index 0ae56db807ce5..53c43139fc58e 100644 --- a/docs/fundamentals/code-analysis/quality-rules/ca5388.md +++ b/docs/fundamentals/code-analysis/quality-rules/ca5388.md @@ -2,6 +2,7 @@ title: "CA5388: Ensure sufficient iteration count when using weak key derivation function (code analysis)" description: Provides information about code analysis rule CA5388, including causes, how to fix violations, and when to suppress it. ms.date: 05/08/2020 +ai-usage: ai-assisted author: LLLXXXCCC ms.author: linche f1_keywords: diff --git a/docs/fundamentals/syslib-diagnostics/syslib0041.md b/docs/fundamentals/syslib-diagnostics/syslib0041.md index a74c1a2d01540..045b2012521e7 100644 --- a/docs/fundamentals/syslib-diagnostics/syslib0041.md +++ b/docs/fundamentals/syslib-diagnostics/syslib0041.md @@ -2,6 +2,7 @@ title: SYSLIB0041 warning - Rfc2898DeriveBytes constructors with default hash algorithm and iteration counts are obsolete description: Learn about the obsoletion of some Rfc2898DeriveBytes constructors that generates compile-time warning SYSLIB0041. ms.date: 04/08/2022 +ai-usage: ai-assisted f1_keywords: - syslib0041 --- diff --git a/docs/standard/security/cryptographic-services.md b/docs/standard/security/cryptographic-services.md index bc1f3a4b64551..f57e0e44e4a4d 100644 --- a/docs/standard/security/cryptographic-services.md +++ b/docs/standard/security/cryptographic-services.md @@ -2,6 +2,7 @@ title: "Overview of encryption, signatures, and hash algorithms in .NET" description: Learn about encryption methods and practices in .NET, including digital signatures, random number generation, and Cryptography Next Generation (CNG) classes. ms.date: 03/03/2022 +ai-usage: ai-assisted helpviewer_keywords: - "cryptography [.NET]" - "pattern of derived class inheritance" diff --git a/docs/standard/security/cryptographic-signatures.md b/docs/standard/security/cryptographic-signatures.md index 6a47d8bc080a1..e7158f01a28bb 100644 --- a/docs/standard/security/cryptographic-signatures.md +++ b/docs/standard/security/cryptographic-signatures.md @@ -2,6 +2,7 @@ description: "Learn more about: Cryptographic Signatures" title: "Cryptographic Signatures" ms.date: 08/08/2022 +ai-usage: ai-assisted dev_langs: - "csharp" - "vb" diff --git a/docs/standard/security/cryptography-model.md b/docs/standard/security/cryptography-model.md index fbabe92801c42..f5c40db1dc837 100644 --- a/docs/standard/security/cryptography-model.md +++ b/docs/standard/security/cryptography-model.md @@ -2,6 +2,7 @@ title: ".NET cryptography model" description: Review implementations of usual cryptographic algorithms in .NET. Learn the cryptography model of object inheritance and one-shots. ms.date: 02/26/2021 +ai-usage: ai-assisted dev_langs: - "csharp" - "vb" diff --git a/docs/standard/security/decrypting-data.md b/docs/standard/security/decrypting-data.md index 96a83802cd43b..e7c796fb1f9aa 100644 --- a/docs/standard/security/decrypting-data.md +++ b/docs/standard/security/decrypting-data.md @@ -2,6 +2,7 @@ title: "Decrypting data" description: Learn how to decrypt data in .NET, using a symmetric algorithm or an asymmetric algorithm. ms.date: 11/14/2022 +ai-usage: ai-assisted dev_langs: - "csharp" - "vb" @@ -38,12 +39,12 @@ CryptoStream cryptStream = new CryptoStream( fileStream, aes.CreateDecryptor(key, iv), CryptoStreamMode.Read); ``` -The following example shows the entire process of creating a stream, decrypting the stream, reading from the stream, and closing the streams. A file stream object is created that reads a file named *TestData.txt*. The file stream is then decrypted using the **CryptoStream** class and the **Aes** class. This example specifies key value that is used in the symmetric encryption example for [Encrypting Data](encrypting-data.md). It does not show the code needed to encrypt and transfer these values. +The following example shows the entire process of creating a stream, decrypting the stream, reading from the stream, and closing the streams. A file stream object is created that reads a file named *TestData.txt*. The file stream is then decrypted using the **CryptoStream** class and the **Aes** class. This example expects the encryption key as a hex-encoded command-line argument. You can obtain this key from the output of the symmetric encryption example in [Encrypting Data](encrypting-data.md). :::code language="csharp" source="snippets/decrypting-data/csharp/aes-decrypt.cs"::: :::code language="vb" source="snippets/decrypting-data/vb/aes-decrypt.vb"::: -The preceding example uses the same key, and algorithm used in the symmetric encryption example for [Encrypting Data](encrypting-data.md). It decrypts the *TestData.txt* file that is created by that example and displays the original text on the console. +The preceding example uses the same algorithm used in the symmetric encryption example for [Encrypting Data](encrypting-data.md). It decrypts the *TestData.txt* file that is created by that example and displays the original text on the console. Pass the hex key printed by the encryption sample as the first command-line argument. ## Asymmetric decryption diff --git a/docs/standard/security/encrypting-data.md b/docs/standard/security/encrypting-data.md index 2b97fd711a0cd..24af1f8fb55aa 100644 --- a/docs/standard/security/encrypting-data.md +++ b/docs/standard/security/encrypting-data.md @@ -2,6 +2,7 @@ title: "Encrypting data" description: Learn how to encrypt data in .NET, using a symmetric algorithm or an asymmetric algorithm. ms.date: 11/14/2022 +ai-usage: ai-assisted dev_langs: - "csharp" - "vb" diff --git a/docs/standard/security/how-to-access-hardware-encryption-devices.md b/docs/standard/security/how-to-access-hardware-encryption-devices.md index 3e8628f4c338f..782ea610ecc05 100644 --- a/docs/standard/security/how-to-access-hardware-encryption-devices.md +++ b/docs/standard/security/how-to-access-hardware-encryption-devices.md @@ -2,6 +2,7 @@ description: "Learn more about: How to: Access Hardware Encryption Devices" title: "How to: Access Hardware Encryption Devices" ms.date: 07/14/2020 +ai-usage: ai-assisted dev_langs: - "csharp" - "vb" diff --git a/docs/standard/security/how-to-encrypt-xml-elements-with-symmetric-keys.md b/docs/standard/security/how-to-encrypt-xml-elements-with-symmetric-keys.md index e002d55265d71..b33af8fd20fc2 100644 --- a/docs/standard/security/how-to-encrypt-xml-elements-with-symmetric-keys.md +++ b/docs/standard/security/how-to-encrypt-xml-elements-with-symmetric-keys.md @@ -2,6 +2,7 @@ description: "Learn more about: How to: Encrypt XML Elements with Symmetric Keys" title: "How to: Encrypt XML Elements with Symmetric Keys" ms.date: 07/14/2020 +ai-usage: ai-assisted dev_langs: - "csharp" - "vb" diff --git a/docs/standard/security/snippets/decrypting-data/csharp/aes-decrypt.cs b/docs/standard/security/snippets/decrypting-data/csharp/aes-decrypt.cs index 014eafffc3dce..60488f88ef8c3 100644 --- a/docs/standard/security/snippets/decrypting-data/csharp/aes-decrypt.cs +++ b/docs/standard/security/snippets/decrypting-data/csharp/aes-decrypt.cs @@ -1,5 +1,11 @@ using System.Security.Cryptography; +if (args.Length < 1) +{ + Console.WriteLine("Usage: aes-decrypt "); + return; +} + try { using (FileStream fileStream = new("TestData.txt", FileMode.Open)) diff --git a/docs/standard/security/snippets/decrypting-data/vb/aes-decrypt.vb b/docs/standard/security/snippets/decrypting-data/vb/aes-decrypt.vb index 08183c81ffc37..5f79487053bad 100644 --- a/docs/standard/security/snippets/decrypting-data/vb/aes-decrypt.vb +++ b/docs/standard/security/snippets/decrypting-data/vb/aes-decrypt.vb @@ -4,10 +4,16 @@ Imports System.Security.Cryptography Module Module1 Sub Main() + Dim args As String() = Environment.GetCommandLineArgs() + If args.Length < 2 Then + Console.WriteLine("Usage: aes-decrypt ") + Return + End If + ' The key must match the key used during encryption. ' In production, retrieve the key from a secure key management ' system rather than hardcoding it in source code. - Dim key As Byte() = Convert.FromHexString(Environment.GetCommandLineArgs()(1)) + Dim key As Byte() = Convert.FromHexString(args(1)) Try ' Create a file stream. diff --git a/docs/standard/security/snippets/encrypting-data/csharp/aes-encrypt.cs b/docs/standard/security/snippets/encrypting-data/csharp/aes-encrypt.cs index 6f64ecbcefccf..8e8cff2ce6443 100644 --- a/docs/standard/security/snippets/encrypting-data/csharp/aes-encrypt.cs +++ b/docs/standard/security/snippets/encrypting-data/csharp/aes-encrypt.cs @@ -4,7 +4,7 @@ { string keyHex; - using (FileStream fileStream = new("TestData.txt", FileMode.OpenOrCreate)) + using (FileStream fileStream = new("TestData.txt", FileMode.Create)) { using (Aes aes = Aes.Create()) { diff --git a/docs/standard/security/snippets/encrypting-data/vb/aes-encrypt.vb b/docs/standard/security/snippets/encrypting-data/vb/aes-encrypt.vb index 2c351ae10e626..e7fac430e19ab 100644 --- a/docs/standard/security/snippets/encrypting-data/vb/aes-encrypt.vb +++ b/docs/standard/security/snippets/encrypting-data/vb/aes-encrypt.vb @@ -8,7 +8,7 @@ Module Module1 Dim keyHex As String ' Create a file stream - Using fileStream As New FileStream("TestData.txt", FileMode.OpenOrCreate) + Using fileStream As New FileStream("TestData.txt", FileMode.Create) ' Create a new instance of the default Aes implementation class ' and configure encryption key. diff --git a/docs/visual-basic/programming-guide/language-features/strings/walkthrough-encrypting-and-decrypting-strings.md b/docs/visual-basic/programming-guide/language-features/strings/walkthrough-encrypting-and-decrypting-strings.md index fd802eac091b0..3aaec29f2e2ee 100644 --- a/docs/visual-basic/programming-guide/language-features/strings/walkthrough-encrypting-and-decrypting-strings.md +++ b/docs/visual-basic/programming-guide/language-features/strings/walkthrough-encrypting-and-decrypting-strings.md @@ -2,7 +2,8 @@ description: "Learn more about: Walkthrough: Encrypting and Decrypting Strings in Visual Basic" title: "Encrypting and Decrypting Strings" ms.date: 07/20/2015 -helpviewer_keywords: +ai-usage: ai-assisted +helpviewer_keywords: - "encryption [Visual Basic], strings" - "strings [Visual Basic], encrypting" - "decryption [Visual Basic], strings" diff --git a/samples/snippets/csharp/VS_Snippets_CLR/CryptoWalkThru/cs/Form1.cs b/samples/snippets/csharp/VS_Snippets_CLR/CryptoWalkThru/cs/Form1.cs index 6e0a851b38c7c..44e5878c3f6cd 100644 --- a/samples/snippets/csharp/VS_Snippets_CLR/CryptoWalkThru/cs/Form1.cs +++ b/samples/snippets/csharp/VS_Snippets_CLR/CryptoWalkThru/cs/Form1.cs @@ -205,10 +205,8 @@ private void DecryptFile(FileInfo file) // file (inFs) and save the decrypted file (outFs). using (var inFs = new FileStream(file.FullName, FileMode.Open)) { - inFs.Seek(0, SeekOrigin.Begin); - inFs.Read(LenK, 0, 4); - inFs.Seek(4, SeekOrigin.Begin); - inFs.Read(LenIV, 0, 4); + inFs.ReadExactly(LenK, 0, 4); + inFs.ReadExactly(LenIV, 0, 4); // Convert the lengths to integer values. int lenK = BitConverter.ToInt32(LenK, 0); From 0fbb4be51f6095d1c65a0a7c4125150e36cd04a5 Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Wed, 15 Apr 2026 19:20:12 -0700 Subject: [PATCH 07/21] Revert DPAPI RNG to RNGCryptoServiceProvider for net461 compat The DPAPI sample targets net461, which does not support RandomNumberGenerator.Fill(Span). Revert to RNGCryptoServiceProvider but wrap in a using statement to properly dispose the instance. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../snippets/csharp/VS_Snippets_CLR/DPAPI-HowTO/cs/sample.cs | 5 ++++- .../visualbasic/VS_Snippets_CLR/DPAPI-HowTO/vb/sample.vb | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/samples/snippets/csharp/VS_Snippets_CLR/DPAPI-HowTO/cs/sample.cs b/samples/snippets/csharp/VS_Snippets_CLR/DPAPI-HowTO/cs/sample.cs index 4817a38ad5e06..8553b67ac4c4a 100644 --- a/samples/snippets/csharp/VS_Snippets_CLR/DPAPI-HowTO/cs/sample.cs +++ b/samples/snippets/csharp/VS_Snippets_CLR/DPAPI-HowTO/cs/sample.cs @@ -105,7 +105,10 @@ public static byte[] CreateRandomEntropy() byte[] entropy = new byte[16]; // Fill the array with a random value. - RandomNumberGenerator.Fill(entropy); + using (var rng = new RNGCryptoServiceProvider()) + { + rng.GetBytes(entropy); + } // Return the array. return entropy; diff --git a/samples/snippets/visualbasic/VS_Snippets_CLR/DPAPI-HowTO/vb/sample.vb b/samples/snippets/visualbasic/VS_Snippets_CLR/DPAPI-HowTO/vb/sample.vb index 6f4dfb7e8ccb2..0cb76ad313a1e 100644 --- a/samples/snippets/visualbasic/VS_Snippets_CLR/DPAPI-HowTO/vb/sample.vb +++ b/samples/snippets/visualbasic/VS_Snippets_CLR/DPAPI-HowTO/vb/sample.vb @@ -116,7 +116,9 @@ Public Module MemoryProtectionSample Dim entropy(15) As Byte ' Fill the array with a random value. - RandomNumberGenerator.Fill(entropy) + Using rng As New RNGCryptoServiceProvider() + rng.GetBytes(entropy) + End Using ' Return the array. Return entropy From e440169c799586436d985623f7cba5bc8881ee5a Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Wed, 15 Apr 2026 19:33:43 -0700 Subject: [PATCH 08/21] Address second round of PR review feedback - VB decrypt: Move Convert.FromHexString inside the Try block so invalid hex input is caught gracefully instead of throwing an unhandled exception before the error handler. - VB encrypt: Align success message to 'The file was encrypted.' to match the C# sample and the article prose. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../security/snippets/decrypting-data/vb/aes-decrypt.vb | 9 ++++----- .../security/snippets/encrypting-data/vb/aes-encrypt.vb | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/docs/standard/security/snippets/decrypting-data/vb/aes-decrypt.vb b/docs/standard/security/snippets/decrypting-data/vb/aes-decrypt.vb index 5f79487053bad..da2fa38d83a94 100644 --- a/docs/standard/security/snippets/decrypting-data/vb/aes-decrypt.vb +++ b/docs/standard/security/snippets/decrypting-data/vb/aes-decrypt.vb @@ -10,12 +10,11 @@ Module Module1 Return End If - ' The key must match the key used during encryption. - ' In production, retrieve the key from a secure key management - ' system rather than hardcoding it in source code. - Dim key As Byte() = Convert.FromHexString(args(1)) - Try + ' The key must match the key used during encryption. + ' In production, retrieve the key from a secure key management + ' system rather than hardcoding it in source code. + Dim key As Byte() = Convert.FromHexString(args(1)) ' Create a file stream. Using fileStream As New FileStream("TestData.txt", FileMode.Open) diff --git a/docs/standard/security/snippets/encrypting-data/vb/aes-encrypt.vb b/docs/standard/security/snippets/encrypting-data/vb/aes-encrypt.vb index e7fac430e19ab..fe92abd579e63 100644 --- a/docs/standard/security/snippets/encrypting-data/vb/aes-encrypt.vb +++ b/docs/standard/security/snippets/encrypting-data/vb/aes-encrypt.vb @@ -40,7 +40,7 @@ Module Module1 End Using End Using - Console.WriteLine("The text was encrypted.") + Console.WriteLine("The file was encrypted.") Console.WriteLine($"Key (hex): {keyHex}") Catch Console.WriteLine("The encryption failed.") From b5e2bbd8d4cd4314fe8b114e03896aa1cfcbc2d8 Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Wed, 15 Apr 2026 19:42:28 -0700 Subject: [PATCH 09/21] Fix RSACryptoServiceProvider obsoletion wording in hardware encryption doc RSACryptoServiceProvider itself is not obsolete in .NET 6; only RNGCryptoServiceProvider is (SYSLIB0023). Specific RSACryptoServiceProvider members become obsolete in later versions. Updated the warning to accurately distinguish between the two. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../security/how-to-access-hardware-encryption-devices.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/standard/security/how-to-access-hardware-encryption-devices.md b/docs/standard/security/how-to-access-hardware-encryption-devices.md index 782ea610ecc05..7a82d2d8a9cf9 100644 --- a/docs/standard/security/how-to-access-hardware-encryption-devices.md +++ b/docs/standard/security/how-to-access-hardware-encryption-devices.md @@ -19,7 +19,7 @@ helpviewer_keywords: > This article applies to Windows. > [!WARNING] -> This article uses legacy APIs ( and ) that are obsolete in .NET 6 and later. For new code, use and instead. The code sample also uses SHA-1 for signing, which is insecure—use SHA-256 or higher. +> This article uses legacy APIs ( and ). is obsolete starting in .NET 6 (SYSLIB0023). is a legacy API, though not itself obsolete; specific members are obsolete in later .NET versions. For new code, use and instead. The code sample also uses SHA-1 for signing, which is insecure—use SHA-256 or higher. You can use the class to access hardware encryption devices. For example, you can use this class to integrate your application with a smart card, a hardware random number generator, or a hardware implementation of a particular cryptographic algorithm. From a356a6b40e306e6a38feaa0ce92037f58ae9dce6 Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Wed, 15 Apr 2026 19:48:06 -0700 Subject: [PATCH 10/21] Add VB DPAPI project file and re-apply fixes The VB DPAPI sample had no .vbproj, causing a snippets-build failure. Add a .vbproj matching the C# project (net461 with System.Security.Cryptography.ProtectedData). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../VS_Snippets_CLR/DPAPI-HowTO/vb/sample.vbproj | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 samples/snippets/visualbasic/VS_Snippets_CLR/DPAPI-HowTO/vb/sample.vbproj diff --git a/samples/snippets/visualbasic/VS_Snippets_CLR/DPAPI-HowTO/vb/sample.vbproj b/samples/snippets/visualbasic/VS_Snippets_CLR/DPAPI-HowTO/vb/sample.vbproj new file mode 100644 index 0000000000000..202fb09d05106 --- /dev/null +++ b/samples/snippets/visualbasic/VS_Snippets_CLR/DPAPI-HowTO/vb/sample.vbproj @@ -0,0 +1,13 @@ + + + + Exe + net461 + DPAPI_HowTO + + + + + + + From a512d7ad4d7ee6640890388653551a7459302a13 Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Wed, 15 Apr 2026 20:06:15 -0700 Subject: [PATCH 11/21] Restore hard-coded sample keys with illustration comments Peer feedback indicated that requiring keys via command-line args was a step backward for sample usability. Restore the original hard-coded keys in the AES encrypt/decrypt snippets so the samples work as a self-contained pair. Add comments clarifying the keys are for illustration only and that production code should use secure key management. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/standard/security/decrypting-data.md | 4 ++-- docs/standard/security/encrypting-data.md | 5 ++--- .../decrypting-data/csharp/aes-decrypt.cs | 18 ++++++++---------- .../snippets/decrypting-data/vb/aes-decrypt.vb | 13 ++++--------- .../encrypting-data/csharp/aes-encrypt.cs | 18 +++++++++--------- .../snippets/encrypting-data/vb/aes-encrypt.vb | 18 +++++++++--------- 6 files changed, 34 insertions(+), 42 deletions(-) diff --git a/docs/standard/security/decrypting-data.md b/docs/standard/security/decrypting-data.md index e7c796fb1f9aa..37ce8c657d110 100644 --- a/docs/standard/security/decrypting-data.md +++ b/docs/standard/security/decrypting-data.md @@ -39,12 +39,12 @@ CryptoStream cryptStream = new CryptoStream( fileStream, aes.CreateDecryptor(key, iv), CryptoStreamMode.Read); ``` -The following example shows the entire process of creating a stream, decrypting the stream, reading from the stream, and closing the streams. A file stream object is created that reads a file named *TestData.txt*. The file stream is then decrypted using the **CryptoStream** class and the **Aes** class. This example expects the encryption key as a hex-encoded command-line argument. You can obtain this key from the output of the symmetric encryption example in [Encrypting Data](encrypting-data.md). +The following example shows the entire process of creating a stream, decrypting the stream, reading from the stream, and closing the streams. A file stream object is created that reads a file named *TestData.txt*. The file stream is then decrypted using the **CryptoStream** class and the **Aes** class. This example specifies the same key value that is used in the symmetric encryption example for [Encrypting Data](encrypting-data.md). It does not show the code needed to encrypt and transfer these values. :::code language="csharp" source="snippets/decrypting-data/csharp/aes-decrypt.cs"::: :::code language="vb" source="snippets/decrypting-data/vb/aes-decrypt.vb"::: -The preceding example uses the same algorithm used in the symmetric encryption example for [Encrypting Data](encrypting-data.md). It decrypts the *TestData.txt* file that is created by that example and displays the original text on the console. Pass the hex key printed by the encryption sample as the first command-line argument. +The preceding example uses the same key and algorithm used in the symmetric encryption example for [Encrypting Data](encrypting-data.md). It decrypts the *TestData.txt* file that is created by that example and displays the original text on the console. ## Asymmetric decryption diff --git a/docs/standard/security/encrypting-data.md b/docs/standard/security/encrypting-data.md index 24af1f8fb55aa..85012c57c455e 100644 --- a/docs/standard/security/encrypting-data.md +++ b/docs/standard/security/encrypting-data.md @@ -46,14 +46,13 @@ The following example shows the entire process of creating a stream, encrypting :::code language="csharp" source="snippets/encrypting-data/csharp/aes-encrypt.cs"::: :::code language="vb" source="snippets/encrypting-data/vb/aes-encrypt.vb"::: -The code encrypts the stream using the AES symmetric algorithm, and writes IV and then encrypted "Hello World!" to the stream. If the code is successful, it creates an encrypted file named *TestData.txt* and displays the key in hexadecimal: +The code encrypts the stream using the AES symmetric algorithm, and writes IV and then encrypted "Hello World!" to the stream. If the code is successful, it creates an encrypted file named *TestData.txt* and displays the following text to the console: ```console The file was encrypted. -Key (hex): 1A2B3C... ``` -You can decrypt the file by using the symmetric decryption example in [Decrypting Data](decrypting-data.md), passing the hex key as a command-line argument. +You can decrypt the file by using the symmetric decryption example in [Decrypting Data](decrypting-data.md). That example and this example specify the same key. However, if an exception is raised, the code displays the following text to the console: diff --git a/docs/standard/security/snippets/decrypting-data/csharp/aes-decrypt.cs b/docs/standard/security/snippets/decrypting-data/csharp/aes-decrypt.cs index 60488f88ef8c3..cc3240451c3ac 100644 --- a/docs/standard/security/snippets/decrypting-data/csharp/aes-decrypt.cs +++ b/docs/standard/security/snippets/decrypting-data/csharp/aes-decrypt.cs @@ -1,11 +1,5 @@ using System.Security.Cryptography; -if (args.Length < 1) -{ - Console.WriteLine("Usage: aes-decrypt "); - return; -} - try { using (FileStream fileStream = new("TestData.txt", FileMode.Open)) @@ -24,10 +18,14 @@ numBytesToRead -= n; } - // The key must match the key used during encryption. - // In production, retrieve the key from a secure key management - // system rather than hardcoding it in source code. - byte[] key = Convert.FromHexString(args[0]); + // This key is for illustration purposes only and must + // match the key used during encryption. + // In production, use a securely stored or managed key. + byte[] key = + { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 + }; using (CryptoStream cryptoStream = new( fileStream, diff --git a/docs/standard/security/snippets/decrypting-data/vb/aes-decrypt.vb b/docs/standard/security/snippets/decrypting-data/vb/aes-decrypt.vb index da2fa38d83a94..a5c633f7ee676 100644 --- a/docs/standard/security/snippets/decrypting-data/vb/aes-decrypt.vb +++ b/docs/standard/security/snippets/decrypting-data/vb/aes-decrypt.vb @@ -4,17 +4,12 @@ Imports System.Security.Cryptography Module Module1 Sub Main() - Dim args As String() = Environment.GetCommandLineArgs() - If args.Length < 2 Then - Console.WriteLine("Usage: aes-decrypt ") - Return - End If + ' This key is for illustration purposes only and must + ' match the key used during encryption. + ' In production, use a securely stored or managed key. + Dim key As Byte() = {&H1, &H2, &H3, &H4, &H5, &H6, &H7, &H8, &H9, &H10, &H11, &H12, &H13, &H14, &H15, &H16} Try - ' The key must match the key used during encryption. - ' In production, retrieve the key from a secure key management - ' system rather than hardcoding it in source code. - Dim key As Byte() = Convert.FromHexString(args(1)) ' Create a file stream. Using fileStream As New FileStream("TestData.txt", FileMode.Open) diff --git a/docs/standard/security/snippets/encrypting-data/csharp/aes-encrypt.cs b/docs/standard/security/snippets/encrypting-data/csharp/aes-encrypt.cs index 8e8cff2ce6443..ee21c127a022c 100644 --- a/docs/standard/security/snippets/encrypting-data/csharp/aes-encrypt.cs +++ b/docs/standard/security/snippets/encrypting-data/csharp/aes-encrypt.cs @@ -2,17 +2,18 @@ try { - string keyHex; - - using (FileStream fileStream = new("TestData.txt", FileMode.Create)) + using (FileStream fileStream = new("TestData.txt", FileMode.OpenOrCreate)) { using (Aes aes = Aes.Create()) { - // Generate a cryptographically secure random key. - // In production, use a key management system or derive from a - // password using Rfc2898DeriveBytes.Pbkdf2 with a high iteration count. - aes.GenerateKey(); - keyHex = Convert.ToHexString(aes.Key); + // This key is for illustration purposes only. + // In production, use a securely stored or managed key. + byte[] key = + { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 + }; + aes.Key = key; byte[] iv = aes.IV; fileStream.Write(iv, 0, iv.Length); @@ -34,7 +35,6 @@ } Console.WriteLine("The file was encrypted."); - Console.WriteLine($"Key (hex): {keyHex}"); } catch (Exception ex) { diff --git a/docs/standard/security/snippets/encrypting-data/vb/aes-encrypt.vb b/docs/standard/security/snippets/encrypting-data/vb/aes-encrypt.vb index fe92abd579e63..0783b144d3525 100644 --- a/docs/standard/security/snippets/encrypting-data/vb/aes-encrypt.vb +++ b/docs/standard/security/snippets/encrypting-data/vb/aes-encrypt.vb @@ -5,19 +5,20 @@ Imports System.Security.Cryptography Module Module1 Sub Main() Try - Dim keyHex As String - ' Create a file stream - Using fileStream As New FileStream("TestData.txt", FileMode.Create) + Using fileStream As New FileStream("TestData.txt", FileMode.OpenOrCreate) ' Create a new instance of the default Aes implementation class ' and configure encryption key. Using aes As Aes = Aes.Create() - ' Generate a cryptographically secure random key. - ' In production, use a key management system or derive from a - ' password using Rfc2898DeriveBytes.Pbkdf2 with a high iteration count. - aes.GenerateKey() - keyHex = Convert.ToHexString(aes.Key) + ' This key is for illustration purposes only. + ' In production, use a securely stored or managed key. + Dim key As Byte() = { + &H1, &H2, &H3, &H4, &H5, &H6, &H7, &H8, + &H9, &H10, &H11, &H12, &H13, &H14, &H15, &H16 + } + + aes.Key = key ' Stores IV at the beginning of the file. ' This information will be used for decryption. @@ -41,7 +42,6 @@ Module Module1 End Using Console.WriteLine("The file was encrypted.") - Console.WriteLine($"Key (hex): {keyHex}") Catch Console.WriteLine("The encryption failed.") Throw From 59997bc604f3bdf8b5d9deadf1dce420a65dd03a Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Wed, 15 Apr 2026 20:16:14 -0700 Subject: [PATCH 12/21] Address reviewer feedback: NIST over OWASP, no algorithm names, no AES-GCM - Replace all OWASP references with NIST SP 800-132, 800-131A, 800-56B, and 800-57 citations. - Remove all casual AES-GCM recommendations. - Avoid recommending specific algorithms like 'SHA-256 or higher'; use 'FIPS-approved hash algorithm' instead. - Add DoS trade-off explanation for PBKDF2 iteration counts. - Name the actual Pbkdf2 method instead of 'one-shot static method'. - Explain why MD5/SHA-1 are included: standards conformance and backward compatibility. - Soften MD5/SHA-1 warning to 'unless required by a data format standard'. - Revert unrelated ASCII-to-UTF8 change in C# signature snippet. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/fundamentals/code-analysis/quality-rules/ca5387.md | 2 +- docs/fundamentals/code-analysis/quality-rules/ca5388.md | 2 +- docs/fundamentals/syslib-diagnostics/syslib0041.md | 4 ++-- docs/standard/security/cryptographic-services.md | 8 ++++---- docs/standard/security/cryptographic-signatures.md | 2 +- docs/standard/security/cryptography-model.md | 2 +- docs/standard/security/decrypting-data.md | 2 +- docs/standard/security/encrypting-data.md | 6 +++--- .../security/how-to-access-hardware-encryption-devices.md | 2 +- .../snippets/cryptographic-signatures/csharp/Program.cs | 2 +- .../walkthrough-encrypting-and-decrypting-strings.md | 2 +- 11 files changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/fundamentals/code-analysis/quality-rules/ca5387.md b/docs/fundamentals/code-analysis/quality-rules/ca5387.md index 5604407b4551f..f02b59a16b26e 100644 --- a/docs/fundamentals/code-analysis/quality-rules/ca5387.md +++ b/docs/fundamentals/code-analysis/quality-rules/ca5387.md @@ -36,7 +36,7 @@ This rule is similar to [CA5388](ca5388.md), but analysis determines that the it Set the iteration count greater than or equal with 100,000 before calling . > [!TIP] -> While the analyzer enforces a minimum of 100,000 iterations, this threshold might not keep pace with hardware improvements. Consult the [OWASP Password Storage Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html) for up-to-date recommendations. For password storage scenarios, use the highest iteration count your performance budget allows. Also consider using (the one-shot static method) with or higher. +> While the analyzer enforces a minimum of 100,000 iterations, this threshold might not keep pace with hardware improvements. [NIST SP 800-132](https://csrc.nist.gov/pubs/sp/800/132/final) recommends selecting an iteration count as high as your environment can tolerate, and increasing it periodically as computing power grows. However, excessively high iteration counts increase CPU cost per authentication attempt, which can be exploited for denial-of-service attacks—choose a value that balances security with acceptable login latency for your application. Also consider using with a FIPS-approved hash algorithm. ## When to suppress warnings diff --git a/docs/fundamentals/code-analysis/quality-rules/ca5388.md b/docs/fundamentals/code-analysis/quality-rules/ca5388.md index 53c43139fc58e..9b4c2162818f0 100644 --- a/docs/fundamentals/code-analysis/quality-rules/ca5388.md +++ b/docs/fundamentals/code-analysis/quality-rules/ca5388.md @@ -36,7 +36,7 @@ This rule is similar to [CA5387](ca5387.md), but analysis can't determine if the Set the iteration count greater than or equal with 100k before calling explicitly. > [!TIP] -> While the analyzer enforces a minimum of 100,000 iterations, this threshold might not keep pace with hardware improvements. Consult the [OWASP Password Storage Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html) for up-to-date recommendations. For password storage scenarios, use the highest iteration count your performance budget allows. Also consider using (the one-shot static method) with or higher. +> While the analyzer enforces a minimum of 100,000 iterations, this threshold might not keep pace with hardware improvements. [NIST SP 800-132](https://csrc.nist.gov/pubs/sp/800/132/final) recommends selecting an iteration count as high as your environment can tolerate, and increasing it periodically as computing power grows. However, excessively high iteration counts increase CPU cost per authentication attempt, which can be exploited for denial-of-service attacks—choose a value that balances security with acceptable login latency for your application. Also consider using with a FIPS-approved hash algorithm. ## When to suppress warnings diff --git a/docs/fundamentals/syslib-diagnostics/syslib0041.md b/docs/fundamentals/syslib-diagnostics/syslib0041.md index 045b2012521e7..31171e519f27f 100644 --- a/docs/fundamentals/syslib-diagnostics/syslib0041.md +++ b/docs/fundamentals/syslib-diagnostics/syslib0041.md @@ -22,10 +22,10 @@ The following constructor Use a different constructor overload where you can explicitly specify the iteration count (the default is 1000) and hash algorithm name (the default is ). -If you're using the default iteration count or default hash algorithm, move to more secure values—that is, a much larger iteration count and a newer hash algorithm such as or higher. +If you're using the default iteration count or default hash algorithm, move to more secure values—that is, a much larger iteration count and a FIPS-approved hash algorithm. > [!IMPORTANT] -> Consult the [OWASP Password Storage Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html) for current recommended iteration counts, and use the highest value your performance budget allows. Prefer the one-shot static method as recommended by [SYSLIB0060](syslib0060.md). +> [NIST SP 800-132](https://csrc.nist.gov/pubs/sp/800/132/final) recommends selecting an iteration count as high as your environment can tolerate. Use with a FIPS-approved hash algorithm, as recommended by [SYSLIB0060](syslib0060.md). ## Suppress a warning diff --git a/docs/standard/security/cryptographic-services.md b/docs/standard/security/cryptographic-services.md index f57e0e44e4a4d..0de63b3c85810 100644 --- a/docs/standard/security/cryptographic-services.md +++ b/docs/standard/security/cryptographic-services.md @@ -69,12 +69,12 @@ Secret-key encryption is also referred to as symmetric encryption because the sa A type of secret-key algorithm called a block cipher is used to encrypt one block of data at a time. Block ciphers such as Data Encryption Standard (DES), TripleDES, and Advanced Encryption Standard (AES) cryptographically transform an input block of *n* bytes into an output block of encrypted bytes. If you want to encrypt or decrypt a sequence of bytes, you have to do it block by block. Because *n* is small (8 bytes for DES and TripleDES; 16 bytes [the default], 24 bytes, or 32 bytes for AES), data values that are larger than *n* have to be encrypted one block at a time. Data values that are smaller than *n* have to be expanded to *n* in order to be processed. > [!WARNING] -> DES and TripleDES (3DES) are deprecated and should not be used for new development. Use instead, ideally with an authenticated encryption mode such as GCM (). +> DES and TripleDES (3DES) are deprecated per [NIST SP 800-131A](https://csrc.nist.gov/pubs/sp/800/131a/r2/final) and should not be used for new development. Use instead. One simple form of block cipher is called the electronic codebook (ECB) mode. ECB mode is not considered secure, because it does not use an initialization vector to initialize the first plaintext block. For a given secret key *k*, a simple block cipher that does not use an initialization vector will encrypt the same input block of plaintext into the same output block of ciphertext. Therefore, if you have duplicate blocks in your input plaintext stream, you will have duplicate blocks in your output ciphertext stream. These duplicate output blocks alert unauthorized users to the weak encryption used the algorithms that might have been employed, and the possible modes of attack. The ECB cipher mode is therefore quite vulnerable to analysis, and ultimately, key discovery. > [!WARNING] -> ECB mode must not be used for encryption. Use CBC mode with integrity verification, or preferably an authenticated mode such as GCM or CCM. +> ECB mode must not be used for encryption. CBC mode with an unpredictable IV is the default for .NET's block cipher classes. If data integrity is also required, apply separate authentication (for example, HMAC) using an Encrypt-then-MAC pattern. The block cipher classes that are provided in the base class library use a default chaining mode called cipher-block chaining (CBC), although you can change this default if you want. @@ -177,10 +177,10 @@ None of the previous methods will prevent someone from reading Alice's messages, - . -.NET also provides and . But the MD5 and SHA-1 algorithms have been found to be insecure, and SHA-2 is now recommended instead. SHA-2 includes SHA256, SHA384, and SHA512. +.NET also provides and for standards conformance and backward compatibility with existing data formats and protocols. However, the MD5 and SHA-1 algorithms have been found to be insecure, and SHA-2 is now recommended instead per [NIST SP 800-131A](https://csrc.nist.gov/pubs/sp/800/131a/r2/final). SHA-2 includes SHA256, SHA384, and SHA512. > [!WARNING] -> Do not use MD5 or SHA-1 for any security-sensitive purpose, including data integrity, digital signatures, or certificate validation. Use SHA-256 or higher from the SHA-2 family. +> Do not use MD5 or SHA-1 for security-sensitive purposes such as digital signatures or certificate validation, unless required by an existing data format standard. Use a current FIPS-approved hash algorithm for new development. ## Random Number Generation diff --git a/docs/standard/security/cryptographic-signatures.md b/docs/standard/security/cryptographic-signatures.md index e7158f01a28bb..4e2fc4b1873b3 100644 --- a/docs/standard/security/cryptographic-signatures.md +++ b/docs/standard/security/cryptographic-signatures.md @@ -68,7 +68,7 @@ using System.Text; using SHA256 alg = SHA256.Create(); -byte[] data = Encoding.UTF8.GetBytes("Hello, from the .NET Docs!"); +byte[] data = Encoding.ASCII.GetBytes("Hello, from the .NET Docs!"); byte[] hash = alg.ComputeHash(data); RSAParameters sharedParameters; diff --git a/docs/standard/security/cryptography-model.md b/docs/standard/security/cryptography-model.md index f5c40db1dc837..246fd4abc57fe 100644 --- a/docs/standard/security/cryptography-model.md +++ b/docs/standard/security/cryptography-model.md @@ -85,7 +85,7 @@ Here is a list of recommended algorithms by application: - > [!TIP] -> .NET's built-in password-based key derivation uses the PBKDF2 algorithm. When using PBKDF2, specify or higher, and use the highest iteration count your performance budget allows. Consult the [OWASP Password Storage Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html) for current iteration count recommendations and for guidance on alternative algorithms (such as Argon2id, bcrypt, or scrypt) that are available through third-party libraries. +> .NET's built-in password-based key derivation uses the PBKDF2 algorithm via . When using PBKDF2, specify a current FIPS-approved hash algorithm and set the iteration count as high as your performance budget allows per [NIST SP 800-132](https://csrc.nist.gov/pubs/sp/800/132/final). Alternative algorithms such as Argon2id, bcrypt, or scrypt are available through third-party libraries. ## See also diff --git a/docs/standard/security/decrypting-data.md b/docs/standard/security/decrypting-data.md index 37ce8c657d110..8cd299fa3d104 100644 --- a/docs/standard/security/decrypting-data.md +++ b/docs/standard/security/decrypting-data.md @@ -21,7 +21,7 @@ Decryption is the reverse operation of encryption. For secret-key encryption, yo ## Symmetric decryption > [!IMPORTANT] -> Symmetric decryption with CBC mode (the default for `Aes.Create()`) is vulnerable to padding oracle attacks if the ciphertext integrity isn't verified before decryption. Always verify data integrity (for example, by using an HMAC) before attempting to decrypt, or use authenticated encryption such as . For more information, see [Timing vulnerabilities with CBC-mode symmetric decryption using padding](vulnerabilities-cbc-mode.md). +> Symmetric decryption with CBC mode (the default for `Aes.Create()`) is vulnerable to padding oracle attacks if the ciphertext integrity isn't verified before decryption. Always verify data integrity (for example, by using an HMAC with an Encrypt-then-MAC pattern) before attempting to decrypt. For more information, see [Timing vulnerabilities with CBC-mode symmetric decryption using padding](vulnerabilities-cbc-mode.md). The decryption of data encrypted with symmetric algorithms is similar to the process used to encrypt data with symmetric algorithms. The class is used with symmetric cryptography classes provided by .NET to decrypt data read from any managed stream object. diff --git a/docs/standard/security/encrypting-data.md b/docs/standard/security/encrypting-data.md index 85012c57c455e..889ab96d41028 100644 --- a/docs/standard/security/encrypting-data.md +++ b/docs/standard/security/encrypting-data.md @@ -21,7 +21,7 @@ Symmetric encryption and asymmetric encryption are performed using different pro ## Symmetric encryption > [!IMPORTANT] -> The `Aes.Create()` method defaults to CBC mode without built-in authentication. CBC mode without integrity verification is vulnerable to padding oracle attacks. For production scenarios, use authenticated encryption such as where available, or apply an Encrypt-then-MAC pattern using . For more information, see [Timing vulnerabilities with CBC-mode symmetric decryption using padding](vulnerabilities-cbc-mode.md). +> The `Aes.Create()` method defaults to CBC mode without built-in authentication. CBC mode without integrity verification is vulnerable to padding oracle attacks. For production scenarios, verify data integrity before decryption—for example, by applying an Encrypt-then-MAC pattern. For more information, see [Timing vulnerabilities with CBC-mode symmetric decryption using padding](vulnerabilities-cbc-mode.md). The managed symmetric cryptography classes are used with a special stream class called a that encrypts data read into the stream. The **CryptoStream** class is initialized with a managed stream class, a class that implements the interface (created from a class that implements a cryptographic algorithm), and a enumeration that describes the type of access permitted to the **CryptoStream**. The **CryptoStream** class can be initialized using any class that derives from the class, including , , and . Using these classes, you can perform symmetric encryption on a variety of stream objects. @@ -64,10 +64,10 @@ The encryption failed. Asymmetric algorithms are usually used to encrypt small amounts of data such as the encryption of a symmetric key and IV. Typically, an individual performing asymmetric encryption uses the public key generated by another party. The class is provided by .NET for this purpose. -The following example uses public key information to encrypt a symmetric key and IV. An key pair is generated with a minimum key size of 2048 bits. The public key from one party is used to encrypt the symmetric key and IV generated by an instance, using OAEP padding with SHA-256 for security. +The following example uses public key information to encrypt a symmetric key and IV. An key pair is generated with a minimum key size of 2048 bits. The public key from one party is used to encrypt the symmetric key and IV generated by an instance, using OAEP padding for security. > [!IMPORTANT] -> Use (or higher) instead of . PKCS#1 v1.5 padding is vulnerable to Bleichenbacher-style attacks. Additionally, use RSA key sizes of at least 2048 bits. +> Use (or higher) instead of . PKCS#1 v1.5 padding is deprecated for new systems per [NIST SP 800-56B](https://csrc.nist.gov/pubs/sp/800/56b/r2/final). Use RSA key sizes of at least 2048 bits per [NIST SP 800-57](https://csrc.nist.gov/pubs/sp/800/57/pt1/r5/final). ```vb Imports System diff --git a/docs/standard/security/how-to-access-hardware-encryption-devices.md b/docs/standard/security/how-to-access-hardware-encryption-devices.md index 7a82d2d8a9cf9..ca7b8b3f5eed5 100644 --- a/docs/standard/security/how-to-access-hardware-encryption-devices.md +++ b/docs/standard/security/how-to-access-hardware-encryption-devices.md @@ -19,7 +19,7 @@ helpviewer_keywords: > This article applies to Windows. > [!WARNING] -> This article uses legacy APIs ( and ). is obsolete starting in .NET 6 (SYSLIB0023). is a legacy API, though not itself obsolete; specific members are obsolete in later .NET versions. For new code, use and instead. The code sample also uses SHA-1 for signing, which is insecure—use SHA-256 or higher. +> This article uses legacy APIs ( and ). is obsolete starting in .NET 6 (SYSLIB0023). is a legacy API, though not itself obsolete; specific members are obsolete in later .NET versions. For new code, use and instead. The code sample also uses SHA-1 for signing, which is no longer considered secure—use a current FIPS-approved hash algorithm. You can use the class to access hardware encryption devices. For example, you can use this class to integrate your application with a smart card, a hardware random number generator, or a hardware implementation of a particular cryptographic algorithm. diff --git a/docs/standard/security/snippets/cryptographic-signatures/csharp/Program.cs b/docs/standard/security/snippets/cryptographic-signatures/csharp/Program.cs index f0fd583608172..1cb8ec594af59 100644 --- a/docs/standard/security/snippets/cryptographic-signatures/csharp/Program.cs +++ b/docs/standard/security/snippets/cryptographic-signatures/csharp/Program.cs @@ -3,7 +3,7 @@ using SHA256 alg = SHA256.Create(); -byte[] data = Encoding.UTF8.GetBytes("Hello, from the .NET Docs!"); +byte[] data = Encoding.ASCII.GetBytes("Hello, from the .NET Docs!"); byte[] hash = alg.ComputeHash(data); RSAParameters sharedParameters; diff --git a/docs/visual-basic/programming-guide/language-features/strings/walkthrough-encrypting-and-decrypting-strings.md b/docs/visual-basic/programming-guide/language-features/strings/walkthrough-encrypting-and-decrypting-strings.md index 3aaec29f2e2ee..2e42cdff7cb54 100644 --- a/docs/visual-basic/programming-guide/language-features/strings/walkthrough-encrypting-and-decrypting-strings.md +++ b/docs/visual-basic/programming-guide/language-features/strings/walkthrough-encrypting-and-decrypting-strings.md @@ -13,7 +13,7 @@ ms.assetid: 1f51e40a-2f88-43e2-a83e-28a0b5c0d6fd # Walkthrough: Encrypting and Decrypting Strings in Visual Basic > [!WARNING] -> The TripleDES (3DES) algorithm demonstrated in this walkthrough is considered weak by modern standards and should not be used for new development. Use with authenticated encryption (such as ) instead. For current guidance, see [.NET cryptography model](../../../../standard/security/cryptography-model.md) and the [OWASP Cryptographic Storage Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html). +> The TripleDES (3DES) algorithm demonstrated in this walkthrough is deprecated per [NIST SP 800-131A](https://csrc.nist.gov/pubs/sp/800/131a/r2/final) and should not be used for new development. Use instead. For current guidance, see [.NET cryptography model](../../../../standard/security/cryptography-model.md). This walkthrough shows you how to use the class to encrypt and decrypt strings using the Triple Data Encryption Standard (3DES) algorithm. The first step is to create a simple wrapper class that encapsulates the 3DES algorithm and stores the encrypted data as a base-64 encoded string. Then, that wrapper is used to securely store private user data in a publicly accessible text file. From a85b17055a0122826a5800fac445a1decd2c161b Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Wed, 15 Apr 2026 21:51:26 -0700 Subject: [PATCH 13/21] Address additional reviewer feedback on RSA key sizes and RNG wording - RSA-2048 in inline samples: add 'for illustration; choose a key size that matches your security requirements per NIST SP 800-57' caveat since 2048-bit is approaching minimum security strength. - RandomNumberGenerator: expand to 'cryptographically secure random number generation algorithm'. - encrypting-data.md prose: soften RSA key size language to match the illustrative caveat. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/standard/security/cryptographic-services.md | 2 +- docs/standard/security/decrypting-data.md | 8 ++++++-- docs/standard/security/encrypting-data.md | 10 +++++++--- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/docs/standard/security/cryptographic-services.md b/docs/standard/security/cryptographic-services.md index 0de63b3c85810..05de6eeaba799 100644 --- a/docs/standard/security/cryptographic-services.md +++ b/docs/standard/security/cryptographic-services.md @@ -186,7 +186,7 @@ None of the previous methods will prevent someone from reading Alice's messages, Random number generation is integral to many cryptographic operations. For example, cryptographic keys need to be as random as possible so that it is infeasible to reproduce them. Cryptographic random number generators must generate output that is computationally infeasible to predict with a probability that is better than one half. Therefore, any method of predicting the next output bit must not perform better than random guessing. The classes in .NET use random number generators to generate cryptographic keys. -The class is an implementation of a random number generator algorithm. +The class is an implementation of a cryptographically secure random number generation algorithm. ## ClickOnce Manifests diff --git a/docs/standard/security/decrypting-data.md b/docs/standard/security/decrypting-data.md index 8cd299fa3d104..8e6d5ddc6f674 100644 --- a/docs/standard/security/decrypting-data.md +++ b/docs/standard/security/decrypting-data.md @@ -55,7 +55,9 @@ For information on how to store an asymmetric key in secure cryptographic key co The following example illustrates the decryption of two arrays of bytes that represent a symmetric key and IV. For information on how to extract the asymmetric public key from the object in a format that you can easily send to a third party, see [Encrypting Data](encrypting-data.md#asymmetric-encryption). ```vb -'Create a new instance of the RSA class. +'Create a new instance of the RSA class. The 2048-bit key size shown +'here is for illustration; choose a key size that matches your +'security requirements per NIST SP 800-57. Dim rsa As RSA = RSA.Create(2048) ' Export the public key information and send it to a third party. @@ -67,7 +69,9 @@ symmetricIV = rsa.Decrypt(encryptedSymmetricIV, RSAEncryptionPadding.OaepSHA256) ``` ```csharp -// Create a new instance of the RSA class with at least 2048-bit key size. +// Create a new instance of the RSA class. The 2048-bit key size shown +// here is for illustration; choose a key size that matches your +// security requirements per NIST SP 800-57. RSA rsa = RSA.Create(2048); // Export the public key information and send it to a third party. diff --git a/docs/standard/security/encrypting-data.md b/docs/standard/security/encrypting-data.md index 889ab96d41028..0bc5db86cf05f 100644 --- a/docs/standard/security/encrypting-data.md +++ b/docs/standard/security/encrypting-data.md @@ -64,7 +64,7 @@ The encryption failed. Asymmetric algorithms are usually used to encrypt small amounts of data such as the encryption of a symmetric key and IV. Typically, an individual performing asymmetric encryption uses the public key generated by another party. The class is provided by .NET for this purpose. -The following example uses public key information to encrypt a symmetric key and IV. An key pair is generated with a minimum key size of 2048 bits. The public key from one party is used to encrypt the symmetric key and IV generated by an instance, using OAEP padding for security. +The following example uses public key information to encrypt a symmetric key and IV. An key pair is generated (the 2048-bit key size shown is for illustration—choose a size that matches your security requirements per [NIST SP 800-57](https://csrc.nist.gov/pubs/sp/800/57/pt1/r5/final)). The public key from one party is used to encrypt the symmetric key and IV generated by an instance, using OAEP padding for security. > [!IMPORTANT] > Use (or higher) instead of . PKCS#1 v1.5 padding is deprecated for new systems per [NIST SP 800-56B](https://csrc.nist.gov/pubs/sp/800/56b/r2/final). Use RSA key sizes of at least 2048 bits per [NIST SP 800-57](https://csrc.nist.gov/pubs/sp/800/57/pt1/r5/final). @@ -76,7 +76,9 @@ Imports System.Security.Cryptography Module Module1 Sub Main() - 'Create a new RSA key pair with at least 2048-bit key size. + 'Create a new RSA key pair. The 2048-bit key size shown here is + 'for illustration; choose a key size that matches your security + 'requirements per NIST SP 800-57. Dim rsa As RSA = RSA.Create(2048) 'Create a new instance of the default Aes implementation class. @@ -98,7 +100,9 @@ class Class1 { static void Main() { - // Create a new RSA key pair with at least 2048-bit key size. + // Create a new RSA key pair. The 2048-bit key size shown here is + // for illustration; choose a key size that matches your security + // requirements per NIST SP 800-57. RSA rsa = RSA.Create(2048); // Create a new instance of the default Aes implementation class. From 230965503c3ada8df0f54d95ab17c39610a2c951 Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Wed, 15 Apr 2026 21:57:00 -0700 Subject: [PATCH 14/21] Modernize hardware encryption sample: SHA-1 to SHA-256, add disposal Update the smart card signing sample to use SHA-256 instead of SHA-1, using the HashAlgorithmName/RSASignaturePadding overloads of SignData and VerifyData. Add proper using/Using disposal for RSACryptoServiceProvider. Replace the hand-wave legacy warning with a factual NOTE explaining that CspParameters and RSACryptoServiceProvider are Windows-specific CAPI APIs. Add note that RNGCryptoServiceProvider remains necessary for hardware RNG access but is obsolete for software RNG. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- ...w-to-access-hardware-encryption-devices.md | 10 +++----- .../Cryptography.SmartCardCSP/CS/example.cs | 6 ++--- .../Cryptography.SmartCardCSP/VB/example.vb | 24 +++++++++---------- 3 files changed, 17 insertions(+), 23 deletions(-) diff --git a/docs/standard/security/how-to-access-hardware-encryption-devices.md b/docs/standard/security/how-to-access-hardware-encryption-devices.md index ca7b8b3f5eed5..fa5d08ba26d4f 100644 --- a/docs/standard/security/how-to-access-hardware-encryption-devices.md +++ b/docs/standard/security/how-to-access-hardware-encryption-devices.md @@ -16,10 +16,7 @@ helpviewer_keywords: # How to: Access hardware encryption devices > [!NOTE] -> This article applies to Windows. - -> [!WARNING] -> This article uses legacy APIs ( and ). is obsolete starting in .NET 6 (SYSLIB0023). is a legacy API, though not itself obsolete; specific members are obsolete in later .NET versions. For new code, use and instead. The code sample also uses SHA-1 for signing, which is no longer considered secure—use a current FIPS-approved hash algorithm. +> This article applies to Windows. The and classes are Windows-specific APIs for accessing CAPI-based hardware cryptographic providers such as smart cards. You can use the class to access hardware encryption devices. For example, you can use this class to integrate your application with a smart card, a hardware random number generator, or a hardware implementation of a particular cryptographic algorithm. @@ -39,15 +36,14 @@ The class creates a cryptograp 1. Create a new instance of the class, passing the integer provider type and the provider name to the constructor. -2. Create a new instance of the , passing the object to the constructor. +2. Create a new instance of the , passing the object to the constructor. Note that is obsolete starting in .NET 6 (SYSLIB0023); however, it remains necessary for targeting a specific CAPI-based hardware random number generator. For software-based random number generation, use instead. 3. Create a random value using the or method. ## Example -The following code example demonstrates how to sign data using a smart card. The code example creates a object that exposes a smart card, and then initializes an object using the CSP. The code example then signs and verifies some data. +The following code example demonstrates how to sign data using a smart card. The code example creates a object that exposes a smart card, and then initializes an object using the CSP. The code example then signs and verifies some data using SHA-256. -Due to collision problems with SHA1, we recommend SHA256 or better. [!code-csharp[Cryptography.SmartCardCSP#1](../../../samples/snippets/csharp/VS_Snippets_CLR/Cryptography.SmartCardCSP/CS/example.cs#1)] [!code-vb[Cryptography.SmartCardCSP#1](../../../samples/snippets/visualbasic/VS_Snippets_CLR/Cryptography.SmartCardCSP/VB/example.vb#1)] diff --git a/samples/snippets/csharp/VS_Snippets_CLR/Cryptography.SmartCardCSP/CS/example.cs b/samples/snippets/csharp/VS_Snippets_CLR/Cryptography.SmartCardCSP/CS/example.cs index d51e3b9cc93c6..7263d406cbd25 100644 --- a/samples/snippets/csharp/VS_Snippets_CLR/Cryptography.SmartCardCSP/CS/example.cs +++ b/samples/snippets/csharp/VS_Snippets_CLR/Cryptography.SmartCardCSP/CS/example.cs @@ -24,7 +24,7 @@ static void Main(string[] args) // Initialize an RSACryptoServiceProvider object using // the CspParameters object. - RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(csp); + using RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(csp); // Create some data to sign. byte[] data = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 }; @@ -32,12 +32,12 @@ static void Main(string[] args) Console.WriteLine("Data : " + BitConverter.ToString(data)); // Sign the data using the Smart Card CryptoGraphic Provider. - byte[] sig = rsa.SignData(data, "SHA1"); + byte[] sig = rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); Console.WriteLine("Signature : " + BitConverter.ToString(sig)); // Verify the data using the Smart Card CryptoGraphic Provider. - bool verified = rsa.VerifyData(data, "SHA1", sig); + bool verified = rsa.VerifyData(data, sig, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); Console.WriteLine("Verified : " + verified); } diff --git a/samples/snippets/visualbasic/VS_Snippets_CLR/Cryptography.SmartCardCSP/VB/example.vb b/samples/snippets/visualbasic/VS_Snippets_CLR/Cryptography.SmartCardCSP/VB/example.vb index e006c90f905c1..b1c570be8bfa4 100644 --- a/samples/snippets/visualbasic/VS_Snippets_CLR/Cryptography.SmartCardCSP/VB/example.vb +++ b/samples/snippets/visualbasic/VS_Snippets_CLR/Cryptography.SmartCardCSP/VB/example.vb @@ -1,8 +1,6 @@ ' Imports System.Security.Cryptography - - Module SCSign Sub Main(ByVal args() As String) @@ -20,23 +18,23 @@ Module SCSign ' Initialize an RSACryptoServiceProvider object using ' the CspParameters object. - Dim rsa As New RSACryptoServiceProvider(csp) - - ' Create some data to sign. - Dim data() As Byte = {0, 1, 2, 3, 4, 5, 6, 7} + Using rsa As New RSACryptoServiceProvider(csp) + ' Create some data to sign. + Dim data() As Byte = {0, 1, 2, 3, 4, 5, 6, 7} - Console.WriteLine("Data : " + BitConverter.ToString(data)) + Console.WriteLine("Data : " + BitConverter.ToString(data)) - ' Sign the data using the Smart Card CryptoGraphic Provider. - Dim sig As Byte() = rsa.SignData(data, "SHA1") + ' Sign the data using the Smart Card CryptoGraphic Provider. + Dim sig As Byte() = rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1) - Console.WriteLine("Signature : " + BitConverter.ToString(sig)) + Console.WriteLine("Signature : " + BitConverter.ToString(sig)) - ' Verify the data using the Smart Card CryptoGraphic Provider. - Dim verified As Boolean = rsa.VerifyData(data, "SHA1", sig) + ' Verify the data using the Smart Card CryptoGraphic Provider. + Dim verified As Boolean = rsa.VerifyData(data, sig, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1) - Console.WriteLine("Verified") + Console.WriteLine("Verified : " + verified.ToString()) + End Using End Sub From cc3f5e893acaf5a1813adea31fe463ef8d851d22 Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Wed, 15 Apr 2026 22:02:57 -0700 Subject: [PATCH 15/21] Remove remaining AES-GCM reference and soften algorithm recommendations - Remove AES-GCM mention from XML encryption note (missed in earlier pass). - Remove specific 'SHA-256' mention from hardware encryption example description. - Reword SHA-2 prose in cryptographic-services.md to avoid framing it as a recommendation; instead note it as the FIPS-approved replacement .NET provides. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/standard/security/cryptographic-services.md | 2 +- .../security/how-to-access-hardware-encryption-devices.md | 2 +- .../security/how-to-encrypt-xml-elements-with-symmetric-keys.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/standard/security/cryptographic-services.md b/docs/standard/security/cryptographic-services.md index 05de6eeaba799..2f9d18214ea7f 100644 --- a/docs/standard/security/cryptographic-services.md +++ b/docs/standard/security/cryptographic-services.md @@ -177,7 +177,7 @@ None of the previous methods will prevent someone from reading Alice's messages, - . -.NET also provides and for standards conformance and backward compatibility with existing data formats and protocols. However, the MD5 and SHA-1 algorithms have been found to be insecure, and SHA-2 is now recommended instead per [NIST SP 800-131A](https://csrc.nist.gov/pubs/sp/800/131a/r2/final). SHA-2 includes SHA256, SHA384, and SHA512. +.NET also provides and for standards conformance and backward compatibility with existing data formats and protocols. However, the MD5 and SHA-1 algorithms have been found to be insecure per [NIST SP 800-131A](https://csrc.nist.gov/pubs/sp/800/131a/r2/final). .NET provides the FIPS-approved SHA-2 family (SHA256, SHA384, and SHA512) as replacements. > [!WARNING] > Do not use MD5 or SHA-1 for security-sensitive purposes such as digital signatures or certificate validation, unless required by an existing data format standard. Use a current FIPS-approved hash algorithm for new development. diff --git a/docs/standard/security/how-to-access-hardware-encryption-devices.md b/docs/standard/security/how-to-access-hardware-encryption-devices.md index fa5d08ba26d4f..fedfddd0591cd 100644 --- a/docs/standard/security/how-to-access-hardware-encryption-devices.md +++ b/docs/standard/security/how-to-access-hardware-encryption-devices.md @@ -42,7 +42,7 @@ The class creates a cryptograp ## Example -The following code example demonstrates how to sign data using a smart card. The code example creates a object that exposes a smart card, and then initializes an object using the CSP. The code example then signs and verifies some data using SHA-256. +The following code example demonstrates how to sign data using a smart card. The code example creates a object that exposes a smart card, and then initializes an object using the CSP. The code example then signs and verifies some data. [!code-csharp[Cryptography.SmartCardCSP#1](../../../samples/snippets/csharp/VS_Snippets_CLR/Cryptography.SmartCardCSP/CS/example.cs#1)] [!code-vb[Cryptography.SmartCardCSP#1](../../../samples/snippets/visualbasic/VS_Snippets_CLR/Cryptography.SmartCardCSP/VB/example.vb#1)] diff --git a/docs/standard/security/how-to-encrypt-xml-elements-with-symmetric-keys.md b/docs/standard/security/how-to-encrypt-xml-elements-with-symmetric-keys.md index b33af8fd20fc2..aa7efb79c3328 100644 --- a/docs/standard/security/how-to-encrypt-xml-elements-with-symmetric-keys.md +++ b/docs/standard/security/how-to-encrypt-xml-elements-with-symmetric-keys.md @@ -22,7 +22,7 @@ ms.assetid: d8461a44-aa2c-4ef4-b3e4-ab7cbaaee1b5 You can use the classes in the namespace to encrypt an element within an XML document. XML Encryption allows you to store or transport sensitive XML, without worrying about the data being easily read. This procedure encrypts an XML element using the Advanced Encryption Standard (AES) algorithm. > [!NOTE] -> The XML Encryption 1.0 standard uses CBC mode by default, which doesn't provide authentication. For scenarios that require strong integrity guarantees, consider using an Encrypt-then-Sign approach or using XML Encryption 1.1 with AES-GCM where supported. For more information, see [Timing vulnerabilities with CBC-mode symmetric decryption using padding](vulnerabilities-cbc-mode.md). +> The XML Encryption 1.0 standard uses CBC mode by default, which doesn't provide authentication. For scenarios that require strong integrity guarantees, consider using an Encrypt-then-Sign approach. For more information, see [Timing vulnerabilities with CBC-mode symmetric decryption using padding](vulnerabilities-cbc-mode.md). For information about how to decrypt an XML element that was encrypted using this procedure, see [How to: Decrypt XML Elements with Symmetric Keys](how-to-decrypt-xml-elements-with-symmetric-keys.md). From 1e65834fef965f48f6bff3f80acab65745afc943 Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Wed, 15 Apr 2026 22:23:44 -0700 Subject: [PATCH 16/21] Align broader security docs with current NIST guidance Clarify that TLS 1.2 is the current baseline and TLS 1.3 is preferred when available, mark legacy TLS/WCF settings as compatibility-only, distinguish crypto support matrices from recommendations, and point new password-based key derivation guidance toward modern APIs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/core/extensions/sslstream-best-practices.md | 6 +++--- .../file-schema/wcf/sslstreamsecurity.md | 5 ++++- .../migration-guide/mitigation-tls-protocols.md | 11 +++++++---- docs/framework/network-programming/tls.md | 14 +++++++------- .../code-analysis/quality-rules/ca5358.md | 1 + .../code-analysis/quality-rules/ca5361.md | 4 ++-- docs/fundamentals/syslib-diagnostics/syslib0033.md | 4 +++- .../security/cross-platform-cryptography.md | 6 ++++++ 8 files changed, 33 insertions(+), 18 deletions(-) diff --git a/docs/core/extensions/sslstream-best-practices.md b/docs/core/extensions/sslstream-best-practices.md index 63f23da8dfd3f..038623db3dea3 100644 --- a/docs/core/extensions/sslstream-best-practices.md +++ b/docs/core/extensions/sslstream-best-practices.md @@ -16,11 +16,11 @@ This article presents best practices for setting up secure communication between While it is possible to specify the version of the TLS protocol to be used via the property, it is recommended to defer to the operating system settings by using value (this is the default). -Deferring the decision to the OS automatically uses the most recent version of TLS available and lets the application pick up changes after OS upgrades. The operating system may also prevent use of TLS versions which are no longer considered secure. +Deferring the decision to the OS automatically uses the most recent version of TLS available and lets the application pick up changes after OS upgrades. The operating system may also prevent use of TLS versions which are no longer considered secure. This approach aligns with [NIST SP 800-52 Rev. 2](https://csrc.nist.gov/pubs/sp/800/52/r2/final), which requires TLS 1.2 and recommends TLS 1.3 when available. ## Select cipher suites -`SslStream` allows users to specify which cipher suites can be negotiated by the TLS handshake via the class. As with TLS versions, it's recommended to let the OS decide which are the best cipher suites to negotiate with, and, therefore, it's recommended to avoid using . +`SslStream` allows users to specify which cipher suites can be negotiated by the TLS handshake via the class. As with TLS versions, it's recommended to let the OS decide which are the best cipher suites to negotiate with, and avoid using unless you have a specific interoperability requirement. > [!NOTE] > is not supported on Windows and attempts to instantiate it will cause to be thrown. @@ -37,7 +37,7 @@ There are multiple ways that a server certificate can be passed to property. When the certificate is obtained by one of the other two ways, a instance is created internally by the implementation. Creating a involves building an which is a CPU intensive operation. It is more efficient to create a once and reuse it for multiple instances. -Reusing instances also enables additional features such us [TLS session resumption](https://datatracker.ietf.org/doc/html/rfc5077) on Linux servers. +Reusing instances also enables additional features such as [TLS session resumption](https://datatracker.ietf.org/doc/html/rfc5077) on Linux servers. ## Custom `X509Certificate` validation diff --git a/docs/framework/configure-apps/file-schema/wcf/sslstreamsecurity.md b/docs/framework/configure-apps/file-schema/wcf/sslstreamsecurity.md index e5429151cdc96..a3770fb855d77 100644 --- a/docs/framework/configure-apps/file-schema/wcf/sslstreamsecurity.md +++ b/docs/framework/configure-apps/file-schema/wcf/sslstreamsecurity.md @@ -22,6 +22,9 @@ Represents a custom binding element that supports channel security using an SSL sslProtocols="Ssl3|Tls|Tls11|Tls12" /> ``` +> [!IMPORTANT] +> The syntax shows the full historical enum surface for the `sslProtocols` attribute. For new configurations, don't enable `Ssl3`, `Tls`, or `Tls11`. Prefer OS defaults, or limit the configuration to modern TLS versions supported by your target platform. For more information, see [Transport Layer Security (TLS) best practices with the .NET Framework](../../../network-programming/tls.md). + ## Attributes and Elements The following sections describe attributes, child elements, and parent elements. @@ -31,7 +34,7 @@ Represents a custom binding element that supports channel security using an SSL |Attribute|Description| |---------------|-----------------| |requireClientCertificate|A Boolean value that specifies if a client certificate is required for this binding. The default is `false`.| -|sslProtocols|A SslProtocols enum flag value that specifies which SslProtocols are supported. The default is Ssl3|Tls|Tls11|Tls12.| +|sslProtocols|A SslProtocols enum flag value that specifies which SslProtocols are supported. The default is Ssl3|Tls|Tls11|Tls12. This historical default exists for compatibility and isn't recommended for new configurations.| ### Child Elements diff --git a/docs/framework/migration-guide/mitigation-tls-protocols.md b/docs/framework/migration-guide/mitigation-tls-protocols.md index 7695302dc86ce..6499394d4b2f2 100644 --- a/docs/framework/migration-guide/mitigation-tls-protocols.md +++ b/docs/framework/migration-guide/mitigation-tls-protocols.md @@ -9,7 +9,10 @@ ms.assetid: 33f97d13-3022-43da-8b18-cdb5c88df9c2 --- # Mitigation: TLS Protocols -Starting with .NET Framework 4.6, the and classes are allowed to use one of the following three protocols: Tls1.0, Tls1.1, or Tls 1.2. The SSL3.0 protocol and RC4 cipher are not supported. +Starting with .NET Framework 4.6, the and classes negotiate TLS 1.0, TLS 1.1, or TLS 1.2 based on OS support. The SSL 3.0 protocol and RC4 cipher are not supported. + +> [!WARNING] +> This article documents a legacy compatibility change in .NET Framework 4.6. For current deployments, use operating system defaults and allow only TLS 1.2 or TLS 1.3 when available. For more information, see [Transport Layer Security (TLS) best practices with the .NET Framework](../network-programming/tls.md). ## Impact @@ -17,11 +20,11 @@ Starting with .NET Framework 4.6, the , , , , and . -- Any server-side app that cannot be upgraded to support Tls1.0, Tls1.1, or Tls 1.2.. +- Any server-side app that cannot be upgraded to support modern TLS configurations, ideally TLS 1.2 or later. ## Mitigation - The recommended mitigation is to upgrade the sever-side app to Tls1.0, Tls1.1, or Tls 1.2. If this is not feasible, or if client apps are broken, the class can be used to opt out of this feature in either of two ways: + The recommended mitigation is to upgrade the server-side app to support modern TLS configurations. If that isn't feasible, or if client apps are broken, the class can be used to opt out of this feature in either of two ways as a temporary compatibility workaround: - Programmatically, by using a code snippet like the following: @@ -36,7 +39,7 @@ Starting with .NET Framework 4.6, the ``` - Note, however, that opting out of the default behavior is not recommended, since it makes the application less secure. + Note, however, that opting out of the default behavior is not recommended, since it makes the application less secure. ## See also diff --git a/docs/framework/network-programming/tls.md b/docs/framework/network-programming/tls.md index 87edb79dcd544..62fc8e1bb06c8 100644 --- a/docs/framework/network-programming/tls.md +++ b/docs/framework/network-programming/tls.md @@ -24,7 +24,7 @@ helpviewer_keywords: ## What is Transport Layer Security (TLS)? > [!WARNING] -> TLS 1.0 and 1.1 has been deprecated by [RFC8996](https://datatracker.ietf.org/doc/rfc8996/). This document covers TLS 1.2 and TLS 1.3 only. +> TLS 1.0 and TLS 1.1 have been deprecated by [RFC 8996](https://datatracker.ietf.org/doc/rfc8996/). Current [NIST SP 800-52 Rev. 2](https://csrc.nist.gov/pubs/sp/800/52/r2/final) guidance requires TLS 1.2 and recommends TLS 1.3 when available. This document covers TLS 1.2 and TLS 1.3 only. The Transport Layer Security (TLS) protocol is an industry latest version of the standard designed to help protect the privacy of information communicated over the Internet. [TLS 1.3](https://tools.ietf.org/html/rfc8446) is a standard that provides security improvements over previous versions. This article presents recommendations to secure .NET Framework applications that use the TLS protocol. @@ -70,7 +70,7 @@ When your app lets the OS choose the TLS version: This article explains how to enable the strongest security available for the version of .NET Framework that your app targets and runs on. When an app explicitly sets a security protocol and version, it opts out of any other alternative, and opts out of .NET Framework and OS default behavior. If you want your app to be able to negotiate a TLS 1.3 connection, explicitly setting to a lower TLS version prevents a TLS 1.3 connection. -If you can't avoid specifying a protocol version explicitly, we strongly recommend that you specify TLS 1.2 or TLS 1.3 (which is `currently considered secure`). For guidance on identifying and removing TLS 1.0 dependencies, download the [Solving the TLS 1.0 Problem](https://www.microsoft.com/download/details.aspx?id=55266) white paper. +If you can't avoid specifying a protocol version explicitly, allow only TLS 1.2 or TLS 1.3. Prefer TLS 1.3 when the operating system and peer support it. For guidance on identifying and removing TLS 1.0 dependencies, download the [Solving the TLS 1.0 Problem](https://www.microsoft.com/download/details.aspx?id=55266) white paper. WCF supports TLS 1.2 as the default in .NET Framework 4.7. Starting with .NET Framework 4.7.1, WCF defaults to the operating system configured version. If an application is explicitly configured with `SslProtocols.None`, WCF uses the operating system default setting when using the NetTcp transport. @@ -139,7 +139,7 @@ Because the defaults to the security protocol and version chosen by the OS. To get the default OS best choice, if possible, don't use the method overloads of that take an explicit parameter. Otherwise, pass . We recommend that you don't use ; setting `SslProtocols.Default` forces the use of SSL 3.0 /TLS 1.0 and prevents TLS 1.2. + defaults to the security protocol and version chosen by the OS. To get the default OS best choice, if possible, don't use the method overloads of that take an explicit parameter. Otherwise, pass . We recommend that you don't use ; setting `SslProtocols.Default` forces the use of SSL 3.0 /TLS 1.0 and prevents negotiation of newer versions. Don't set a value for the property (for HTTP networking). @@ -160,7 +160,7 @@ If you're targeting 4.7.1, WCF is configured to allow the OS to choose the best - In your application configuration file. - **Or**, in your application in the source code. -By default, .NET Framework 4.7 and later versions are configured to use TLS 1.2 and allow connections using TLS 1.1 or TLS 1.0. Configure WCF to allow the OS to choose the best security protocol by configuring your binding to use . You can set this on . `SslProtocols.None` can be accessed from . `NetTcpSecurity.Transport` can be accessed from . +By default, .NET Framework 4.7 and later versions are configured to use TLS 1.2 and allow connections using TLS 1.1 or TLS 1.0. Don't rely on those older protocols. Configure WCF to allow the OS to choose the best security protocol by configuring your binding to use . You can set this on . `SslProtocols.None` can be accessed from . `NetTcpSecurity.Transport` can be accessed from . If you're using a custom binding: @@ -171,7 +171,7 @@ If you're **not** using a custom binding **and** you're setting your WCF binding #### Using Message Security with certificate credentials -.NET Framework 4.7 and later versions by default use the protocol specified in the property. When the [AppContextSwitch](../configure-apps/file-schema/runtime/appcontextswitchoverrides-element.md) `Switch.System.ServiceModel.DisableUsingServicePointManagerSecurityProtocols` is set to `true`, WCF chooses the best protocol, up to TLS 1.0. +.NET Framework 4.7 and later versions by default use the protocol specified in the property. When the [AppContextSwitch](../configure-apps/file-schema/runtime/appcontextswitchoverrides-element.md) `Switch.System.ServiceModel.DisableUsingServicePointManagerSecurityProtocols` is set to `true`, WCF chooses the best protocol, up to TLS 1.0. That compatibility path is for legacy scenarios and doesn't satisfy current security guidance. #### [.NET Framework 4.6.2 and earlier](#tab/462-minus) @@ -191,7 +191,7 @@ The switches have the same effect whether you're doing HTTP networking (, ). +- If you use CBC-based encryption, validate integrity before you decrypt. For more information, see [Timing vulnerabilities with CBC-mode symmetric decryption using padding](../../../standard/security/vulnerabilities-cbc-mode.md). ## When to suppress warnings diff --git a/docs/fundamentals/code-analysis/quality-rules/ca5361.md b/docs/fundamentals/code-analysis/quality-rules/ca5361.md index c49f5796a0dcb..ac1b94244a7d3 100644 --- a/docs/fundamentals/code-analysis/quality-rules/ca5361.md +++ b/docs/fundamentals/code-analysis/quality-rules/ca5361.md @@ -30,7 +30,7 @@ By default, this rule analyzes the entire codebase, but this is [configurable](# ## Rule description -Setting `Switch.System.Net.DontEnableSchUseStrongCrypto` to `true` weakens the cryptography used in outgoing Transport Layer Security (TLS) connections. Weaker cryptography can compromise the confidentiality of communication between your application and the server, making it easier for attackers to eavesdrop sensitive data. For more information, see [Transport Layer Security (TLS) best practices with .NET Framework](../../../framework/network-programming/tls.md#switchsystemnetdontenableschusestrongcrypto). +Setting `Switch.System.Net.DontEnableSchUseStrongCrypto` to `true` weakens the cryptography used in outgoing Transport Layer Security (TLS) connections. Weaker cryptography can compromise the confidentiality of communication between your application and the server, making it easier for attackers to eavesdrop sensitive data. Current guidance in [NIST SP 800-52 Rev. 2](https://csrc.nist.gov/pubs/sp/800/52/r2/final) requires TLS 1.2 and recommends TLS 1.3 when available. For more information, see [Transport Layer Security (TLS) best practices with .NET Framework](../../../framework/network-programming/tls.md#switchsystemnetdontenableschusestrongcrypto). ## How to fix violations @@ -40,7 +40,7 @@ Setting `Switch.System.Net.DontEnableSchUseStrongCrypto` to `true` weakens the c ## When to suppress warnings -You can suppress this warning if you need to connect to a legacy service that can't be upgraded to use secure TLS configurations. +You can suppress this warning only if you must connect to a legacy service that can't yet be upgraded to use TLS 1.2 or later. Treat that suppression as a temporary compatibility measure. ## Suppress a warning diff --git a/docs/fundamentals/syslib-diagnostics/syslib0033.md b/docs/fundamentals/syslib-diagnostics/syslib0033.md index 1c810a06bf3a9..15464ff202667 100644 --- a/docs/fundamentals/syslib-diagnostics/syslib0033.md +++ b/docs/fundamentals/syslib-diagnostics/syslib0033.md @@ -11,7 +11,9 @@ The instead. +If you need compatibility with an existing CryptoAPI-based format or protocol, use . + +For new development, derive key material directly with or , and then assign the result to the algorithm you're using. When you derive keys from passwords, use a unique salt and an iteration count that fits your performance budget, as described in [NIST SP 800-132](https://csrc.nist.gov/pubs/sp/800/132/final). ## Suppress a warning diff --git a/docs/standard/security/cross-platform-cryptography.md b/docs/standard/security/cross-platform-cryptography.md index 78c7f7564c417..e97bcce5a9f1a 100644 --- a/docs/standard/security/cross-platform-cryptography.md +++ b/docs/standard/security/cross-platform-cryptography.md @@ -19,6 +19,9 @@ The dependency on OS libraries also means that .NET apps can only use cryptograp This article assumes you have a working familiarity with cryptography in .NET. For more information, see [.NET Cryptography Model](cryptography-model.md) and [.NET Cryptographic Services](cryptographic-services.md). +> [!IMPORTANT] +> The following tables show platform support, not recommendations for new development. Some algorithms and modes remain available for standards conformance and backward compatibility even though current guidance deprecates them for new systems. For example, [NIST SP 800-131A](https://csrc.nist.gov/pubs/sp/800/131a/r2/final) deprecates MD5, SHA-1 for digital signatures, DES, and 3DES. + ## Hash and Message Authentication Algorithms All hash algorithm and hash-based message authentication (HMAC) classes, including the `*Managed` classes, defer to the OS libraries with the exception of .NET on Browser WASM. In Browser WASM, SHA-1, SHA-2-256, SHA-2-384, SHA-2-512 and the HMAC equivalents are implemented using managed code. @@ -155,6 +158,9 @@ Padding and digest support vary by platform: | PKCS1 Signature (SHA-3) | Windows 11 Build 25324+ | OpenSSL 1.1.1+ | ❌ | ❌ | ❌ | ❌ | | PSS | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ❌ | +> [!NOTE] +> Support for OAEP-SHA1 and PKCS#1 signatures with MD5 or SHA-1 is listed for compatibility with existing protocols and data formats. For new development, use current FIPS-approved hash algorithms and padding choices that your protocol or standard requires. + 1 Windows CryptoAPI (CAPI) is capable of PKCS1 signature with a SHA-2 algorithm. But the individual RSA object may be loaded in a cryptographic service provider (CSP) that doesn't support it. #### RSA on Windows From ea7660915d32da5c2d1286cd29470c39280f6184 Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Wed, 15 Apr 2026 22:26:36 -0700 Subject: [PATCH 17/21] Tighten remaining security compatibility docs Clarify legacy SSL/TLS wording and align the remaining PBKDF obsoletion summaries with the updated security guidance. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../network-programming/using-secure-sockets-layer.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/framework/network-programming/using-secure-sockets-layer.md b/docs/framework/network-programming/using-secure-sockets-layer.md index 6e434421bc1f4..dcdf8db99dc18 100644 --- a/docs/framework/network-programming/using-secure-sockets-layer.md +++ b/docs/framework/network-programming/using-secure-sockets-layer.md @@ -19,7 +19,10 @@ ms.assetid: 6e4289e6-d1b7-4e82-ab0d-e83e3b6063ed --- # Using Secure Sockets Layer -The classes use the Secure Sockets Layer (SSL) to encrypt the connection for several network protocols. +> [!WARNING] +> This article uses the historical "SSL" terminology from older .NET Framework APIs. For current guidance, use TLS rather than older SSL protocols, and prefer OS defaults. For more information, see [Transport Layer Security (TLS) best practices with the .NET Framework](tls.md). + +The classes use Transport Layer Security (TLS), historically referred to as Secure Sockets Layer (SSL), to encrypt the connection for several network protocols. For http connections, the and classes use SSL to communicate with web hosts that support SSL. The decision to use SSL is made by the class, based on the URI it is given. If the URI begins with "https:", SSL is used; if the URI begins with "http:", an unencrypted connection is used. From a812155b32989b78aeb8313aacdc6ea5ab839c65 Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Wed, 15 Apr 2026 22:59:34 -0700 Subject: [PATCH 18/21] Remove remaining AES-GCM recommendations Neutralize the last recommendation-style AES-GCM wording so the repo stays consistent with the broader cryptography guidance, while leaving factual API and compatibility documentation intact. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../cryptography/10.0/openssl-macos-unsupported.md | 2 +- docs/standard/security/vulnerabilities-cbc-mode.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/core/compatibility/cryptography/10.0/openssl-macos-unsupported.md b/docs/core/compatibility/cryptography/10.0/openssl-macos-unsupported.md index c4840d1e52e3c..4a22700dfdaf1 100644 --- a/docs/core/compatibility/cryptography/10.0/openssl-macos-unsupported.md +++ b/docs/core/compatibility/cryptography/10.0/openssl-macos-unsupported.md @@ -46,7 +46,7 @@ If you're using OpenSSL-backed primitives without any specific intention of usin * `new ECDsaOpenSsl(...)` -> `ECDsa.Create(...)` * `new RSAOpenSsl(...)` -> `RSA.Create(...)` - has no functional equivalent on macOS. Consider using a different cryptographic primitive, such as , instead. + has no functional equivalent on macOS. If you need equivalent functionality, choose a supported cryptographic primitive that matches your protocol and compatibility requirements. ## Affected APIs diff --git a/docs/standard/security/vulnerabilities-cbc-mode.md b/docs/standard/security/vulnerabilities-cbc-mode.md index 4281cf6267773..86dcc878ea602 100644 --- a/docs/standard/security/vulnerabilities-cbc-mode.md +++ b/docs/standard/security/vulnerabilities-cbc-mode.md @@ -70,7 +70,7 @@ First and foremost, Microsoft recommends that any data that has confidentiality Next, analyze your application to: - Understand precisely what encryption you're performing and what encryption is being provided by the platforms and APIs you're using. -- Be certain that each usage at each layer of a symmetric [block cipher algorithm](https://en.wikipedia.org/wiki/Block_cipher#Notable_block_ciphers), such as AES and 3DES, in CBC mode incorporate the use of a secret-keyed data integrity check (an asymmetric signature, an HMAC, or to change the cipher mode to an [authenticated encryption](https://en.wikipedia.org/wiki/Authenticated_encryption) (AE) mode such as GCM or CCM). +- Be certain that each usage at each layer of a symmetric [block cipher algorithm](https://en.wikipedia.org/wiki/Block_cipher#Notable_block_ciphers), such as AES and 3DES, in CBC mode incorporate the use of a secret-keyed data integrity check, such as an asymmetric signature, an HMAC, or another authenticated-encryption design that provides integrity protection. Based on the current research, it's generally believed that when the authentication and encryption steps are performed independently for non-AE modes of encryption, authenticating the ciphertext (encrypt-then-sign) is the best general option. However, there's no one-size-fits-all correct answer to cryptography and this generalization isn't as good as directed advice from a professional cryptographer. From 2840c506ff9b7e2832d921d7eb3e868f09c4ada4 Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Wed, 15 Apr 2026 23:19:48 -0700 Subject: [PATCH 19/21] Fix DPAPI sample analyzer failures Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../VS_Snippets_CLR/DPAPI-HowTO/cs/sample.cs | 14 ++++++++++- .../VS_Snippets_CLR/DPAPI-HowTO/vb/sample.vb | 24 +++++++++++++------ 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/samples/snippets/csharp/VS_Snippets_CLR/DPAPI-HowTO/cs/sample.cs b/samples/snippets/csharp/VS_Snippets_CLR/DPAPI-HowTO/cs/sample.cs index 8553b67ac4c4a..b10e806e7f5d1 100644 --- a/samples/snippets/csharp/VS_Snippets_CLR/DPAPI-HowTO/cs/sample.cs +++ b/samples/snippets/csharp/VS_Snippets_CLR/DPAPI-HowTO/cs/sample.cs @@ -161,7 +161,19 @@ public static byte[] DecryptDataFromStream(byte[] Entropy, DataProtectionScope S // Read the encrypted data from a stream. if (S.CanRead) { - S.Read(inBuffer, 0, Length); + int offset = 0; + + while (offset < Length) + { + int bytesRead = S.Read(inBuffer, offset, Length - offset); + + if (bytesRead == 0) + { + throw new EndOfStreamException("Could not read the expected number of bytes from the stream."); + } + + offset += bytesRead; + } outBuffer = ProtectedData.Unprotect(inBuffer, Entropy, Scope); } diff --git a/samples/snippets/visualbasic/VS_Snippets_CLR/DPAPI-HowTO/vb/sample.vb b/samples/snippets/visualbasic/VS_Snippets_CLR/DPAPI-HowTO/vb/sample.vb index 0cb76ad313a1e..ac168dd12d57f 100644 --- a/samples/snippets/visualbasic/VS_Snippets_CLR/DPAPI-HowTO/vb/sample.vb +++ b/samples/snippets/visualbasic/VS_Snippets_CLR/DPAPI-HowTO/vb/sample.vb @@ -88,7 +88,7 @@ Public Module MemoryProtectionSample Throw New ArgumentNullException("Buffer") End If If Buffer.Length <= 0 Then - Throw New ArgumentException("Buffer") + Throw New ArgumentException("The buffer length was 0.", NameOf(Buffer)) End If ' Encrypt the data in memory. The result is stored in the same array as the original data. @@ -102,7 +102,7 @@ Public Module MemoryProtectionSample Throw New ArgumentNullException("Buffer") End If If Buffer.Length <= 0 Then - Throw New ArgumentException("Buffer") + Throw New ArgumentException("The buffer length was 0.", NameOf(Buffer)) End If ' Decrypt the data in memory. The result is stored in the same array as the original data. @@ -132,13 +132,13 @@ Public Module MemoryProtectionSample Throw New ArgumentNullException("Buffer") End If If Buffer.Length <= 0 Then - Throw New ArgumentException("Buffer") + Throw New ArgumentException("The buffer length was 0.", NameOf(Buffer)) End If If Entropy Is Nothing Then Throw New ArgumentNullException("Entropy") End If If Entropy.Length <= 0 Then - Throw New ArgumentException("Entropy") + Throw New ArgumentException("The entropy length was 0.", NameOf(Entropy)) End If If S Is Nothing Then Throw New ArgumentNullException("S") @@ -166,13 +166,13 @@ Public Module MemoryProtectionSample Throw New ArgumentNullException("S") End If If Length <= 0 Then - Throw New ArgumentException("Length") + Throw New ArgumentException("The given length was 0.", NameOf(Length)) End If If Entropy Is Nothing Then Throw New ArgumentNullException("Entropy") End If If Entropy.Length <= 0 Then - Throw New ArgumentException("Entropy") + Throw New ArgumentException("The entropy length was 0.", NameOf(Entropy)) End If @@ -181,7 +181,17 @@ Public Module MemoryProtectionSample ' Read the encrypted data from a stream. If S.CanRead Then - S.Read(inBuffer, 0, Length) + Dim offset As Integer = 0 + + While offset < Length + Dim bytesRead As Integer = S.Read(inBuffer, offset, Length - offset) + + If bytesRead = 0 Then + Throw New EndOfStreamException("Could not read the expected number of bytes from the stream.") + End If + + offset += bytesRead + End While outBuffer = ProtectedData.Unprotect(inBuffer, Entropy, Scope) Else From 20355a33e8823e941ec985a277b17cf4beb2c067 Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Wed, 15 Apr 2026 23:38:04 -0700 Subject: [PATCH 20/21] Fix CryptoWalkThru partial reads Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../CryptoWalkThru/cs/Form1.cs | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/samples/snippets/csharp/VS_Snippets_CLR/CryptoWalkThru/cs/Form1.cs b/samples/snippets/csharp/VS_Snippets_CLR/CryptoWalkThru/cs/Form1.cs index 44e5878c3f6cd..c3912db973b3b 100644 --- a/samples/snippets/csharp/VS_Snippets_CLR/CryptoWalkThru/cs/Form1.cs +++ b/samples/snippets/csharp/VS_Snippets_CLR/CryptoWalkThru/cs/Form1.cs @@ -35,6 +35,22 @@ public partial class Form1 : Form private void Close_Click(object sender, EventArgs e) => Application.Exit(); + private static void ReadBytesExactly(Stream stream, byte[] buffer, int offset, int count) + { + while (count > 0) + { + int bytesRead = stream.Read(buffer, offset, count); + + if (bytesRead == 0) + { + throw new EndOfStreamException("Could not read the expected number of bytes from the stream."); + } + + offset += bytesRead; + count -= bytesRead; + } + } + #endregion #region Snippet2 - buttonCreateAsmKeys @@ -205,8 +221,8 @@ private void DecryptFile(FileInfo file) // file (inFs) and save the decrypted file (outFs). using (var inFs = new FileStream(file.FullName, FileMode.Open)) { - inFs.ReadExactly(LenK, 0, 4); - inFs.ReadExactly(LenIV, 0, 4); + ReadBytesExactly(inFs, LenK, 0, LenK.Length); + ReadBytesExactly(inFs, LenIV, 0, LenIV.Length); // Convert the lengths to integer values. int lenK = BitConverter.ToInt32(LenK, 0); @@ -228,9 +244,9 @@ private void DecryptFile(FileInfo file) // starting from index 8 // after the length values. inFs.Seek(8, SeekOrigin.Begin); - inFs.Read(KeyEncrypted, 0, lenK); + ReadBytesExactly(inFs, KeyEncrypted, 0, lenK); inFs.Seek(8 + lenK, SeekOrigin.Begin); - inFs.Read(IV, 0, lenIV); + ReadBytesExactly(inFs, IV, 0, lenIV); Directory.CreateDirectory(DecrFolder); // From cb76bf4c0550bc28bbef7312acab184b8517babf Mon Sep 17 00:00:00 2001 From: Jeremy Barton Date: Thu, 16 Apr 2026 17:11:23 -0700 Subject: [PATCH 21/21] Apply feedback (top half) Generally, this revision is removing duplicated warnings and superfluous appeals to authority. --- .../10.0/openssl-macos-unsupported.md | 2 +- .../extensions/sslstream-best-practices.md | 2 +- .../mitigation-tls-protocols.md | 7 ++----- docs/framework/network-programming/tls.md | 12 +++++------ .../using-secure-sockets-layer.md | 3 --- .../code-analysis/quality-rules/ca5361.md | 4 ++-- .../code-analysis/quality-rules/ca5387.md | 6 ++++-- .../code-analysis/quality-rules/ca5388.md | 6 ++++-- .../syslib-diagnostics/syslib0033.md | 2 +- .../syslib-diagnostics/syslib0041.md | 10 +++++----- .../security/cross-platform-cryptography.md | 5 +---- .../security/cryptographic-services.md | 20 +++++-------------- .../security/cryptographic-signatures.md | 9 +++++---- docs/standard/security/cryptography-model.md | 5 +---- .../csharp/Program.cs | 9 ++++++--- .../cryptographic-signatures/vb/Program.vb | 7 +++++-- 16 files changed, 49 insertions(+), 60 deletions(-) diff --git a/docs/core/compatibility/cryptography/10.0/openssl-macos-unsupported.md b/docs/core/compatibility/cryptography/10.0/openssl-macos-unsupported.md index 4a22700dfdaf1..b3a61c0835ba6 100644 --- a/docs/core/compatibility/cryptography/10.0/openssl-macos-unsupported.md +++ b/docs/core/compatibility/cryptography/10.0/openssl-macos-unsupported.md @@ -46,7 +46,7 @@ If you're using OpenSSL-backed primitives without any specific intention of usin * `new ECDsaOpenSsl(...)` -> `ECDsa.Create(...)` * `new RSAOpenSsl(...)` -> `RSA.Create(...)` - has no functional equivalent on macOS. If you need equivalent functionality, choose a supported cryptographic primitive that matches your protocol and compatibility requirements. + has no functional equivalent on macOS. ## Affected APIs diff --git a/docs/core/extensions/sslstream-best-practices.md b/docs/core/extensions/sslstream-best-practices.md index 038623db3dea3..57f60832bcc06 100644 --- a/docs/core/extensions/sslstream-best-practices.md +++ b/docs/core/extensions/sslstream-best-practices.md @@ -16,7 +16,7 @@ This article presents best practices for setting up secure communication between While it is possible to specify the version of the TLS protocol to be used via the property, it is recommended to defer to the operating system settings by using value (this is the default). -Deferring the decision to the OS automatically uses the most recent version of TLS available and lets the application pick up changes after OS upgrades. The operating system may also prevent use of TLS versions which are no longer considered secure. This approach aligns with [NIST SP 800-52 Rev. 2](https://csrc.nist.gov/pubs/sp/800/52/r2/final), which requires TLS 1.2 and recommends TLS 1.3 when available. +Deferring the decision to the OS automatically uses the most recent version of TLS available and lets the application pick up changes after OS upgrades. The operating system may also prevent use of TLS versions which are no longer considered secure. ## Select cipher suites diff --git a/docs/framework/migration-guide/mitigation-tls-protocols.md b/docs/framework/migration-guide/mitigation-tls-protocols.md index 6499394d4b2f2..7d6c38e3190ba 100644 --- a/docs/framework/migration-guide/mitigation-tls-protocols.md +++ b/docs/framework/migration-guide/mitigation-tls-protocols.md @@ -9,10 +9,7 @@ ms.assetid: 33f97d13-3022-43da-8b18-cdb5c88df9c2 --- # Mitigation: TLS Protocols -Starting with .NET Framework 4.6, the and classes negotiate TLS 1.0, TLS 1.1, or TLS 1.2 based on OS support. The SSL 3.0 protocol and RC4 cipher are not supported. - -> [!WARNING] -> This article documents a legacy compatibility change in .NET Framework 4.6. For current deployments, use operating system defaults and allow only TLS 1.2 or TLS 1.3 when available. For more information, see [Transport Layer Security (TLS) best practices with the .NET Framework](../network-programming/tls.md). +Starting with .NET Framework 4.6, the and classes no longer support the SSL 3.0 protocol or the RC4 cipher. ## Impact @@ -20,7 +17,7 @@ Starting with .NET Framework 4.6, the , , , , and . -- Any server-side app that cannot be upgraded to support modern TLS configurations, ideally TLS 1.2 or later. +- Any server-side app that cannot be upgraded to support modern TLS configurations. ## Mitigation diff --git a/docs/framework/network-programming/tls.md b/docs/framework/network-programming/tls.md index 62fc8e1bb06c8..4cf64f4ceb552 100644 --- a/docs/framework/network-programming/tls.md +++ b/docs/framework/network-programming/tls.md @@ -24,7 +24,7 @@ helpviewer_keywords: ## What is Transport Layer Security (TLS)? > [!WARNING] -> TLS 1.0 and TLS 1.1 have been deprecated by [RFC 8996](https://datatracker.ietf.org/doc/rfc8996/). Current [NIST SP 800-52 Rev. 2](https://csrc.nist.gov/pubs/sp/800/52/r2/final) guidance requires TLS 1.2 and recommends TLS 1.3 when available. This document covers TLS 1.2 and TLS 1.3 only. +> TLS 1.0 and TLS 1.1 have been deprecated by [RFC 8996](https://datatracker.ietf.org/doc/rfc8996/). This document covers TLS 1.2 and TLS 1.3 only. The Transport Layer Security (TLS) protocol is an industry latest version of the standard designed to help protect the privacy of information communicated over the Internet. [TLS 1.3](https://tools.ietf.org/html/rfc8446) is a standard that provides security improvements over previous versions. This article presents recommendations to secure .NET Framework applications that use the TLS protocol. @@ -53,11 +53,11 @@ For more information see [TLS protocol version support in Schannel](/windows/win ## Recommendations -- For TLS 1.3, target .NET Framework 4.8 or later. Check [Audit your code](#audit-your-code-and-make-code-changes) section how to verify your `target framework`. +- For TLS 1.3, target .NET Framework 4.8 or later. Check the [Audit your code](#audit-your-code-and-make-code-changes) section how to verify your `target framework`. - Do not specify the TLS version explicitly, i.e. don't use the method overloads of `SslStream` that take an explicit `SslProtocols` parameter. - That way your code will let the OS decide on the TLS version. - - If you must set , then set it to . That will also use OS default. - - If you must use the method overloads of `SslStream` that take an explicit `SslProtocols` parameter, then pass `SslProtocols.SystemDefault` as argument. That will also use OS default. + - If you must set , then set it to . That will also use the OS default. + - If you must use the method overloads of `SslStream` that take an explicit `SslProtocols` parameter, then pass `SslProtocols.SystemDefault` as argument. That will also use the OS default. - Perform a thorough code audit to verify you're not specifying a TLS or SSL version explicitly. > [!WARNING] @@ -70,7 +70,7 @@ When your app lets the OS choose the TLS version: This article explains how to enable the strongest security available for the version of .NET Framework that your app targets and runs on. When an app explicitly sets a security protocol and version, it opts out of any other alternative, and opts out of .NET Framework and OS default behavior. If you want your app to be able to negotiate a TLS 1.3 connection, explicitly setting to a lower TLS version prevents a TLS 1.3 connection. -If you can't avoid specifying a protocol version explicitly, allow only TLS 1.2 or TLS 1.3. Prefer TLS 1.3 when the operating system and peer support it. For guidance on identifying and removing TLS 1.0 dependencies, download the [Solving the TLS 1.0 Problem](https://www.microsoft.com/download/details.aspx?id=55266) white paper. +If you can't avoid specifying a protocol version explicitly, include only those legacy versions that you absolutely need, and omit modern default versions only when they cause compatibility issues. For guidance on identifying and removing TLS 1.0 dependencies, download the [Solving the TLS 1.0 Problem](https://www.microsoft.com/download/details.aspx?id=55266) white paper. WCF supports TLS 1.2 as the default in .NET Framework 4.7. Starting with .NET Framework 4.7.1, WCF defaults to the operating system configured version. If an application is explicitly configured with `SslProtocols.None`, WCF uses the operating system default setting when using the NetTcp transport. @@ -191,7 +191,7 @@ The switches have the same effect whether you're doing HTTP networking ( [!WARNING] -> This article uses the historical "SSL" terminology from older .NET Framework APIs. For current guidance, use TLS rather than older SSL protocols, and prefer OS defaults. For more information, see [Transport Layer Security (TLS) best practices with the .NET Framework](tls.md). - The classes use Transport Layer Security (TLS), historically referred to as Secure Sockets Layer (SSL), to encrypt the connection for several network protocols. For http connections, the and classes use SSL to communicate with web hosts that support SSL. The decision to use SSL is made by the class, based on the URI it is given. If the URI begins with "https:", SSL is used; if the URI begins with "http:", an unencrypted connection is used. diff --git a/docs/fundamentals/code-analysis/quality-rules/ca5361.md b/docs/fundamentals/code-analysis/quality-rules/ca5361.md index ac1b94244a7d3..02e43e70d182f 100644 --- a/docs/fundamentals/code-analysis/quality-rules/ca5361.md +++ b/docs/fundamentals/code-analysis/quality-rules/ca5361.md @@ -30,7 +30,7 @@ By default, this rule analyzes the entire codebase, but this is [configurable](# ## Rule description -Setting `Switch.System.Net.DontEnableSchUseStrongCrypto` to `true` weakens the cryptography used in outgoing Transport Layer Security (TLS) connections. Weaker cryptography can compromise the confidentiality of communication between your application and the server, making it easier for attackers to eavesdrop sensitive data. Current guidance in [NIST SP 800-52 Rev. 2](https://csrc.nist.gov/pubs/sp/800/52/r2/final) requires TLS 1.2 and recommends TLS 1.3 when available. For more information, see [Transport Layer Security (TLS) best practices with .NET Framework](../../../framework/network-programming/tls.md#switchsystemnetdontenableschusestrongcrypto). +Setting `Switch.System.Net.DontEnableSchUseStrongCrypto` to `true` weakens the cryptography used in outgoing Transport Layer Security (TLS) connections. Weaker cryptography can compromise the confidentiality of communication between your application and the server, making it easier for attackers to eavesdrop sensitive data. For more information, see [Transport Layer Security (TLS) best practices with .NET Framework](../../../framework/network-programming/tls.md#switchsystemnetdontenableschusestrongcrypto). ## How to fix violations @@ -40,7 +40,7 @@ Setting `Switch.System.Net.DontEnableSchUseStrongCrypto` to `true` weakens the c ## When to suppress warnings -You can suppress this warning only if you must connect to a legacy service that can't yet be upgraded to use TLS 1.2 or later. Treat that suppression as a temporary compatibility measure. +You can suppress this warning only if you need to connect to a legacy service that does not support modern TLS versions. Treat that suppression as a temporary compatibility measure. ## Suppress a warning diff --git a/docs/fundamentals/code-analysis/quality-rules/ca5387.md b/docs/fundamentals/code-analysis/quality-rules/ca5387.md index f02b59a16b26e..ca144313e77e4 100644 --- a/docs/fundamentals/code-analysis/quality-rules/ca5387.md +++ b/docs/fundamentals/code-analysis/quality-rules/ca5387.md @@ -2,7 +2,6 @@ title: "CA5387: Do not use weak key derivation function with insufficient iteration count (code analysis)" description: Provides information about code analysis rule CA5387, including causes, how to fix violations, and when to suppress it. ms.date: 05/08/2020 -ai-usage: ai-assisted author: LLLXXXCCC ms.author: linche f1_keywords: @@ -36,7 +35,10 @@ This rule is similar to [CA5388](ca5388.md), but analysis determines that the it Set the iteration count greater than or equal with 100,000 before calling . > [!TIP] -> While the analyzer enforces a minimum of 100,000 iterations, this threshold might not keep pace with hardware improvements. [NIST SP 800-132](https://csrc.nist.gov/pubs/sp/800/132/final) recommends selecting an iteration count as high as your environment can tolerate, and increasing it periodically as computing power grows. However, excessively high iteration counts increase CPU cost per authentication attempt, which can be exploited for denial-of-service attacks—choose a value that balances security with acceptable login latency for your application. Also consider using with a FIPS-approved hash algorithm. +> While the analyzer enforces a minimum of 100,000 iterations, this threshold might not keep pace with hardware improvements. [NIST SP 800-132](https://csrc.nist.gov/pubs/sp/800/132/final) recommends selecting an iteration count as high as your environment can tolerate, and increasing it periodically as computing power grows. However, excessively high iteration counts increase CPU cost per authentication attempt, which can be exploited for denial-of-service attacks. Choose a value that balances security with acceptable latency for your application. + +> [!TIP] +> Remember that you need to save the iteration count (or a version/scheme identifier that represents it) used to produce the original output so that you can specify the same value again when trying to reproduce the value. ## When to suppress warnings diff --git a/docs/fundamentals/code-analysis/quality-rules/ca5388.md b/docs/fundamentals/code-analysis/quality-rules/ca5388.md index 9b4c2162818f0..b976dc017b620 100644 --- a/docs/fundamentals/code-analysis/quality-rules/ca5388.md +++ b/docs/fundamentals/code-analysis/quality-rules/ca5388.md @@ -2,7 +2,6 @@ title: "CA5388: Ensure sufficient iteration count when using weak key derivation function (code analysis)" description: Provides information about code analysis rule CA5388, including causes, how to fix violations, and when to suppress it. ms.date: 05/08/2020 -ai-usage: ai-assisted author: LLLXXXCCC ms.author: linche f1_keywords: @@ -36,7 +35,10 @@ This rule is similar to [CA5387](ca5387.md), but analysis can't determine if the Set the iteration count greater than or equal with 100k before calling explicitly. > [!TIP] -> While the analyzer enforces a minimum of 100,000 iterations, this threshold might not keep pace with hardware improvements. [NIST SP 800-132](https://csrc.nist.gov/pubs/sp/800/132/final) recommends selecting an iteration count as high as your environment can tolerate, and increasing it periodically as computing power grows. However, excessively high iteration counts increase CPU cost per authentication attempt, which can be exploited for denial-of-service attacks—choose a value that balances security with acceptable login latency for your application. Also consider using with a FIPS-approved hash algorithm. +> While the analyzer enforces a minimum of 100,000 iterations, this threshold might not keep pace with hardware improvements. [NIST SP 800-132](https://csrc.nist.gov/pubs/sp/800/132/final) recommends selecting an iteration count as high as your environment can tolerate, and increasing it periodically as computing power grows. However, excessively high iteration counts increase CPU cost per authentication attempt, which can be exploited for denial-of-service attacks. Choose a value that balances security with acceptable latency for your application. + +> [!TIP] +> Remember that you need to save the iteration count (or a version/scheme identifier that represents it) used to produce the original output so that you can specify the same value again when trying to reproduce the value. ## When to suppress warnings diff --git a/docs/fundamentals/syslib-diagnostics/syslib0033.md b/docs/fundamentals/syslib-diagnostics/syslib0033.md index 15464ff202667..170db08c9762e 100644 --- a/docs/fundamentals/syslib-diagnostics/syslib0033.md +++ b/docs/fundamentals/syslib-diagnostics/syslib0033.md @@ -13,7 +13,7 @@ The . -For new development, derive key material directly with or , and then assign the result to the algorithm you're using. When you derive keys from passwords, use a unique salt and an iteration count that fits your performance budget, as described in [NIST SP 800-132](https://csrc.nist.gov/pubs/sp/800/132/final). +For new development, use a newer, standardized Key Derivation Function (KDF). ## Suppress a warning diff --git a/docs/fundamentals/syslib-diagnostics/syslib0041.md b/docs/fundamentals/syslib-diagnostics/syslib0041.md index 31171e519f27f..fda02b2fe288a 100644 --- a/docs/fundamentals/syslib-diagnostics/syslib0041.md +++ b/docs/fundamentals/syslib-diagnostics/syslib0041.md @@ -2,7 +2,6 @@ title: SYSLIB0041 warning - Rfc2898DeriveBytes constructors with default hash algorithm and iteration counts are obsolete description: Learn about the obsoletion of some Rfc2898DeriveBytes constructors that generates compile-time warning SYSLIB0041. ms.date: 04/08/2022 -ai-usage: ai-assisted f1_keywords: - syslib0041 --- @@ -20,12 +19,13 @@ The following constructor ## Workaround -Use a different constructor overload where you can explicitly specify the iteration count (the default is 1000) and hash algorithm name (the default is ). +Use a different constructor overload where you can explicitly specify the iteration count and hash algorithm name. -If you're using the default iteration count or default hash algorithm, move to more secure values—that is, a much larger iteration count and a FIPS-approved hash algorithm. +For compatibility with existing values specify an iteration count of 1000 and a hash algorithm of . +When generating new values, use an iteration count and hash algorithm consistent with your desired security properties. -> [!IMPORTANT] -> [NIST SP 800-132](https://csrc.nist.gov/pubs/sp/800/132/final) recommends selecting an iteration count as high as your environment can tolerate. Use with a FIPS-approved hash algorithm, as recommended by [SYSLIB0060](syslib0060.md). +> [!TIP] +> For information on choosing an iteration count, see [NIST SP 800-132](https://csrc.nist.gov/pubs/sp/800/132/final) Appendix A.2.2. ## Suppress a warning diff --git a/docs/standard/security/cross-platform-cryptography.md b/docs/standard/security/cross-platform-cryptography.md index e97bcce5a9f1a..6d95d4d54c245 100644 --- a/docs/standard/security/cross-platform-cryptography.md +++ b/docs/standard/security/cross-platform-cryptography.md @@ -20,7 +20,7 @@ The dependency on OS libraries also means that .NET apps can only use cryptograp This article assumes you have a working familiarity with cryptography in .NET. For more information, see [.NET Cryptography Model](cryptography-model.md) and [.NET Cryptographic Services](cryptographic-services.md). > [!IMPORTANT] -> The following tables show platform support, not recommendations for new development. Some algorithms and modes remain available for standards conformance and backward compatibility even though current guidance deprecates them for new systems. For example, [NIST SP 800-131A](https://csrc.nist.gov/pubs/sp/800/131a/r2/final) deprecates MD5, SHA-1 for digital signatures, DES, and 3DES. +> The following tables show platform support, not recommendations for new development. Some algorithms and modes remain available for standards conformance and backward compatibility even though current guidance deprecates them for new systems. ## Hash and Message Authentication Algorithms @@ -158,9 +158,6 @@ Padding and digest support vary by platform: | PKCS1 Signature (SHA-3) | Windows 11 Build 25324+ | OpenSSL 1.1.1+ | ❌ | ❌ | ❌ | ❌ | | PSS | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ❌ | -> [!NOTE] -> Support for OAEP-SHA1 and PKCS#1 signatures with MD5 or SHA-1 is listed for compatibility with existing protocols and data formats. For new development, use current FIPS-approved hash algorithms and padding choices that your protocol or standard requires. - 1 Windows CryptoAPI (CAPI) is capable of PKCS1 signature with a SHA-2 algorithm. But the individual RSA object may be loaded in a cryptographic service provider (CSP) that doesn't support it. #### RSA on Windows diff --git a/docs/standard/security/cryptographic-services.md b/docs/standard/security/cryptographic-services.md index 2f9d18214ea7f..587d15ed14d2c 100644 --- a/docs/standard/security/cryptographic-services.md +++ b/docs/standard/security/cryptographic-services.md @@ -2,7 +2,6 @@ title: "Overview of encryption, signatures, and hash algorithms in .NET" description: Learn about encryption methods and practices in .NET, including digital signatures, random number generation, and Cryptography Next Generation (CNG) classes. ms.date: 03/03/2022 -ai-usage: ai-assisted helpviewer_keywords: - "cryptography [.NET]" - "pattern of derived class inheritance" @@ -66,15 +65,9 @@ Secret-key encryption algorithms use a single secret key to encrypt and decrypt Secret-key encryption is also referred to as symmetric encryption because the same key is used for encryption and decryption. Secret-key encryption algorithms are very fast (compared with public-key algorithms) and are well suited for performing cryptographic transformations on large streams of data. Asymmetric encryption algorithms such as RSA are limited mathematically in how much data they can encrypt. Symmetric encryption algorithms do not generally have those problems. -A type of secret-key algorithm called a block cipher is used to encrypt one block of data at a time. Block ciphers such as Data Encryption Standard (DES), TripleDES, and Advanced Encryption Standard (AES) cryptographically transform an input block of *n* bytes into an output block of encrypted bytes. If you want to encrypt or decrypt a sequence of bytes, you have to do it block by block. Because *n* is small (8 bytes for DES and TripleDES; 16 bytes [the default], 24 bytes, or 32 bytes for AES), data values that are larger than *n* have to be encrypted one block at a time. Data values that are smaller than *n* have to be expanded to *n* in order to be processed. +A type of secret-key algorithm called a block cipher is used to encrypt one block of data at a time. Block ciphers such as Data Encryption Standard (DES), TripleDES, and Advanced Encryption Standard (AES) cryptographically transform an input block of *n* bytes into an output block of encrypted bytes. If you want to encrypt or decrypt a sequence of bytes, you have to do it block by block. Because *n* is small (8 bytes for DES and TripleDES; 16 bytes [the default], 24 bytes, or 32 bytes for AES), data values that are larger than *n* have to be encrypted one block at a time. Data values that are smaller than *n* have to be expanded to *n* in order to be processed. There are multiple algorithms for handling the sequence of blocks, known as the "block cipher mode of operation", "block cipher chain mode" or just "chain mode". -> [!WARNING] -> DES and TripleDES (3DES) are deprecated per [NIST SP 800-131A](https://csrc.nist.gov/pubs/sp/800/131a/r2/final) and should not be used for new development. Use instead. - -One simple form of block cipher is called the electronic codebook (ECB) mode. ECB mode is not considered secure, because it does not use an initialization vector to initialize the first plaintext block. For a given secret key *k*, a simple block cipher that does not use an initialization vector will encrypt the same input block of plaintext into the same output block of ciphertext. Therefore, if you have duplicate blocks in your input plaintext stream, you will have duplicate blocks in your output ciphertext stream. These duplicate output blocks alert unauthorized users to the weak encryption used the algorithms that might have been employed, and the possible modes of attack. The ECB cipher mode is therefore quite vulnerable to analysis, and ultimately, key discovery. - -> [!WARNING] -> ECB mode must not be used for encryption. CBC mode with an unpredictable IV is the default for .NET's block cipher classes. If data integrity is also required, apply separate authentication (for example, HMAC) using an Encrypt-then-MAC pattern. +One simple form of block cipher mode is called Electronic CodeBook (ECB). ECB mode is not considered secure, because it does not use an initialization vector to initialize the first plaintext block. For a given secret key *k*, a simple block cipher that does not use an initialization vector will encrypt the same input block of plaintext into the same output block of ciphertext. Therefore, if you have duplicate blocks in your input plaintext stream, you will have duplicate blocks in your output ciphertext stream. These duplicate output blocks alert unauthorized users to the weak encryption used the algorithms that might have been employed, and the possible modes of attack. The ECB cipher mode is therefore quite vulnerable to analysis, and ultimately, key discovery. The block cipher classes that are provided in the base class library use a default chaining mode called cipher-block chaining (CBC), although you can change this default if you want. @@ -126,7 +119,7 @@ The following list offers comparisons between public-key and secret-key cryptogr - -RSA allows both encryption and signing, but DSA can be used only for signing. DSA is not as secure as RSA, and we recommend RSA. Diffie-Hellman can be used only for key generation. In general, public-key algorithms are more limited in their uses than private-key algorithms. +RSA allows both encryption and signing, but DSA can be used only for signing. DSA is not as secure as RSA, and we recommend RSA. Diffie-Hellman can be used only for key generation. In general, public-key algorithms are more limited in their uses than secret-key algorithms. ## Digital Signatures @@ -177,16 +170,13 @@ None of the previous methods will prevent someone from reading Alice's messages, - . -.NET also provides and for standards conformance and backward compatibility with existing data formats and protocols. However, the MD5 and SHA-1 algorithms have been found to be insecure per [NIST SP 800-131A](https://csrc.nist.gov/pubs/sp/800/131a/r2/final). .NET provides the FIPS-approved SHA-2 family (SHA256, SHA384, and SHA512) as replacements. - -> [!WARNING] -> Do not use MD5 or SHA-1 for security-sensitive purposes such as digital signatures or certificate validation, unless required by an existing data format standard. Use a current FIPS-approved hash algorithm for new development. +.NET also provides and for standards conformance and backward compatibility with existing data formats and protocols. However, the MD5 and SHA-1 algorithms have been found to be insecure per [NIST SP 800-131A](https://csrc.nist.gov/pubs/sp/800/131/a/r2/final). ## Random Number Generation Random number generation is integral to many cryptographic operations. For example, cryptographic keys need to be as random as possible so that it is infeasible to reproduce them. Cryptographic random number generators must generate output that is computationally infeasible to predict with a probability that is better than one half. Therefore, any method of predicting the next output bit must not perform better than random guessing. The classes in .NET use random number generators to generate cryptographic keys. -The class is an implementation of a cryptographically secure random number generation algorithm. +Use the static methods of to obtain cryptographically secure random numbers. ## ClickOnce Manifests diff --git a/docs/standard/security/cryptographic-signatures.md b/docs/standard/security/cryptographic-signatures.md index 4e2fc4b1873b3..4bf261246fb9b 100644 --- a/docs/standard/security/cryptographic-signatures.md +++ b/docs/standard/security/cryptographic-signatures.md @@ -2,7 +2,6 @@ description: "Learn more about: Cryptographic Signatures" title: "Cryptographic Signatures" ms.date: 08/08/2022 -ai-usage: ai-assisted dev_langs: - "csharp" - "vb" @@ -48,7 +47,8 @@ Module Program Dim sharedParameters As RSAParameters Dim signedHash As Byte() - ' Generate signature + ' Generate signature with Pkcs1 padding. + ' When creating RSA signatures, choose a padding mode that is appropriate to your needs. Using rsa As RSA = RSA.Create() sharedParameters = rsa.ExportParameters(False) Dim rsaFormatter As New RSAPKCS1SignatureFormatter(rsa) @@ -68,13 +68,14 @@ using System.Text; using SHA256 alg = SHA256.Create(); -byte[] data = Encoding.ASCII.GetBytes("Hello, from the .NET Docs!"); +byte[] data = Encoding.UTF8.GetBytes("Hello, from the .NET Docs!"); byte[] hash = alg.ComputeHash(data); RSAParameters sharedParameters; byte[] signedHash; -// Generate signature +// Generate signature with Pkcs1 padding. +// When creating RSA signatures, choose a padding mode that is appropriate to your needs. using (RSA rsa = RSA.Create()) { sharedParameters = rsa.ExportParameters(false); diff --git a/docs/standard/security/cryptography-model.md b/docs/standard/security/cryptography-model.md index 246fd4abc57fe..50c13d963e583 100644 --- a/docs/standard/security/cryptography-model.md +++ b/docs/standard/security/cryptography-model.md @@ -2,7 +2,6 @@ title: ".NET cryptography model" description: Review implementations of usual cryptographic algorithms in .NET. Learn the cryptography model of object inheritance and one-shots. ms.date: 02/26/2021 -ai-usage: ai-assisted dev_langs: - "csharp" - "vb" @@ -65,7 +64,7 @@ In most cases, you don't need to directly reference an algorithm implementation You can select an algorithm for different reasons: for example, for data integrity, for data privacy, or to generate a key. Symmetric and hash algorithms are intended for protecting data for either integrity reasons (protect from change) or privacy reasons (protect from viewing). Hash algorithms are used primarily for data integrity. -Here is a list of recommended algorithms by application: +Here is a partial list of algorithms by application: - Data privacy: - @@ -84,8 +83,6 @@ Here is a list of recommended algorithms by application: - Generating a key from a password: - -> [!TIP] -> .NET's built-in password-based key derivation uses the PBKDF2 algorithm via . When using PBKDF2, specify a current FIPS-approved hash algorithm and set the iteration count as high as your performance budget allows per [NIST SP 800-132](https://csrc.nist.gov/pubs/sp/800/132/final). Alternative algorithms such as Argon2id, bcrypt, or scrypt are available through third-party libraries. ## See also diff --git a/docs/standard/security/snippets/cryptographic-signatures/csharp/Program.cs b/docs/standard/security/snippets/cryptographic-signatures/csharp/Program.cs index 1cb8ec594af59..683084f519613 100644 --- a/docs/standard/security/snippets/cryptographic-signatures/csharp/Program.cs +++ b/docs/standard/security/snippets/cryptographic-signatures/csharp/Program.cs @@ -3,13 +3,14 @@ using SHA256 alg = SHA256.Create(); -byte[] data = Encoding.ASCII.GetBytes("Hello, from the .NET Docs!"); +byte[] data = Encoding.UTF8.GetBytes("Hello, from the .NET Docs!"); byte[] hash = alg.ComputeHash(data); RSAParameters sharedParameters; byte[] signedHash; -// Generate signature +// Generate signature with Pkcs1 padding. +// When creating RSA signatures, choose a padding mode that is appropriate to your needs. using (RSA rsa = RSA.Create()) { sharedParameters = rsa.ExportParameters(false); @@ -20,7 +21,9 @@ signedHash = rsaFormatter.CreateSignature(hash); } -// Verify signature +// Verify signature. +// Since the signature was generated with Pkcs1 padding, +// it can only be verified with Pkcs1 padding. using (RSA rsa = RSA.Create()) { rsa.ImportParameters(sharedParameters); diff --git a/docs/standard/security/snippets/cryptographic-signatures/vb/Program.vb b/docs/standard/security/snippets/cryptographic-signatures/vb/Program.vb index 825d316c851bf..072975a151113 100644 --- a/docs/standard/security/snippets/cryptographic-signatures/vb/Program.vb +++ b/docs/standard/security/snippets/cryptographic-signatures/vb/Program.vb @@ -12,7 +12,8 @@ Module Program Dim sharedParameters As RSAParameters Dim signedHash As Byte() - ' Generate signature + ' Generate signature with Pkcs1 padding. + ' When creating RSA signatures, choose a padding mode that is appropriate to your needs. Using rsa As RSA = RSA.Create() sharedParameters = rsa.ExportParameters(False) Dim rsaFormatter As New RSAPKCS1SignatureFormatter(rsa) @@ -21,7 +22,9 @@ Module Program signedHash = rsaFormatter.CreateSignature(hash) End Using - ' Verify signature + ' Verify signature. + ' Since the signature was generated with Pkcs1 padding, + ' it can only be verified with Pkcs1 padding. Using rsa As RSA = RSA.Create() rsa.ImportParameters(sharedParameters)