System.Security.Cryptography.Aes has some strange APIs, which make it difficult to use. #109887
-
Summary
MotivationWhen I use an instance of the Aes class, I often find myself deeply puzzled.
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (KeyValue != null)
{
Array.Clear(KeyValue);
KeyValue = null;
}
if (IVValue != null)
{
Array.Clear(IVValue);
IVValue = null;
}
}
} Is it really necessary to dispose? |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 3 replies
-
These apis were introduced in very different versions. There are some legacy designs from 20 years ago, which were proved as inconvenient. For example, the CipherMode property were introduced in .NET Framework 1.1 at 2004, while the EncryptCbc method were introduced in .NET 6 at 2021. You can see the design review of additional methods at #2406.
When it comes to cryptographic, it can be important to clear sensitive information after use. |
Beta Was this translation helpful? Give feedback.
-
Certain implementations may have unmanaged resources to dispose, like https://referencesource.microsoft.com/#System.Core/System/Security/Cryptography/AesCryptoServiceProvider.cs,270 |
Beta Was this translation helpful? Give feedback.
-
Even were it "unnecessary", it can't stop being IDisposable. Clearing the key out is important for some people, particularly anyone who has to operate under FedRAMP/FIPS/FISMA data processing standards, which dictate that a secret key must be removed from memory when it is no longer necessary. And also, that implementation is just the base class behavior. Implementations like
It also contains the Mode property to distinguish CBC from ECB (et al). The methods were created because the property bag design is bad. The IV property isn't used by all operations. The FeedbackSize property isn't used by all operations. They're still there because we can't remove them... and because leaving them alone makes it easier for someone to work with both .NET and .NET Framework using the legacy CreateEncryptor()/CreateDecryptor() paradigm. The new methods show clearly what data they use, except the one thing they all share, the key, which is what the object itself represents.
Why? A) It'd be against design guidelines (don't add extension methods on a type in the same assembly that defines it [except for some special cases]), B) it means that all implementations have to be done by changing the Mode property, et al, and calling CreateEncryptor/CreateDecryptor... and that's actually a bad way to implement them. None of the built-in implementations call CreateEncryptor from their newer methods.
The
The logical concept of "the key" is used by all of the new methods, as well as the parameterless CreateEncryptor and CreateDecryptor legacy methods. For most implementations that means the key property, but for AesCng (at least) it might not. No other property is read by the Encrypt[Mode] or Decrypt[Mode] methods. They're only used by the CreateEncryptor and CreateDecryptor overloads. Which properties get read depend on the value of the Mode property. If you're writing code for .NET 5+ (nee Core) only, use the Encrypt and Decrypt methods, and ignore everything else except Key. If you're writing code for .NET Framework or .NET Standard you have to use the legacy properties and the CreateEncryptor/CreateDecryptor methods. If you're writing for both you can choose to do |
Beta Was this translation helpful? Give feedback.
Even were it "unnecessary", it can't stop being IDisposable.
Clearing the key out is important for some people, particularly anyone who has to operate under FedRAMP/FIPS/FISMA data processing standards, which dictate that a secret key must be removed from memory when it is no longer necessary.
And also, that implementation is just the base class behavior. Implementations like
AesCryptoServiceProvider
in .NET Framework have interop considerations... specifically, SafeHandle values that should be disposed. Sure, those values could b…