Transparent Encryption of Properties in .NET, Part 1a: The Bugfixes
I recently posted my initial draft of a project that will provide secure, easy to use encryption of properties and fields in .NET types. Almost immediately some very knowledgeable people reached out to me with great suggestions on areas where I used suboptimal processes, as well as a few performance concerns that are not apparent in the basic unit tests I have in place. Thanks to them I am pleased to announce a few breaking changes to the initial 0.0.1 alpha release of my EncryptedType library.
First, credit where credit is due. Thanks to @tomasrestrepo for pointing out some areas of potential instability. Next, a huge thanks for the time and effort that Stan Drapkin put into looking through my code and having an extended conversation with me on how to make it better. If you are interested in .NET security (and why wouldn’t you be?) then take a look at Stan’s new book Security Driven .NET. It contains a huge amount of content and I plan to use it to continue to improve this project even further.
The first thing you will notice in the latest 0.0.3 (still alpha) release of this library is the move from a single integrity function for a type to individual integrity functions for each encrypted value. The integrity function is intended to prevent a user with read/write access to the data store but not access to the encryption keys from tampering with data by replacing the contents of one blob with the contents of another. This is to replicate the add_authenticator functionality of the ENCRYPTBYKEY function in SQL Server. The intent behind this change is to minimize the reuse of HMAC keys used for data validation.
The next change is a performance optimization. In the initial release I was performing a PBKDF2 derivation on the master encryption key every time a value was encrypted or decrypted. Since PBKDF2 derivation is designed to be slow this is certainly not how you would want to write a production implementation. I am now caching the derived encryption key in memory for the lifecycle of the type. This means improved performance, not just with key derivation but also with master key retrieval since the key server only needs to be contacted once per key lifespan within each type.
On a related note, I have also fixed the HMAC algorithm and reduced it to SHA256. This is a performance optimization as using more bits for the hash then there are in the encryption is unnecessary.
I have also modified the encryption to not just encrypt the value but to add a message authentication value as part of the encrypted payload. I am performing the HMAC against the encrypted data as that is the strongest method for ensuring the data is maximally protected against tampering. By doing this, I gain additional security against tampering as the encrypted data has another layer of validation that has to stay in tact. There is also a performance gain in decryption, as I first perform the hash check of the encrypted data and if it does not match then I don’t even have to bother decrypting the data, as it is by definition invalid.
In order to implement message authentication of the encrypted data I needed to generate and store a unique value to use as the key for the HMAC. While there is no known weakness in reusing the encryption key as the HMAC key I chose instead to just extend the PBKDF2 derivation I am performing on the encryption master key and use the next set of bits from that function as the HMAC key.
Since I am already caching the key derivation I also cache the MAC secret value in the same structure.
With these changes I have increased the integrity of the encrypted values and further hardened the data protection process. By caching the key derivation results I have increased performance without a significant impact on the security of the library.
As noted in my original post I do plan to continue enhancing this library and will be diving further into the implementation in future posts. I am also going to build out some sample projects and document those as well. You can always check out the source code on GitHub as well as on NuGet.
Please feel free to reach out to me via email or on Twitter if you have any feedback, concerns or questions. I am also very open to suggestions on related topics where this library can be useful.
Finally, I am writing this in early December and CodeMash is about a month away. I am once again running a door decorating competition during the days of the conference. If you are at any of the CodeMash hotels let your geek flag fly and show off how well you can decorate your hotel room door.
If you are not able to make it to CodeMash come out to CodepaLOUsa in Louisville, KY in February. I will be speaking there and also running another door decorating competition.
Stay secure and I hope to see you around!
- Transparent Encryption of Properties in .NET, Part 1: The Foundation
- Unofficial CodeMash 2014 Activities