Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
f4d3143
Add OWASP-aligned PBKDF2 iteration guidance and password hashing context
jeffhandley Apr 15, 2026
3e12992
Modernize AES encryption snippets and add CBC mode warnings
jeffhandley Apr 15, 2026
457c5df
Replace 1024-bit RSA and PKCS#1 v1.5 with 2048-bit RSA and OAEP
jeffhandley Apr 15, 2026
b70d56b
Add deprecation warnings for legacy crypto algorithms and APIs
jeffhandley Apr 15, 2026
62c2f8e
Fix correctness bugs in crypto code samples
jeffhandley Apr 15, 2026
acfaaeb
Address PR review feedback
jeffhandley Apr 16, 2026
0fbb4be
Revert DPAPI RNG to RNGCryptoServiceProvider for net461 compat
jeffhandley Apr 16, 2026
e440169
Address second round of PR review feedback
jeffhandley Apr 16, 2026
b5e2bbd
Fix RSACryptoServiceProvider obsoletion wording in hardware encryptio…
jeffhandley Apr 16, 2026
a356a6b
Add VB DPAPI project file and re-apply fixes
jeffhandley Apr 16, 2026
a512d7a
Restore hard-coded sample keys with illustration comments
jeffhandley Apr 16, 2026
59997bc
Address reviewer feedback: NIST over OWASP, no algorithm names, no AE…
jeffhandley Apr 16, 2026
a85b170
Address additional reviewer feedback on RSA key sizes and RNG wording
jeffhandley Apr 16, 2026
2309655
Modernize hardware encryption sample: SHA-1 to SHA-256, add disposal
jeffhandley Apr 16, 2026
cc3f5e8
Remove remaining AES-GCM reference and soften algorithm recommendations
jeffhandley Apr 16, 2026
1e65834
Align broader security docs with current NIST guidance
jeffhandley Apr 16, 2026
ea76609
Tighten remaining security compatibility docs
jeffhandley Apr 16, 2026
a812155
Remove remaining AES-GCM recommendations
jeffhandley Apr 16, 2026
2840c50
Fix DPAPI sample analyzer failures
jeffhandley Apr 16, 2026
20355a3
Fix CryptoWalkThru partial reads
jeffhandley Apr 16, 2026
cb76bf4
Apply feedback (top half)
bartonjs Apr 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/fundamentals/code-analysis/quality-rules/ca5387.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ This rule is similar to [CA5388](ca5388.md), but analysis determines that the it

Set the iteration count greater than or equal with 100,000 before calling <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. Consult the [OWASP Password Storage Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html) for up-to-date recommendations. For password storage scenarios, use the highest iteration count your performance budget allows. Also consider using <xref:System.Security.Cryptography.Rfc2898DeriveBytes.Pbkdf2*?displayProperty=nameWithType> (the one-shot static method) with <xref:System.Security.Cryptography.HashAlgorithmName.SHA256?displayProperty=nameWithType> or higher.
Comment thread
jeffhandley marked this conversation as resolved.
Outdated

Comment thread
jeffhandley marked this conversation as resolved.
## When to suppress warnings

It's safe to suppress a warning if you need to use a smaller iteration count for compatibility with existing data.
Expand Down
3 changes: 3 additions & 0 deletions docs/fundamentals/code-analysis/quality-rules/ca5388.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ This rule is similar to [CA5387](ca5387.md), but analysis can't determine if the

Set the iteration count greater than or equal with 100k before calling <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. Consult the [OWASP Password Storage Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html) for up-to-date recommendations. For password storage scenarios, use the highest iteration count your performance budget allows. Also consider using <xref:System.Security.Cryptography.Rfc2898DeriveBytes.Pbkdf2*?displayProperty=nameWithType> (the one-shot static method) with <xref:System.Security.Cryptography.HashAlgorithmName.SHA256?displayProperty=nameWithType> or higher.
Comment thread
jeffhandley marked this conversation as resolved.
Outdated

Comment thread
jeffhandley marked this conversation as resolved.
## When to suppress warnings

It's safe to suppress warnings from this rule if:
Expand Down
5 changes: 4 additions & 1 deletion docs/fundamentals/syslib-diagnostics/syslib0041.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ The following <xref:System.Security.Cryptography.Rfc2898DeriveBytes> constructor

Use a different constructor overload where you can explicitly specify the iteration count (the default is 1000) and hash algorithm name (the default is <xref:System.Security.Cryptography.HashAlgorithmName.SHA1?displayProperty=nameWithType>).

If you're using the default iteration count or default hash algorithm, consider moving to more secure values&mdash;that is, a larger iteration count or a newer hash algorithm.
If you're using the default iteration count or default hash algorithm, move to more secure values&mdash;that is, a much larger iteration count and a newer hash algorithm such as <xref:System.Security.Cryptography.HashAlgorithmName.SHA256?displayProperty=nameWithType> or higher.

> [!IMPORTANT]
> Consult the [OWASP Password Storage Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html) for current recommended iteration counts, and use the highest value your performance budget allows. Prefer the one-shot static method <xref:System.Security.Cryptography.Rfc2898DeriveBytes.Pbkdf2*?displayProperty=nameWithType> as recommended by [SYSLIB0060](syslib0060.md).
Comment thread
jeffhandley marked this conversation as resolved.
Outdated

Comment thread
jeffhandley marked this conversation as resolved.
Outdated
## Suppress a warning

Expand Down
9 changes: 9 additions & 0 deletions docs/standard/security/cryptographic-services.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,14 @@ Secret-key encryption is also referred to as symmetric encryption because the sa

A type of secret-key algorithm called a block cipher is used to encrypt one block of data at a time. Block ciphers such as Data Encryption Standard (DES), TripleDES, and Advanced Encryption Standard (AES) cryptographically transform an input block of *n* bytes into an output block of encrypted bytes. If you want to encrypt or decrypt a sequence of bytes, you have to do it block by block. Because *n* is small (8 bytes for DES and TripleDES; 16 bytes [the default], 24 bytes, or 32 bytes for AES), data values that are larger than *n* have to be encrypted one block at a time. Data values that are smaller than *n* have to be expanded to *n* in order to be processed.

> [!WARNING]
> DES and TripleDES (3DES) are deprecated and should not be used for new development. Use <xref:System.Security.Cryptography.Aes> instead, ideally with an authenticated encryption mode such as GCM (<xref:System.Security.Cryptography.AesGcm>).
Comment thread
jeffhandley marked this conversation as resolved.
Outdated

One simple form of block cipher is called the electronic codebook (ECB) mode. ECB mode is not considered secure, because it does not use an initialization vector to initialize the first plaintext block. For a given secret key *k*, a simple block cipher that does not use an initialization vector will encrypt the same input block of plaintext into the same output block of ciphertext. Therefore, if you have duplicate blocks in your input plaintext stream, you will have duplicate blocks in your output ciphertext stream. These duplicate output blocks alert unauthorized users to the weak encryption used the algorithms that might have been employed, and the possible modes of attack. The ECB cipher mode is therefore quite vulnerable to analysis, and ultimately, key discovery.

> [!WARNING]
> ECB mode must not be used for encryption. Use CBC mode with integrity verification, or preferably an authenticated mode such as GCM or CCM.

Comment thread
jeffhandley marked this conversation as resolved.
Outdated
The block cipher classes that are provided in the base class library use a default chaining mode called cipher-block chaining (CBC), although you can change this default if you want.

CBC ciphers overcome the problems associated with ECB ciphers by using an initialization vector (IV) to encrypt the first block of plaintext. Each subsequent block of plaintext undergoes a bitwise exclusive OR (`XOR`) operation with the previous ciphertext block before it is encrypted. Each ciphertext block is therefore dependent on all previous blocks. When this system is used, common message headers that might be known to an unauthorized user cannot be used to reverse-engineer a key.
Expand Down Expand Up @@ -172,6 +178,9 @@ None of the previous methods will prevent someone from reading Alice's messages,

.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.
Comment thread
jeffhandley marked this conversation as resolved.
Outdated

> [!WARNING]
> Do not use MD5 or SHA-1 for any security-sensitive purpose, including data integrity, digital signatures, or certificate validation. Use SHA-256 or higher from the SHA-2 family.
Comment thread
jeffhandley marked this conversation as resolved.
Outdated

## Random Number Generation

Random number generation is integral to many cryptographic operations. For example, cryptographic keys need to be as random as possible so that it is infeasible to reproduce them. Cryptographic random number generators must generate output that is computationally infeasible to predict with a probability that is better than one half. Therefore, any method of predicting the next output bit must not perform better than random guessing. The classes in .NET use random number generators to generate cryptographic keys.
Expand Down
4 changes: 2 additions & 2 deletions docs/standard/security/cryptographic-signatures.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ Module Program

' Generate signature
Using rsa As RSA = RSA.Create()
sharedParameters = rsa.ExportParameters(True)
sharedParameters = rsa.ExportParameters(False)
Dim rsaFormatter As New RSAPKCS1SignatureFormatter(rsa)
rsaFormatter.SetHashAlgorithm(NameOf(SHA256))

Expand All @@ -67,7 +67,7 @@ using System.Text;

using SHA256 alg = SHA256.Create();

byte[] data = Encoding.ASCII.GetBytes("Hello, from the .NET Docs!");
byte[] data = Encoding.UTF8.GetBytes("Hello, from the .NET Docs!");
Comment thread
jeffhandley marked this conversation as resolved.
byte[] hash = alg.ComputeHash(data);
Comment thread
jeffhandley marked this conversation as resolved.

RSAParameters sharedParameters;
Expand Down
3 changes: 3 additions & 0 deletions docs/standard/security/cryptography-model.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ Here is a list of recommended algorithms by application:
- Generating a key from a password:
- <xref:System.Security.Cryptography.Rfc2898DeriveBytes.Pbkdf2*?displayProperty=nameWithType>

> [!TIP]
> .NET's built-in password-based key derivation uses the PBKDF2 algorithm. When using PBKDF2, specify <xref:System.Security.Cryptography.HashAlgorithmName.SHA256?displayProperty=nameWithType> or higher, and use the highest iteration count your performance budget allows. Consult the [OWASP Password Storage Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html) for current iteration count recommendations and for guidance on alternative algorithms (such as Argon2id, bcrypt, or scrypt) that are available through third-party libraries.
Comment thread
jeffhandley marked this conversation as resolved.
Outdated

Comment thread
jeffhandley marked this conversation as resolved.
Outdated
## See also

- [Cryptographic Services](cryptographic-services.md)
Expand Down
21 changes: 12 additions & 9 deletions docs/standard/security/decrypting-data.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ Decryption is the reverse operation of encryption. For secret-key encryption, yo

## Symmetric decryption

> [!IMPORTANT]
> Symmetric decryption with CBC mode (the default for `Aes.Create()`) is vulnerable to padding oracle attacks if the ciphertext integrity isn't verified before decryption. Always verify data integrity (for example, by using an HMAC) before attempting to decrypt, or use authenticated encryption such as <xref:System.Security.Cryptography.AesGcm>. For more information, see [Timing vulnerabilities with CBC-mode symmetric decryption using padding](vulnerabilities-cbc-mode.md).

Comment thread
jeffhandley marked this conversation as resolved.
Comment thread
jeffhandley marked this conversation as resolved.
The decryption of data encrypted with symmetric algorithms is similar to the process used to encrypt data with symmetric algorithms. The <xref:System.Security.Cryptography.CryptoStream> class is used with symmetric cryptography classes provided by .NET to decrypt data read from any managed stream object.

The following example illustrates how to create a new instance of the default implementation class for the <xref:System.Security.Cryptography.Aes> algorithm. The instance is used to perform decryption on a <xref:System.Security.Cryptography.CryptoStream> object. This example first creates a new instance of the <xref:System.Security.Cryptography.Aes> implementation class. It reads the initialization vector (IV) value from a managed stream variable, `fileStream`. Next it instantiates a <xref:System.Security.Cryptography.CryptoStream> object and initializes it to the value of the `fileStream` instance. The <xref:System.Security.Cryptography.SymmetricAlgorithm.CreateDecryptor*?displayProperty=nameWithType> method from the <xref:System.Security.Cryptography.Aes> instance is passed the IV value and the same key that was used for encryption.
Expand Down Expand Up @@ -52,26 +55,26 @@ The following example illustrates the decryption of two arrays of bytes that rep

```vb
'Create a new instance of the RSA class.
Dim rsa As RSA = RSA.Create()
Dim rsa As RSA = RSA.Create(2048)
Comment thread
jeffhandley marked this conversation as resolved.

' Export the public key information and send it to a third party.
' Wait for the third party to encrypt some data and send it back.

'Decrypt the symmetric key and IV.
symmetricKey = rsa.Decrypt(encryptedSymmetricKey, RSAEncryptionPadding.Pkcs1)
symmetricIV = rsa.Decrypt(encryptedSymmetricIV, RSAEncryptionPadding.Pkcs1)
'Decrypt the symmetric key and IV using OAEP padding.
symmetricKey = rsa.Decrypt(encryptedSymmetricKey, RSAEncryptionPadding.OaepSHA256)
symmetricIV = rsa.Decrypt(encryptedSymmetricIV, RSAEncryptionPadding.OaepSHA256)
```

```csharp
//Create a new instance of the RSA class.
RSA rsa = RSA.Create();
// Create a new instance of the RSA class with at least 2048-bit key size.
RSA rsa = RSA.Create(2048);

// Export the public key information and send it to a third party.
// Wait for the third party to encrypt some data and send it back.

//Decrypt the symmetric key and IV.
symmetricKey = rsa.Decrypt(encryptedSymmetricKey, RSAEncryptionPadding.Pkcs1);
symmetricIV = rsa.Decrypt(encryptedSymmetricIV , RSAEncryptionPadding.Pkcs1);
// Decrypt the symmetric key and IV using OAEP padding.
symmetricKey = rsa.Decrypt(encryptedSymmetricKey, RSAEncryptionPadding.OaepSHA256);
symmetricIV = rsa.Decrypt(encryptedSymmetricIV, RSAEncryptionPadding.OaepSHA256);
```

## See also
Expand Down
Loading
Loading