Whenever you encrypt data you had to solve the problem on where and how to store encryption keys securely. Now that you have encrypted the data and you have transferred the secret to the key you are as much as secure as the key! Where I can store the key securely? Well, ask yourself first, did you really have to encrypt your secrets? If you are using .NET and your secret are "windows secrets" such as connection strings, passwords the best option you have is to have windows handling the secrets for you such as using integrated security. For example, let say your web server connects to a SQL server, instead to store the credentials in clear in the web file (bad idea!) or encrypting them (ok idea) or ACLs the configuration file (better idea) you are much better off secure-wise by using windows trusted authentication, therefore no windows defined secrets have to be stored in a file. But what happen when you have to handle user defined secrets such as personal identified information, credit card information etc? Assume your web server encrypts a VISA card number to store the encrypted value in a SQL Server (very popular way to do it..) You certainly (I hope) decide to use symmetric encryption and you are faced with the dilemma on where to store the key securely. A security-wise solution is to encrypt the key and store it in a secure key container in dedicated server (I'll explain later why dedicated). You move the key from the web server to a dedicated server that is much more secure and less exposed (certainly being a DMZ!). How? In the January 2006 edition of MSDN Magazine Keith Brown shows a great nice example on how to write web applications that use secure key storage in .NET. First, public key cryptography is used to encrypt and decrypt the secret key.
With .NET you can use the RSACryptoServiceProvider API to generate a (PR) private/(PK) public key pairs to be stored "securely" in the CryptoAPI (CAPI) key container. The CAPI key container has actually two PR/PK key pairs, one for encrypting the secret such as secret keys and another for creating digital signatures. The key container is then stored in an hidden file directory (see previous post on this blog:"Where Cryptographic Service Providers store keys?"). As an option, CAPI allow you to save the PR key on a smartcard to reduce your attack surface even further. The key container can be given either user access or machine access. In the case of user access only the user that created the keys and the administrator of the machine can have access to the key pairs. In the case of machine access, you can set ACLs to grant access to specific user accounts on the machine where the key container resides. The best practice (and I agree) is to create an application to manage keys. Then you can restrict read access to the keys to the application that has to decrypt the key. In the article, the key manager application runs on the machine where the data has to be decrypted and allows to create and delete several key containers that can be retrieved by key container names. The key manager application also grants ACL (Access Control Lists) to give read access to the decryption agent. Once the key manager runs, it will generate a PK/PR pair. The PK is in base64 encoded format. During configuration such PK can be cut and pasted in the web config file of the web application that needs to encrypt the data. The encryptor application will generate the secret key such as using AES 256 bit random key, encrypt the data to be secured with the secret key and encrypt the key with the PK generated by the keymanager application. Finally, the key container name + encrypted AES key + the encrypted data + AES key length and initialization vector are given to the decryptor that will decrypt the AES key with his PR key (stored in the container) and use the AES key to decrypt the data.
To simplify (I hope) this is the scenario, step by step:
1) key manager running on the decryptor machine creates a CAPI Key container. The key container has a name and generates a PK/PR key pair
2) The encryptor running on a different machine (e.g. web server) get configured with the generated PK by copying it on the web.config file
3) The encryptor generates a secret AES key to encrypt the confidential data (i.e. credit card info, PII etc)
4) The encryptor encrypts the AES Key with the PK retrieved from the web.config file and appends other information such as the key container where the key pair is stored, the AES key length, the IV vector and the data encrypted and return it to the decryptor in a base64 blob
5) The decryptor takes the base64 encoded blob, gets the name of the container, gets the PR key from the container, decrypts the AES secret key with the PR key and then uses the AES key to decrypt the data
There are some important considerations:
1) the secret key is not stored on the web server
2) the secret key is encrypted with RSA encryption and stored encrypted in a more secure decryptor machine (such as behind the DMZ)
3) public key encryption provides confidentiality to the secret key exchanged between the web server (encryptor) and the decryptor machine
4) the PK/PR key pair to encrypt the secret key is stored securely in the key container
5) only the web server and the decryptor can have access to the key container
6) the ciphertext is stored in another machine
The application is an example of factoring encryption, such as using dedicated agents on different machines for encryption, decryption and storage of ciphertext.
Factoring encryption offer several advantages:
1) increases security because limit exposure of the secrets. In the example the most exposed machine such as the encryption web server not to store any secret.
2) optimizes performance by dedicating different resources to different operations. This is a big deal when dealing with public encryption since decryption is sever orders slower than encryption (in the article it is shown that encrypting a with RSA 4096 bit takes 3 milliseconds for encryption and 0.3 seconds (100 times slower!) for decryption).
As the article points out, you might want to use dedicated hardware solutions to speed up the process of decryption by offloading the process from the main CPU (it might just add 4000 $ to your hardware bill..) Another important point is to protect integrity of the secret key while transmitting it between servers.
One of things we the I stress out at my BSS class (check Foundstone training) is that when you use symmetric algorithms such as AES that is a CBC Cipher Block Chaining algorithm you do not protect the integrity of the data (that is you do not provide tampering protection), if you tamper the encrypted data during transmission you can still decrypt garbage. You might want to use digital signatures and hash the encrypted key to protect it from tampering or provide SSL between web server and the decryptor. This is also mentioned in the article (very good)
The article referred here is available on msdn web site