Update security docs to address outdated cryptographic defaults, broken samples, and weak recommendations#53164
Conversation
- 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>
- 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>
- 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>
- 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>
- 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>
There was a problem hiding this comment.
Pull request overview
This PR modernizes .NET security documentation and sample code to remove outdated cryptographic guidance, improve defaults, and fix correctness issues in several crypto-related snippets.
Changes:
- Updates docs to warn against legacy/weak algorithms and insecure modes (for example, 3DES, ECB, and unauthenticated CBC), and to point readers to current OWASP guidance for PBKDF2 recommendations.
- Modernizes encryption and signature samples (for example, AES key handling, RSA OAEP padding, RSA key sizes, and consistent UTF-8 usage).
- Fixes correctness bugs in sample code (for example, CryptoWalkThru decrypt length reads, and DPAPI entropy generation API usage).
Reviewed changes
Copilot reviewed 20 out of 20 changed files in this pull request and generated 17 comments.
Show a summary per file
| File | Description |
|---|---|
| samples/snippets/visualbasic/VS_Snippets_CLR/DPAPI-HowTO/vb/sample.vb | Fixes encoding API usage and replaces obsolete RNGCryptoServiceProvider usage with RandomNumberGenerator.Fill. |
| samples/snippets/csharp/VS_Snippets_CLR/DPAPI-HowTO/cs/sample.cs | Fixes encoding API usage and replaces obsolete RNGCryptoServiceProvider usage with RandomNumberGenerator.Fill. |
| samples/snippets/csharp/VS_Snippets_CLR/CryptoWalkThru/cs/Form1.cs | Fixes length field reads for decrypt path (3 bytes → 4 bytes). |
| docs/visual-basic/programming-guide/language-features/strings/walkthrough-encrypting-and-decrypting-strings.md | Adds warnings and updates guidance around 3DES usage in the walkthrough. |
| docs/standard/security/snippets/encrypting-data/vb/aes-encrypt.vb | Replaces hard-coded AES key with generated key and prints hex key for decrypt pairing. |
| docs/standard/security/snippets/encrypting-data/csharp/aes-encrypt.cs | Replaces hard-coded AES key with generated key and prints hex key for decrypt pairing. |
| docs/standard/security/snippets/decrypting-data/vb/aes-decrypt.vb | Switches AES key to command-line hex input for pairing with updated encrypt sample. |
| docs/standard/security/snippets/decrypting-data/csharp/aes-decrypt.cs | Switches AES key to command-line hex input for pairing with updated encrypt sample. |
| docs/standard/security/snippets/cryptographic-signatures/vb/Program.vb | Stops exporting private key parameters and aligns data encoding to UTF-8. |
| docs/standard/security/snippets/cryptographic-signatures/csharp/Program.cs | Aligns data encoding to UTF-8. |
| docs/standard/security/how-to-encrypt-xml-elements-with-symmetric-keys.md | Adds note about CBC limitations in XML Encryption 1.0 and points to padding-oracle guidance. |
| docs/standard/security/how-to-access-hardware-encryption-devices.md | Adds warning about obsolete APIs and SHA-1 usage in the legacy hardware crypto flow. |
| docs/standard/security/encrypting-data.md | Adds CBC-mode warning, updates AES guidance, and modernizes RSA example (OAEP SHA-256, ≥2048-bit). |
| docs/standard/security/decrypting-data.md | Adds CBC-mode warning and modernizes RSA example (OAEP SHA-256, ≥2048-bit). |
| docs/standard/security/cryptography-model.md | Adds PBKDF2 best-practice tip and links to OWASP for current iteration guidance and alternatives. |
| docs/standard/security/cryptographic-signatures.md | Aligns inline sample text with snippet fixes (UTF-8, and no private key export). |
| docs/standard/security/cryptographic-services.md | Adds warnings for deprecated algorithms, ECB insecurity, and MD5/SHA-1 usage. |
| docs/fundamentals/syslib-diagnostics/syslib0041.md | Strengthens PBKDF2 guidance and links to OWASP; references one-shot Pbkdf2 API guidance. |
| docs/fundamentals/code-analysis/quality-rules/ca5387.md | Adds tip that analyzer iteration thresholds might lag hardware improvements; links to OWASP. |
| docs/fundamentals/code-analysis/quality-rules/ca5388.md | Adds tip that analyzer iteration thresholds might lag hardware improvements; links to OWASP. |
- 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>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 20 out of 20 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
samples/snippets/csharp/VS_Snippets_CLR/CryptoWalkThru/cs/Form1.cs:213
- After reading
lenK/lenIVfrom the file, the code allocates arrays directly from those untrusted values and then usesStream.Read, which isn't guaranteed to fill the buffers. Consider validatinglenK/lenIV(non-negative and within a reasonable maximum) and usingReadExactlyfor theKeyEncryptedandIVreads to avoid partial reads or excessive allocations on malformed input files.
inFs.ReadExactly(LenK, 0, 4);
inFs.ReadExactly(LenIV, 0, 4);
// Convert the lengths to integer values.
int lenK = BitConverter.ToInt32(LenK, 0);
int lenIV = BitConverter.ToInt32(LenIV, 0);
The DPAPI sample targets net461, which does not support RandomNumberGenerator.Fill(Span<byte>). Revert to RNGCryptoServiceProvider but wrap in a using statement to properly dispose the instance. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- 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>
…n 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>
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>
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>
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>
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>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
| # Mitigation: TLS Protocols | ||
|
|
||
| Starting with .NET Framework 4.6, the <xref:System.Net.ServicePointManager?displayProperty=nameWithType> and <xref:System.Net.Security.SslStream?displayProperty=nameWithType> 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 <xref:System.Net.ServicePointManager?displayProperty=nameWithType> and <xref:System.Net.Security.SslStream?displayProperty=nameWithType> 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. |
There was a problem hiding this comment.
I think this is missing TLS 1.3 but probably better to make it more generic and future proof
| Starting with .NET Framework 4.6, the <xref:System.Net.ServicePointManager?displayProperty=nameWithType> and <xref:System.Net.Security.SslStream?displayProperty=nameWithType> 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). |
There was a problem hiding this comment.
I think mentioning specific TLS version is not future proof unless we mention "as of 2026" somewhere but that doesn't sound very good
| - Any app that uses SSL to talk to an HTTPS server or a socket server using any of the following types: <xref:System.Net.Http.HttpClient>, <xref:System.Net.HttpWebRequest>, <xref:System.Net.FtpWebRequest>, <xref:System.Net.Mail.SmtpClient>, and <xref:System.Net.Security.SslStream>. | ||
|
|
||
| - 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. |
| 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. |
There was a problem hiding this comment.
perhaps something along the lines of "allow only NIST approved TLS versions which at time of writing this document are TLS 1.2 and TLS 1.3"
| - **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 <xref:System.Security.Authentication.SslProtocols.None?displayProperty=nameWithType>. You can set this on <xref:System.ServiceModel.TcpTransportSecurity.SslProtocols>. `SslProtocols.None` can be accessed from <xref:System.ServiceModel.NetTcpSecurity.Transport>. `NetTcpSecurity.Transport` can be accessed from <xref:System.ServiceModel.NetTcpBinding.Security>. | ||
| 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 <xref:System.Security.Authentication.SslProtocols.None?displayProperty=nameWithType>. You can set this on <xref:System.ServiceModel.TcpTransportSecurity.SslProtocols>. `SslProtocols.None` can be accessed from <xref:System.ServiceModel.NetTcpSecurity.Transport>. `NetTcpSecurity.Transport` can be accessed from <xref:System.ServiceModel.NetTcpBinding.Security>. |
There was a problem hiding this comment.
I'm not certain this is true because IIRC TLS 1.3 says that if both side can talk TLS 1.3 they MUST talk TLS 1.3 and IIRC we did add support for TLS 1.3. Possibly more generic statement will be better here. @bartonjs ideas?
|
|
||
| The <xref:System.Net> 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). |
There was a problem hiding this comment.
Might be worth to just updade this doc to use new terminology since we have tools for that but perhaps separate PR might be better idea
| ## 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. |
There was a problem hiding this comment.
honestly the old statement which didn't mention specific version seemed better. We don't know how long TLS 1.2 will be recommended
| 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 |
There was a problem hiding this comment.
what's this? I don't think we changed it elsewhere - probably should be consistent (either everywhere or nowhere)
| Using rsa As RSA = RSA.Create() | ||
| sharedParameters = rsa.ExportParameters(True) | ||
| sharedParameters = rsa.ExportParameters(False) | ||
| Dim rsaFormatter As New RSAPKCS1SignatureFormatter(rsa) |
There was a problem hiding this comment.
this sample should probably mention that RSA+PKCS1 is for illustrative purposes only
There was a problem hiding this comment.
(RSA-PSS or ECDSA with P-256 curve would be better choice but we should likely not go specific)
| 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. |
There was a problem hiding this comment.
perhaps it's me being non-native English speaker but this sounds weird to me "deprecates MD5, SHA-1 for digital signatures, DES, and 3DES"
There was a problem hiding this comment.
specifically that "for digital signatures" before DES and 3 DES
| 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 per [NIST SP 800-131A](https://csrc.nist.gov/pubs/sp/800/131a/r2/final) and should not be used for new development. Use <xref:System.Security.Cryptography.Aes> instead. |
There was a problem hiding this comment.
IMO more future proof without last sentence
| 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. |
There was a problem hiding this comment.
perhpas refer to NIST standards rather than "Encrypt-then-MAC" since at some point they might recommend to always use bundled together algo and not recommend to do it manually at all
| - <xref:System.Security.Cryptography.SHA512>. | ||
|
|
||
| .NET also provides <xref:System.Security.Cryptography.MD5> and <xref:System.Security.Cryptography.SHA1>. 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 <xref:System.Security.Cryptography.MD5> and <xref:System.Security.Cryptography.SHA1> 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. |
There was a problem hiding this comment.
"FIPS approved" is a function with time domain so more correct will be "at time of writing this document" - especially with quantum on the horizon
|
|
||
| private void Close_Click(object sender, EventArgs e) => Application.Exit(); | ||
|
|
||
| private static void ReadBytesExactly(Stream stream, byte[] buffer, int offset, int count) |
There was a problem hiding this comment.
nit: this could be replaced by https://learn.microsoft.com/en-us/dotnet/api/system.io.stream.readexactly?view=net-10.0
| // Create a new instance of the RNGCryptoServiceProvider. | ||
| // Fill the array with a random value. | ||
| new RNGCryptoServiceProvider().GetBytes(entropy); | ||
| using (var rng = new RNGCryptoServiceProvider()) |
There was a problem hiding this comment.
If we're changing this perhaps RandomNumberGenerator.GetBytes
| S.Read(inBuffer, 0, Length); | ||
| int offset = 0; | ||
|
|
||
| while (offset < Length) |
| ' 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) |
There was a problem hiding this comment.
this should mention it's for illustrative purposes also ECDSA might be better choice if we want to change this at all
| '''''''''''''''''''''''''''''''''''' | ||
| ' 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") |
There was a problem hiding this comment.
I don't know about those changes in DPAPI samples, I think this should focus on making statement that algos are for illustrative purpose because we should make sure all samples actually can run and I'm not certain AI tested all that
Summary
This PR refreshes .NET security documentation and related samples across cryptography and TLS. It updates the guidance to reflect current standards-based practices, clarifies compatibility-only behavior in legacy APIs and platform notes, and modernizes the samples so the examples remain accurate and runnable.
Scope
SslStream, .NET Framework TLS docs, WCF configuration references, and legacy compatibility pages.What changes in practice
Areas touched
docs/standard/security/*docs/fundamentals/code-analysis/quality-rules/*docs/fundamentals/syslib-diagnostics/*docs/core/extensions/sslstream-best-practices.mddocs/framework/network-programming/*docs/standard/security/snippetsandsamples/snippetsInternal previews
Toggle expand/collapse
<sslStreamSecurity>