I am developing a .NET application spanning multiple servers who should all be able to decrypt data stored in a SQL database. My database is multi-company where each company has its own GUID. since the data being encrypted is personally identifiable information (PII) and the requirement is to be PII compliant, I am encrypting it all with AES256-CBC were the IV is generated randomly at each encryption and data is stored in a binary field in this format

<version><IV><encrypted data>

the version field is for future use should I need to change encryption/decryption algorithm, the IV is random and then the encrypted data.

as for the AES key, I am hashing the company GUID the database record belongs to using SHA256 (resulting in the same key on each server that is trying to decrypt the record from the DB) I am unable to use SQL encryption for various reasons and must use code for encryption/decryption.

Is this PII encryption scheme secure? Any downsides? I know that no matter what key generation code I build, a hacker if he is already on my server could use a debugger or look at the .NET IL to decode what I am doing. That said, if he only gets the raw data from the DB is that data secure?

  • 2
    $\begingroup$ a) How secret are the GUIDs? b) How easy are they to guess? $\endgroup$ – SEJPM Jul 10 '16 at 12:49
  • $\begingroup$ As for a solution to your problem: What about storing a symmetric key on a trusted server (preferably a HSM?) and letting your application server query this server to get an HMAC of the GUID created using the secret server-stored key. This HMAC tag can then subsequently be used as the base for more secure keys. $\endgroup$ – SEJPM Jul 11 '16 at 19:03

It isn't secure at all unless the GUIDs are completely inaccessible to everything except the encryption code. I doubt that is the case in a real application; I assume every DB query and API call passes those GUIDs around. Any anyone who can access the database can easily hash the GUIDs as well and decrypt any of the data. Your scheme as described is basically pointless obfuscation, not strong encryption.

One alternative would be to use the per-customer GUID as a salt for the input to HKDF, and then use a global secret key for the whole app as the key input to HKDF. This will give you a per-customer secret key while not requiring the GUIDs to be secret.

Protecting this "master" app key will be challenging, but protecting it in the same way you protect your TLS certificate private keys makes sense as compromising either would break all security.

  • $\begingroup$ I agree that the Guid is visible and a hacker will try to use it as the key (I would). That said, I am not using the Guid directly so lets assume I take the Guid and run 20 hash transformations on it and pack it all into a .NET dll that cannot be decompiled. So unless the hacker has access to my code to see the sequence of hash transformations, the Guid is useless to him and will not decode the data. Same concept can be applied with HKDF (as long as it's black boxed into a protected code). If the hacker can run a debugger on my prod server I assume all is lost though $\endgroup$ – Dani Avni Jul 11 '16 at 7:51
  • 1
    $\begingroup$ @DaniAvni: "So unless the hacker has access to my code to see the sequence of hash transformations, the Guid is useless to him and will not decode the data. [...] If the hacker can run a debugger on my prod server I assume all is lost though." Which should tell you right away that you're on the wrong track. Read up on Kerckhoff's principle. You really need to have secret keys, and some sort of key-management solution. $\endgroup$ – Luis Casillas Jul 11 '16 at 19:00
  • $\begingroup$ @rmalayter: Your suggestion to use the GUID as a "salt" to HKDF is a technical mistake; what you should say is to use the GUID as the info parameter. In HKDF, the term "salt" is used to mean a non-secret random value given as an optional argument to the HKDF-Extract function. The "info" is "optional context and application specific information" given to the HKDF-Expand function. See RFC 5869. $\endgroup$ – Luis Casillas Jul 11 '16 at 19:06
  • $\begingroup$ @Luis_Cadillias: no the GUID in this case is a non-secret random value. A salt. The info parameter is also non-secret for domain separation, in this case should be something like the string "per-customer database encryption key". You could then use the same inputs with a different info to get a separate key for some other purpose. $\endgroup$ – rmalayter Jul 12 '16 at 2:59
  • 1
    $\begingroup$ Let me explain what I mean "all is lost with a debugger", If I use for example Amazon KSM, in code I have to create a KSM client, get a reference to a key and then call the encrypt/decrypt methods with the key reference. My code has no idea what is the actual key (except it's id). If a hacker puts a breakpoint just after I decode something then he could know the decode of a specific encoded value. True it does not give him access to decode the rest of the DB. Now he could write some code (using credentials from debugger) and call the amazon client and in a loop decode all values. $\endgroup$ – Dani Avni Jul 12 '16 at 6:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.