First, just a brief intro on what I’m talking about. 

A few months ago (we finished it in July, actually, in a hotel in Atlanta while at Microsoft’s internal Global Briefing), Michael Stuart (local MCS consultant, developer extraordinaire and darn good friend) and I collaborated on an article for MSDN magazine.  The code for this article … and the component … was based on a successful implementation that we worked on together for a customer here in Houston.  This customer needed to encrypt highly sensitive data in a closed system.  The encryption need to be reversible on any machine (with configuration, of course) and the customer also needed to make sure that the data could all be store offsite and restored at any later time.  Also, this was a server-based application that would run a significant part of the business – so it had to be solid, stable and fast.  Naturally, the only logical choice was .NET J

If you are interested (and I hope you are), here’s a link to the article:  http://msdn.microsoft.com/msdnmag/issues/04/11/CryptoUtility/default.aspx.  

Now, we’ve gotten a good bit of feedback on this article.  The ratings seem to cluster at the high end and the low end (a lot of 1’s and a lot of 9’s) with a couple in the middle.  But really extreme overall.  I can’t say that I’m sure what that means.  The feedback that I’ve gotten in person has been extremely positive – but then, would someone tell me that it sucked to my face?  (Actually, I would hope so … and that they would follow it up with a good explanation as to why!) 

Regarding the feedback, Michael has already responded to some.  You can read it here: http://blogs.msdn.com/methylamine/archive/2004/11/18/265887.aspx.  I’ll try not to reiterate his points or, if I do, I’ll try to add something new or interesting to them. 

This is, by far, the largest comment and I want to respond to it in pieces.

The article misses the problem with a static key.
Actually, no it doesn’t.  A static key was a huge issue with this application and, due to the constraints of the application, one risk that we had to accept.  Dynamic keys are not without issue either … when the key changes, do a decrypt and re-encrypt the entire database?  Certainly, we don’t discuss it but that doesn’t mean that we didn’t consider it.  I would issue the challenge back to the commenter: How would you resolve this in a practical and secure manner?  And how would you resolve the issues of key management across a server farm as well as backup and restoration of dynamic keys? 
First of all, there is no discussion of how the key gets to all parties who will be encrypting and decrypting data. This is absolutely critical. With the approach that the article details, the key must travel over some medium between the client and the server.
Actually, there is.  I quote: Since we won't be distributing the key to anyone, we'll use symmetric encryption for our utility. It has the advantage of being significantly faster than an asymmetric algorithm, but we will need to take some precautions to protect the key.  It’s a closed system, so distributing the key is a non-issue for this implementation.  The key never travels between client and server.  The key is stored only on the server, where the data in encrypted and decrypted.  The big problem, as we state, is protecting the key on the server and anywhere else it is stored. 
If you send it over the network, then you are effectively not encrypting at all. You could use SSH, a floppy disk, etc., however the key is only as secure as that medium.
But we aren’t sending the key over the network.  This is a closed system.  We aren’t distributing the key.  Now, you did come close with a valid critique here … if you look at the admin tool, it will save the configuration settings to a file, including the partial key.  That file in unencrypted.  To protect this, you can (and should) use a password to generate a key to the file before it gets written.  Oh … but you missed that, didn’t you?  True enough, the key is only as secure as the medium … but there is also a great deal of context that must be taken into consideration.  Did we consider key rotation? Briefly.  But, considering that it is a closed system with no key exchange and no sending of the data to an uncontrolled system, it wasn’t worth the extra complexity.  With different parameters, the end decision may well have been different.
The rest of the comment is based on the previous assumptions, so I won’t go into it.  Had the architecture and usage of the system been different and we were transmitting the key over the network or if this system was used to secure data in transmission between client and server, these points would be valid.  But that’s not the case. When doing security, you need a holistic view of the system, your intentions, your assets and your threats.  So … there is no chance of a replay attack in this scenario. 
You did miss another potential issue … that of COM callers.  With a .NET caller, the LinkDemand ensures that we have only trusted callers.  But this doesn’t work with COM clients.  So … there is a potential for hijacking by a malicious COM component. 

 

Now, for some more comments …

Gee... Astonishing content, but you should have put a link to a simpler, more straightforward solution, so that a developer looking for some security would put it to work in a couple of minutes...
Michael detailed how to get started in his blog.  It is quite well documented.  The setup utility is straightforward and the tabs are numbered for the steps (1 … 2 … 3).  Run that tool and the utility will be set up and good to go.  The CryptoAdminUtility project does all of this.  And the CryptoAdminUtility will also check to make sure it works.  One thing must be said though: good security is not a simple solution.  It’s not a matter of “a couple of minutes” to get it going.  You need to spend a great deal of time with it.  You must analyze your needs for crypto and security.  And don’t expect to implement it in just a couple of minutes.  The devil’s in the details and, if you want good security, he’s pretty hairy devil … with some friends hanging out.  There is no magic security pixie dust.  While I’m a big believer in the KISS principle, some things are just complex to do right. 
With that said, .NET does make it a lot easier to do the right thing security-wise.  It’s certainly a lot easier than before … anyone that’s done any work with the raw Win32 CryptoAPI can attest to that. 

 

Excellent info and .exe, but it does not fully work on Win2000 or XPPro... not setting the CrytoRole up, Component services attributes not getting set. :(

Thanks for the compliment!  Well, I don’t know about Windows2000, but I do know that it works on XPPro.  That’s what I run on my machine and it’s set up just find and dandy.  It should work fine on Win2K, but I haven’t tested it myself so I might be wrong.  I wonder what issues you are experiencing with XPPro??  

 

Theory is great, but this article suffers from the same problem that I find many msdn articles suffer from: a lack of usable code and content. It is an excellent overview of modern cryptography with best practices and pitfalls, but I usually don't come to the website for fun. I come to find information that will allow me to write code to solve a solution. I don't feel I learned enough to incorporate the CryptoUtility into our application.
We actually tried to detail best practices and pitfalls.  Michael and I both discussed the number of articles that guide you through using the CryptoAPI, but nothing that really discussed this in context with an actual application and threat analysis.  A combination of theory and applicability to the real world.  I’m sorry that it wasn’t what you were looking for.  You can, of course, download the code and just start using it.  The docs are pretty good … and if you don’t like the VB’s style, that’s my fault.  I did the VB port (after, of course, running it through a conversion tool). 

Would've been nice if the authors mentioned the original developers of the DPAPI wrapper class (See "How To: Create a DPAPI Library")...ripoff...
As Michael already pointed out, we did have links to articles that this was derived from in the “flowerbox” at the top of the module.  Additionally, this code has been repeated so many times in so many places on Microsoft sites and other sites, that it’s hard to tell where exactly it came from.  In fact, I’d say that the article mentioned here and listed in the code module took it from another (uncredited) source.  I actually first remembering seeing it in Michael Howard’s Writing Secure Code … First Edition.  This was copyrighted in 2002 … and the article mentioned here was 11/2002.  Who came first? 
Still, the DPAPICryptographer was still derived from the original source.  Several small, sometimes subtle changes were made, particularly with making sure that all handles were cleaned up.  Michael found that the original leaked handles when he soak tested it over several days using NUnit.

Great Utility and very well explained. Had a few problems getting it installed so cannot give 9.
Well, that’s two with issues getting it installed.  More details would be good … what was hard and how could it be better?  Also, did you notice the (way cool) method of installing to the GAC … without using GacUtil???

Some general concepts. And if somebody makes partial keys by spliting [sic] key into shorter parts should have never said a word about security.
I’m not really sure I understand this.  What is the issue with the partial key?  Here’s why we went down that path.  First, there’s the issue of storage.  If we stored the full key on a medium (see above), we have potential issue if the USB drive (or whatever) gets out.  With this implementation, that won’t do it for you … you don’t have the whole thing.  The other part of the key came from the assembly’s strong name.  This is derived from a public/private key pair and the full key pair is required to apply the strong name.  So … we know that the assembly that is trying to decrypt the data is signed with a strong name key pair owned by the organization.  This provides some authentication of the caller … not a bad thing at all.  Additionally, if an attacker manages to get the key data stored in the registry, their job is only partially down … they still need to get the key that came from the strong name.  Security by obscurity?  Perhaps a bit.  If SBO is your only defense, you are in bad, bad shape.  However, as a small piece of a larger security strategy, it is perfectly valid and appropriate. 

Finally some code in VB and it's useful!
Thanks! J

Awesome coverage in one place for a lot of gotchas!
Thanks!  That’s what we tried to do. 

I think everyone should read this article.
I agree.  And I think I should get paid for every person who reads it.  J 
And I also think every developer should read Michael Howard’s Writing Secure Code.  Not only is it a darn good read and full of great information, Michael’s an awesome guy and deserves the $$.

Ahhh … well … enough said for now. If anyone has had any issues with installing, I’d really like some details.  If anyone has any additional comments, that’d be appreciated as well.