Skip to content

Update security docs to address outdated cryptographic defaults, broken samples, and weak recommendations#53164

Open
jeffhandley wants to merge 21 commits intodotnet:mainfrom
jeffhandley:jeffhandley/outdated-recommendations
Open

Update security docs to address outdated cryptographic defaults, broken samples, and weak recommendations#53164
jeffhandley wants to merge 21 commits intodotnet:mainfrom
jeffhandley:jeffhandley/outdated-recommendations

Conversation

@jeffhandley
Copy link
Copy Markdown
Member

@jeffhandley jeffhandley commented Apr 16, 2026

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

  • Refresh the core security docs for encryption, decryption, cryptographic services, the cryptography model, CBC-mode vulnerabilities, XML encryption, and related walkthroughs.
  • Refresh TLS and SSL guidance across SslStream, .NET Framework TLS docs, WCF configuration references, and legacy compatibility pages.
  • Update analyzer and obsoletion docs that cover PBKDF2, strong crypto, and unsafe cipher modes.
  • Modernize the related snippets and sample projects, including hardware crypto and data-protection examples.

What changes in practice

  • Clarifies that the docs describe current security guidance separately from compatibility behavior that .NET still supports.
  • Keeps the sample code self-contained and runnable for readers, while making the illustrative nature of embedded sample material explicit.
  • Reframes the guidance around durable security properties such as integrity protection, current approved hash choices, and OS-default TLS negotiation.
  • Updates older code examples to more current API usage patterns and clearer platform context.

Areas touched

  • docs/standard/security/*
  • docs/fundamentals/code-analysis/quality-rules/*
  • docs/fundamentals/syslib-diagnostics/*
  • docs/core/extensions/sslstream-best-practices.md
  • docs/framework/network-programming/*
  • related cryptography snippets and sample projects under docs/standard/security/snippets and samples/snippets

Internal previews

Toggle expand/collapse
📄 File 🔗 Preview link
docs/core/compatibility/cryptography/10.0/openssl-macos-unsupported.md docs/core/compatibility/cryptography/10.0/openssl-macos-unsupported
docs/core/extensions/sslstream-best-practices.md docs/core/extensions/sslstream-best-practices
docs/framework/configure-apps/file-schema/wcf/sslstreamsecurity.md docs/framework/configure-apps/file-schema/wcf/sslstreamsecurity
docs/framework/migration-guide/mitigation-tls-protocols.md docs/framework/migration-guide/mitigation-tls-protocols
docs/framework/network-programming/tls.md docs/framework/network-programming/tls
docs/framework/network-programming/using-secure-sockets-layer.md docs/framework/network-programming/using-secure-sockets-layer
docs/fundamentals/code-analysis/quality-rules/ca5358.md docs/fundamentals/code-analysis/quality-rules/ca5358
docs/fundamentals/code-analysis/quality-rules/ca5361.md docs/fundamentals/code-analysis/quality-rules/ca5361
docs/fundamentals/code-analysis/quality-rules/ca5387.md docs/fundamentals/code-analysis/quality-rules/ca5387
docs/fundamentals/code-analysis/quality-rules/ca5388.md docs/fundamentals/code-analysis/quality-rules/ca5388
docs/fundamentals/syslib-diagnostics/syslib0033.md docs/fundamentals/syslib-diagnostics/syslib0033
docs/fundamentals/syslib-diagnostics/syslib0041.md docs/fundamentals/syslib-diagnostics/syslib0041
docs/standard/security/cross-platform-cryptography.md docs/standard/security/cross-platform-cryptography
docs/standard/security/cryptographic-services.md docs/standard/security/cryptographic-services
docs/standard/security/cryptographic-signatures.md docs/standard/security/cryptographic-signatures
docs/standard/security/cryptography-model.md docs/standard/security/cryptography-model
docs/standard/security/decrypting-data.md docs/standard/security/decrypting-data
docs/standard/security/encrypting-data.md docs/standard/security/encrypting-data
docs/standard/security/how-to-access-hardware-encryption-devices.md docs/standard/security/how-to-access-hardware-encryption-devices
docs/standard/security/how-to-encrypt-xml-elements-with-symmetric-keys.md docs/standard/security/how-to-encrypt-xml-elements-with-symmetric-keys
docs/standard/security/vulnerabilities-cbc-mode.md docs/standard/security/vulnerabilities-cbc-mode
docs/visual-basic/programming-guide/language-features/strings/walkthrough-encrypting-and-decrypting-strings.md docs/visual-basic/programming-guide/language-features/strings/walkthrough-encrypting-and-decrypting-strings

jeffhandley and others added 5 commits April 15, 2026 18:16
- 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>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread docs/standard/security/decrypting-data.md
Comment thread docs/fundamentals/syslib-diagnostics/syslib0041.md Outdated
Comment thread docs/fundamentals/code-analysis/quality-rules/ca5388.md
Comment thread docs/standard/security/how-to-access-hardware-encryption-devices.md Outdated
Comment thread docs/standard/security/snippets/decrypting-data/csharp/aes-decrypt.cs Outdated
Comment thread docs/standard/security/cryptography-model.md Outdated
Comment thread docs/standard/security/cryptographic-services.md Outdated
Comment thread docs/standard/security/cryptographic-signatures.md
- 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>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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/lenIV from the file, the code allocates arrays directly from those untrusted values and then uses Stream.Read, which isn't guaranteed to fill the buffers. Consider validating lenK/lenIV (non-negative and within a reasonable maximum) and using ReadExactly for the KeyEncrypted and IV reads 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);

Comment thread docs/standard/security/snippets/decrypting-data/vb/aes-decrypt.vb Outdated
Comment thread docs/standard/security/encrypting-data.md Outdated
jeffhandley and others added 2 commits April 15, 2026 19:20
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>
@jeffhandley jeffhandley requested a review from Copilot April 16, 2026 02:35
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 20 out of 20 changed files in this pull request and generated 3 comments.

Comment thread samples/snippets/csharp/VS_Snippets_CLR/DPAPI-HowTO/cs/sample.cs
Comment thread docs/standard/security/how-to-access-hardware-encryption-devices.md Outdated
…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>
Comment thread docs/fundamentals/code-analysis/quality-rules/ca5387.md Outdated
Comment thread docs/fundamentals/code-analysis/quality-rules/ca5388.md Outdated
Comment thread docs/fundamentals/syslib-diagnostics/syslib0041.md Outdated
Comment thread docs/standard/security/snippets/decrypting-data/csharp/aes-decrypt.cs Outdated
Comment thread docs/standard/security/snippets/decrypting-data/vb/aes-decrypt.vb Outdated
Comment thread docs/standard/security/cryptographic-services.md Outdated
Comment thread docs/standard/security/cryptographic-services.md Outdated
Comment thread docs/standard/security/cryptographic-services.md Outdated
Comment thread docs/standard/security/decrypting-data.md Outdated
Comment thread docs/standard/security/how-to-access-hardware-encryption-devices.md Outdated
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>

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).
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Member

@bartonjs bartonjs Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rewritten sentence (currently line 25) is good. The warning feels superfluous. [I advise that we should just] delete it.

## 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.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this sample should probably mention that RSA+PKCS1 is for illustrative purposes only

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(RSA-PSS or ECDSA with P-256 curve would be better choice but we should likely not go specific)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RSAES-PKCS1 is bad, everyone agrees. Use RSAES-OAEP.

RSASSA-PKCS1, OTOH, is "uh... well... we made PSS when we made OAEP... so... use PSS, maybe?". RSASSA-PSS has... not great... industry penetration.

So, if we're putting weasel words here, it would be "This sample uses RSASSA-PKCS1-v1_5. When using RSA signatures, choose a padding mode that is appropriate to your needs."

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.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

specifically that "for digital signatures" before DES and 3 DES

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's because that document says

Use Status
Digital signature generation Disallowed, except where specifically allowed by NIST protocol-specific guidance.
Digital signature verification Legacy use
Non-digital-signature applications Acceptable

So it can't appeal to that document saying "SHA-1 is deprecated".

I'd just delete the appeal to authority. The weasel words are "this is saying what's available, not what's good". End there.

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.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO more future proof without last sentence

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, much better without the warning at all. It's describing block ciphers, and says DES, DES-EDE, and AES are block ciphers. It doesn't say "use DES", or even "you can use DES".

To stick with strained analogies:

"A type of weapon called a projectile weapon is used to transmit an object from one party with the intent of striking another while remaining afar. Projectile weapons such as a slingshot, M16, and Glock 19 are typically used in a more-or-less horizontal fashion, while alternatives such as a trebuchet are fired in a high arc.

Warning: Early model M16 guns are/were prone to jamming. Do not use early model M16s for new combat."

It's just... so out of place.

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.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It already says "ECB mode is not considered secure."

Don't double down.

- <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.
Copy link
Copy Markdown
Member

@krwq krwq Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just delete the last sentence.


private void Close_Click(object sender, EventArgs e) => Application.Exit();

private static void ReadBytesExactly(Stream stream, byte[] buffer, int offset, int count)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// Create a new instance of the RNGCryptoServiceProvider.
// Fill the array with a random value.
new RNGCryptoServiceProvider().GetBytes(entropy);
using (var rng = new RNGCryptoServiceProvider())
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're changing this perhaps RandomNumberGenerator.GetBytes

S.Read(inBuffer, 0, Length);
int offset = 0;

while (offset < Length)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s.ReadExactly

' 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)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

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).
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The metadata says this is "Learn about the impact and mitigation for the TLS Protocol changes beginning with .NET Framework 4.6.". I don't understand why we'd include "Warning: Knives are sharp." in such a document.

#### Switch.System.Net.DontEnableSchUseStrongCrypto

A value of `false` for `Switch.System.Net.DontEnableSchUseStrongCrypto` causes your app to use strong cryptography. A value of `false` for `DontEnableSchUseStrongCrypto` uses more secure network protocols (TLS 1.2 and TLS 1.1) and blocks protocols that are not secure. For more info, see [The SCH_USE_STRONG_CRYPTO flag](#the-sch_use_strong_crypto-flag). A value of `true` disables strong cryptography for your app. This switch affects only client (outgoing) connections in your application.
A value of `false` for `Switch.System.Net.DontEnableSchUseStrongCrypto` causes your app to use strong cryptography. A value of `false` for `DontEnableSchUseStrongCrypto` uses modern network protocols, such as TLS 1.2 and TLS 1.3 when available, and blocks protocols that are not secure. For more info, see [The SCH_USE_STRONG_CRYPTO flag](#the-sch_use_strong_crypto-flag). A value of `true` disables strong cryptography for your app. This switch affects only client (outgoing) connections in your application.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
A value of `false` for `Switch.System.Net.DontEnableSchUseStrongCrypto` causes your app to use strong cryptography. A value of `false` for `DontEnableSchUseStrongCrypto` uses modern network protocols, such as TLS 1.2 and TLS 1.3 when available, and blocks protocols that are not secure. For more info, see [The SCH_USE_STRONG_CRYPTO flag](#the-sch_use_strong_crypto-flag). A value of `true` disables strong cryptography for your app. This switch affects only client (outgoing) connections in your application.
A value of `false` for `Switch.System.Net.DontEnableSchUseStrongCrypto` causes your app to use strong cryptography. A value of `false` for `DontEnableSchUseStrongCrypto` uses modern TLS versions, and blocks protocols that are not secure. For more info, see [The SCH_USE_STRONG_CRYPTO flag](#the-sch_use_strong_crypto-flag). A value of `true` disables strong cryptography for your app. This switch affects only client (outgoing) connections in your application.

Don't mention versions if you can help it, that way we don't have to come back in a few years and debate "should this 'and 1.3' also include 1.4 now?, or was it point-in-time?"

Set the iteration count greater than or equal with 100,000 before calling <xref:System.Security.Cryptography.Rfc2898DeriveBytes.GetBytes*>.

> [!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 <xref:System.Security.Cryptography.Rfc2898DeriveBytes.Pbkdf2*?displayProperty=nameWithType> with a FIPS-approved hash algorithm.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the "Also consider" about? The diagnostic here is "you passed too low a number". The warning is explaining "if the diagnostic goes off, you're too low. If it doesn't... you might still be too low."

It feels like we have a diagnostic of COLDSTEAK: Your steak is below 125 F. Then, a warning "Steak below 125 F is not considered food, don't eat it. The CDC is concerned that Rare (125-130 F) is not sufficient to kill all foodborne pathogens, consult with your medical provider for advice on your minimum steak temperature. Also, consider cutting your steak with a knife."

Set the iteration count greater than or equal with 100k before calling <xref:System.Security.Cryptography.Rfc2898DeriveBytes.GetBytes*> 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 <xref:System.Security.Cryptography.Rfc2898DeriveBytes.Pbkdf2*?displayProperty=nameWithType> with a FIPS-approved hash algorithm.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same irrelevant "Also consider"

If you're using the default iteration count or default hash algorithm, move to more secure values&mdash;that is, a much larger iteration count and a FIPS-approved hash algorithm.

> [!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 <xref:System.Security.Cryptography.Rfc2898DeriveBytes.Pbkdf2*?displayProperty=nameWithType> with a FIPS-approved hash algorithm, as recommended by [SYSLIB0060](syslib0060.md).
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SYSLIB0060 is "we obsoleted all the constructors, call the static Pbkdf2 method instead". It doesn't have anything to do with FIPS-Approved.

Maybe the sentence is trying to mean "Call Pbkdf2, like SYSLIB0060 says, also, when doing so, use a good hash algorithm", but the order of "FIPS-approved" and "recommended" make it sound like SYSLIB0060 is an authority.

If we're trying to update this to be a full present recommendation, then the whole "Workaround" needs to be rewritten to say to call Pbkdf2 instead of "a different constructor". But, if this is intended to be useful to someone upgrading to a point between 0041 and 0060, then it'd stand.

So, I think the change should be something like

## Workaround

Use a different constructor overload, or the newer [Rfc2898DeriveBytes.Pbkdf2](link) static method, where both the iteration count and the hash algorithm can be specified.

For compatibility with older values, such as reproducing a key used to encrypt persisted data, specify an iteration count of 1000 and a digest algorithm of SHA-1.
When deriving new keys, specify a sufficiently strong iteration count and a sufficiently strong hash algorithm.  For more information on choosing an iteration count and/or a hash algorithm for PBKDF2, see [the one and only one place we talk about it](link).

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.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hallucinated/typoed link. (Missing a / between 131 and a)

Suggested change
> 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. For example, [NIST SP 800-131A](https://csrc.nist.gov/pubs/sp/800/131/a/r2/final) deprecates MD5, SHA-1 for digital signatures, DES, and 3DES.

Comment on lines +161 to +163
> [!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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Delete. The document already says it's representing "available", not "good".

.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.

> [!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.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My redundant rage has built up, I apologize. But:

THIS WAS ALREADY SAID BY THE PREVIOUS PARAGRAPH! OH MY FREAKING GOSH STOP SAYING A THING THEN SAYING "WARNING: THAT THING I SAID!"

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 <xref:System.Security.Cryptography.RandomNumberGenerator> class is an implementation of a random number generator algorithm.
The <xref:System.Security.Cryptography.RandomNumberGenerator> class is an implementation of a cryptographically secure random number generation algorithm.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, semantics. RandomNumberGenerator as an instantiable class is the same as an interface: it just provides syntax, no semantics. It is intended to be a CSPRNG, but it can't guarantee it.

The static methods on RandomNumberGenerator use the CSPRNG provided by the underlying OS/platform.

The object returned by RandomNumberGenerator.Create() (unless you're on NetFX and have overridden it with CryptoConfig) is (sort of) an implementation of a CSPRNG.

The best fix, I think is

Suggested change
The <xref:System.Security.Cryptography.RandomNumberGenerator> class is an implementation of a cryptographically secure random number generation algorithm.
Use the static methods of <xref:System.Security.Cryptography.RandomNumberGenerator> to obtain cryptographically secure random numbers.

- <xref:System.Security.Cryptography.Rfc2898DeriveBytes.Pbkdf2*?displayProperty=nameWithType>

> [!TIP]
> .NET's built-in password-based key derivation uses the PBKDF2 algorithm via <xref:System.Security.Cryptography.Rfc2898DeriveBytes.Pbkdf2*?displayProperty=nameWithType>. 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.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to bother mentioning third-party alternatives.

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 <xref:System.Security.Cryptography.RSA> 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 <xref:System.Security.Cryptography.RSAParameters> 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 <xref:System.Security.Cryptography.RSA.ImportParameters*?displayProperty=nameWithType> method. Finally, the private key and IV created by an <xref:System.Security.Cryptography.Aes> 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 <xref:System.Security.Cryptography.RSA> 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 <xref:System.Security.Cryptography.Aes> instance, using OAEP padding for security.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just... word salad.

The code comments already have the "2048 is for illustrative purposes", so don't need to be here. It doesn't need to describe using OAEP here, since the code and code comments do that, too.

Suggested change
The following example uses public key information to encrypt a symmetric key and IV. An <xref:System.Security.Cryptography.RSA> 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 <xref:System.Security.Cryptography.Aes> instance, using OAEP padding for security.
The following example uses public key information to encrypt a symmetric key and an IV. The encrypting-party uses the public key of the indented recipient. In this example, the public key is represented by the **RSAParameters** type, but file format such as X.509 Subject Public Key Info is more likely to be used in real-world applications.

The following example uses public key information to encrypt a symmetric key and IV. An <xref:System.Security.Cryptography.RSA> 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 <xref:System.Security.Cryptography.Aes> instance, using OAEP padding for security.

> [!IMPORTANT]
> Use <xref:System.Security.Cryptography.RSAEncryptionPadding.OaepSHA256?displayProperty=nameWithType> (or higher) instead of <xref:System.Security.Cryptography.RSAEncryptionPadding.Pkcs1?displayProperty=nameWithType>. 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).
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it's not "!IMPORTANT". Nothing mentions Pkcs1, so it's not worth mentioning here.

If the example stayed as Pkcs1 encryption, then the warning would be justified.

'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)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The export/import part is actually important to this example... otherwise it looks like you need to create a public/private pair to encrypt.


> [!NOTE]
> This article applies to Windows.
> This article applies to Windows. The <xref:System.Security.Cryptography.CspParameters> and <xref:System.Security.Cryptography.RSACryptoServiceProvider> classes are Windows-specific APIs for accessing CAPI-based hardware cryptographic providers such as smart cards.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
> This article applies to Windows. The <xref:System.Security.Cryptography.CspParameters> and <xref:System.Security.Cryptography.RSACryptoServiceProvider> classes are Windows-specific APIs for accessing CAPI-based hardware cryptographic providers such as smart cards.
> This article applies to Windows. The <xref:System.Security.Cryptography.CspParameters> and <xref:System.Security.Cryptography.RSACryptoServiceProvider> classes are Windows-specific APIs for accessing CAPI-based hardware cryptographic providers.

As written, it implies all smart cards are CAPI-based.

1. Create a new instance of the <xref:System.Security.Cryptography.CspParameters> class, passing the integer provider type and the provider name to the constructor.

2. Create a new instance of the <xref:System.Security.Cryptography.RNGCryptoServiceProvider>, passing the <xref:System.Security.Cryptography.CspParameters> object to the constructor.
2. Create a new instance of the <xref:System.Security.Cryptography.RNGCryptoServiceProvider>, passing the <xref:System.Security.Cryptography.CspParameters> object to the constructor. Note that <xref:System.Security.Cryptography.RNGCryptoServiceProvider> 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 <xref:System.Security.Cryptography.RandomNumberGenerator?displayProperty=nameWithType> instead.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
2. Create a new instance of the <xref:System.Security.Cryptography.RNGCryptoServiceProvider>, passing the <xref:System.Security.Cryptography.CspParameters> object to the constructor. Note that <xref:System.Security.Cryptography.RNGCryptoServiceProvider> 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 <xref:System.Security.Cryptography.RandomNumberGenerator?displayProperty=nameWithType> instead.
2. Create a new instance of the <xref:System.Security.Cryptography.RNGCryptoServiceProvider>, passing the <xref:System.Security.Cryptography.CspParameters> object to the constructor. Note that <xref:System.Security.Cryptography.RNGCryptoServiceProvider> is obsolete starting in .NET 6 (SYSLIB0023); however, it remains necessary for targeting specific CAPI-based hardware random number generators. For software-based random number generation, use <xref:System.Security.Cryptography.RandomNumberGenerator?displayProperty=nameWithType> instead.

used plural of generators rather than implying there's only one that someone would use this for. (In fact, I think there are zero, but, whatever).

Generally, this revision is removing duplicated warnings and superfluous appeals to authority.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants