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>
|
|
||
| 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
There was a problem hiding this comment.
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. |
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)
There was a problem hiding this comment.
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. |
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
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
IMO more future proof without last sentence
There was a problem hiding this comment.
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. |
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
There was a problem hiding this comment.
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. |
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
There was a problem hiding this comment.
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) |
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
| 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.
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. |
There was a problem hiding this comment.
| 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. |
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
Same irrelevant "Also consider"
| 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] | ||
| > [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). |
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
Hallucinated/typoed link. (Missing a / between 131 and a)
| > 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. |
| > [!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. | ||
|
|
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
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
| 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. |
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
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.
| 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). |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
| > 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. |
There was a problem hiding this comment.
| 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.
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