What is considered \"best practice\" for encrypting certain sensitive or personally identifiable data in a SQL database (under PCI, HIPAA, or other applicable compliance standar
I would add:
Keeping the IV hidden is not important. It's OK if the IV is public. Just use good IVs, which means, use a cryptographic-strong random number generator so that your IVs are indistinguishable from random.
Storing the encryption key separate from the data that it encrypts.
Add authentication to your encryption. For example, add an HMAC keyed with a second symmetric encryption key, covering the ciphertext. If you don't use some form of authenticated encryption, then your ciphertext could be modified, and you have no way of knowing (AES will decrypt garbage just fine.) You want any tampering of the ciphertext to be noticed.
I saw that one of the previous comments mentioned that it doesn't matter if you use CryptoAPI. I just wanted to point out that CryptoAPI is FIPS 140-2 compliant, while Bouncy Castle and the built-in managed classes (all the ones with "Managed" at the end of their names in the System.Security.Cryptography namespace) are not. If you have a requirement for FIPS compliance, it's probably easiest to for you to use CryptoAPI.
Taken more generic list of best practices, from OWASP (Cryptographic Storage Cheat Sheet):
Also, according to this Cisco article:
Your approach is good, with a few adjustments in my eyes (I code for PCI compliance generally):
Use CryptoAPI and Rijndael
Use Rijndael/AES256 at a minimum, regardless of other APIs
Generate IV and store it with the encrypted data
Good
Use DPAPI (Machine scope) to "protect" the symmetric key
Not sure if it matters. I'd just keep the IV next to the data that's encrypted, or if you're really paranoid on some other medium. Ensure that the IV is not accessible to the public.
Store the symmetric key in the registry or a file or the database, split the key and store parts in multiple places for added protection
Storing in multiple places will not help you if someone steals your media. It's a bit overkill to split the key up all over heck, but definitely do NOT store it with your IV and/or ciphertext. That'd be bad.
do not decrypt the data unless it is really needed, i.e. not upon read from the database. Instead, hold cipher text in memory.
Definitely. Holding cipher text in memory in fine, but don't pass it around anywhere, and don't decrypt except when you absolutely must, and even then don't EXPOSE the entire unencrypted dataset - only what is needed from it at the minimum. Also, do not hold the key in memory if possible - a memory dump could expose it.
Additions:
Hope these help. Some of them are my personal opinions but remain PCI compliant to the best of my knowledge.