ASP.NET Cryptography Insecurities

I've found a serious shortcoming in one of the security methods I've been using. I've inherited two projects in which social security numbers were stored in a database in an unencrypted format. For the web application I don't think the SQL Server 2005 built-in encryption methods are an option because the web hosting company is still using SQL Server 2000. Instead, I used the .NET Framework's built-in cryptography classes found in the System.Security.Cryptography namespace. I used the Rijndael (aka Advanced Encryption Standard (AES)) cipher in a custom assembly which I uploaded to the web server's bin directory without the source code. This encryption method relies on a 128 bit key and an initialization vector (IV) which are basically just byte arrays of 16 numbers.

The shortcoming with this security solution is that the 128 key and initialization vector (IV) can be obtained from the DLL by using Lutz Roeder's .NET Reflector. I was able to reverse engineer my DLL and easily found the keys you would need to decrypt the social security numbers. I then tried using Dotfuscator Community Edition 3.0 to see if it could obscure the keys but I was still able to find them although the variables were renamed a.a and a.b. I was still able to determine that RijndaelManaged was the encryption method and the byte arrays make it obvious that these are the keys (which are identical to the non-obfuscated version). I doubt that any obfuscator tool is going to touch a byte array so you really cannot have your keys in a DLL that can be reversed engineered.

The MSDN article on the RijndaelManaged.CreateEncryptor Method suggests that when you create a new instance of the RijndaelManaged class, it generates a new key and initialization vector (IV). However, this is not very clear and the sample code I've seen used byte arrays to specify the key and initialization vector.

Of course, if someone has a copy of your database and your application files then you are probably screwed anyway.

1 Comment

  • Why not use an encrypted configuration section (using DPAPI) to store the key and initialization vector? Another option is to write some SQL Server functions to read/write the SSNs and decrypt/encrypt them (using an extended stored procedure to perform the operations).

Comments have been disabled for this content.