# The problem

I need to encrypt sensitive client information in my site and make sure that even in the worst case scenario that the site gets hacked the information cannot be retrieved. (I guess is similar to the credit cards situation)

# What I see around

I found many discussions regarding how to secure the credit card information and the approach I see around in forums is to use an algorithm like AES to encrypt the data using a key stored in the code or a configuration file or similar.

# My guess of whats wrong

Surely that would make the data secure as long as the attacker only gains control over the database and no other file in the server, but, if someone was good enough to break your security or find an exploitable hole in your system is a good chance he also gained access to the key, and therefore, is still a chance he can decrypt the data.

# A possible approach I think it could work

I'm thinking I could split the key in two parts, have one part in a file readable only by the web server's user and the other part shared by the users with rights to see that data in this way:

1. First the key is assigned to the first admin user and I use the user's password (which is not saved anywhere) to encrypt that part of the key and stored encrypted with that users information.
2. When another user is to be assigned that part of the key, then the first admin would decrypt the key and encrypt it with the new user's password and store that with that user's information, and like that for any other user.

Update for more clarification:
Having a message $m$ I will use a key $k$ that I will generate, and then when storing that key to use later I will split (or XOR it or something) so that $k$ now will be the result of some operation applied to $k_1$ and $k_2$, for example: $k = k_1 \oplus k_2$, then I save $k_1$ in a file readable only by the web server user. And to save $k_2$, I will use the user's password as key $s$ to encrypt $k_2$ and store it with the user information, and therefore there will be $n$ different $r$, where $r$ is $f(k_2, s)$ where $s$ is different by each user and therefore $r$ is different by each user.

So that to recover $m$ from the encrypted version $e$ and $d$ being the algorithm to decrypt we need to: $m$ = $d(e, d(k_2, s) \oplus k_1)$, and as $s$ is the user's password, you can't decrypt the message unless you the password of a person with access to the data; the system will never have stored the complete key anywhere.

This way even if gained access to the complete server there would be no full key to decrypt the sensitive data.

# Would that be a good way?

Does this makes sense? are other/better ways to achieve it? (I'm sure there are).
So, that is what I'm after, to know what other/better ways solve this can someone with actual knowledge on encryption can tell me (I consider my self a complete newbie on cryptography).

## Note:

It seems there is a confusion on my question being off topic. I want to clarify that I'm not looking for any implementation, what I'm after is to know what the recommended algorithm and techniques are suggested for this kind of situation, so I can proceed to research and implement them.

• Comments are not for extended discussion; this conversation has been moved to chat. – e-sushi Oct 1 '16 at 21:54

## 1. Clarifying the attacker model

You need to decide, what sort of attacks you want to protect from. The general eavesdropping adversary model suggest that the attacker can access your database and your entire system any time.

Another, more specific assumption can be mobile eavesdropping adversary. The "mobile" attributive relates to the fact that the adversary does not have access to your system any time, only for a limited time - for instance, somebody breaks in to your server and you detect the attack, patching the system, and with that move you "remove" the attacker. The attacker might break in again, but until that point the new information is considered to be secure. Any data accessible on your server during the time window of compromise considered to be leaked in full.

You may also consider, that some special hardware (e.g. HSM) stored private keys cannot be compromised - whether this assumption is correct or not depends on the further capabilities of the attacker

You also need to consider outsider or insider attack - outsider can be a hacker from the internet, insider can be a rogue employee.

It is important to note, what axapaxa pointed out clearly: an active attacker might be able to change the behavior of your site, and steal the passwords or do other malicious changes to gain access to the information. Protection against an active attacker is hard, would require digital signing of your webserver resources on a way, that the user can check it before connecting to your service - for instance, checking the code signature on your javascript, signed with a key not available on your webserver (so, TLS does not count...). Unfortunately, there is no such a standard - yet.

So, I will stick with the passive/eavesdropping adversary assumption. Still a nice challenge to solve :).

## 2. Encryption architectures

On the market, you can categorize the existing solutions for this matter based on two standpoints:

• where is the key managed and persistently stored
• where is the encryption process takes place

Key management categories:

• Managed by the site provider (this is you) with the site (e.g. simple database encryption)
• Managed by the site provider in a different system (e.g. a HSM or other special hardware)
• Managed by the end-user, in its own datacenter/on-premise server (e.g. HSM is provided by the end-user, your system get temporal keys from such hardware)
• Managed by the end-user, on its end-device (e.g. private keys in the browser; or the password of the user if you don't store it on your webserver)

Encryption process categories:

• Encryption takes place at the site provider's server (e.g. using simply a software encryption lib, with a key anywhere above)
• Encryption takes place at the site provider's, separate subsystem (e.g. using a special hardware, HSM, for the encryption process as well, not just for key management)
• Encryption takes place at the end-user on-premise server (e.g. encryption gateway like CipherCloud)
• Encryption takes place at the end-user device (e.g. using JavaScript to encrypt).

I will not go through all of the combinations here (16 cases) in details, only the end-device key management and encryption.

Note, that your suggested version falls into the category of End-device managed key with site provider managed encryption process. This can limit the damage of a mobile eavesdropping adversary, if you regularly patch and check the system. If you want to go down that road, that is fine, even not the most secure setup, I would suggest the following:

• Use PBKDF2, or preferably bcrypt, or scrypt (the last is the best) to derive a good secret from the password. Use random salt + at least 1000, but preferably 10,000 iterations, with scrypt sufficient size of memory map (larger the better, but webserver is a tricky question...). Let's say that the secret derived from the password is X.
• DO NOT store X for password validation.
• Use HKDF-Extract with random salt to derive from X (let's say, V), or derive from the password using PBKF2/bcrypt/scrypt using the same parameters as for X, but with a different IV. Store V for password validation.
• Use HSM or other special hardware to do the server side encryption of the data.
• DO NOT encrypt data with HSM+X, rather encrypt a key-encryption-key K. Encryption of actual data with K can be done outside of a HSM, simply using a crypto lib on your webserver.
• I suggest using AES-GCM with random IV for data encryption, AES-KW for key wrapping. You may also consider format-preserving encryption modes IF, and ONLY IF there is an unavoidable size constraint for the data, because format-preserving encryption modes are less secure than AES-GCM with random IV.

## 3. End-device managed key with end-device managed encryption (aka. end-to-end encryption)

You asked about a website, so I will focus only on WebCrypto API capabilities - an encryption library for JavaScript, provided by modern browsers. For applications, you may use other cryptolibs.

With WebCrypto, you can generate a secure random key, to use it for encryption. Encryption can take place at the frontend of the website, for instance before submiting a form, a JavaScript encrypts its content with AES-GCM. The keys can be stored in the local storage of the browser, which is never shared with your website, unlike cookies - it is kept local all the time.

However, if you want that a user access the information from another computer, I suggest that you use PBKDF2 to derive a secret from user password (using proper salt and proper number of iterations for stretching) on the browser side. Then, using this derived key, you can wrap the encryption keys with AES-KW - all supported by WebCrypto API.

This way, your server will not get access to the user password any-time, unless you do the password authentication properly. If you want to authenticate the user, do not send the password to your server, because that is an actual disclosure and the whole point of keywrapping, encryption will slip on this banana... instead of that, use PBKDF2 derived secret for authentication, with a completely random salt, different from what is used for encryption. You may also consider using SRP, SPAKE, AugPAKE, etc. for authentication - however, those are not supported by WebCrypto.

If you do not want to implement those, you may also consider using 0_kit, a project I am involved in, which provides all those features integrated, on top of WebCrypto and other JavaScript implementation of crypto algorithms.

Your scheme isn't invalid, but it has some flaws. I try to talk about those that I found:

## 1.Password isn't same thing as key

Key should be generated from CSPRNG (implementing this good is OS specific, so let's just assume you use good CSPRNG with proper seed). But since passwords are generated from user input, you need to take special care when converting them to key. This is done by using proper KDF. This was answered in details before, for example here .