# Designing a scheme to store encrypted data on a backend

My goal is to design an encryption scheme for the application so that the backend stores encrypted data and the whole process of encoding and decoding happens on the frontend. And you can be sure that even if the backend database gets compromised the data is impossible to decrypt.

I'm in no way an expert on the topic but tried my best to grasp as much information as I could in the last couple of weeks. It's obviously not as easy as just doing the plain encryption of the data via master password from the user since it could be prone to KPA and rainbow tables.

For the purpose of this particular question to not make it too broad assume that the passwords that are being used are strong enough (e.g. 16+ characters including lower/uppercase, special symbols, etc). As well as the user device is not compromised in any way. So we talking only about the storage part of the encrypted data.

The scheme I came up with is:

• User has its master password
• When we need to encrypt something:
• We generate a random salt value
• Use Argon to derive a key from the master password and salt value from the previous step.
• Using the key from the previous step we encrypt the data with AES256 and send it over to the backend along with the salt used where it is stored.
• When we need to decrypt something:
• We do the same steps to get the key and decrypt the data to show it.

If I understood everything correctly the output for the encryption key should be consistent so that we can decrypt the info from anywhere.

Did I miss something? What attacks I haven't thought about?

EDIT1:

Users can choose both the pin and the master password. The idea I thought about is that if the salt could be generated from the pin consistently then this whole process could be done for example on a new user device and with the knowledge of both he could decrypt previous info, that way if the database gets compromised - the attacker won't know the salt that was used making it harder to decrypt.

EDIT2: Updated information in the question based on comments and an answer.

EDIT3: To increase security I could create a pepper key from the user's pin code (separate value, not related to the master password), but still apply random salt during encryption before sending it to the backend.

Based on the answers I'll use: Argon2 for key derivation from the master password, a random salt value for each derivation of not less than 128 bits, AES256-GCM for encryption, and optionally implement the pepper via key derivation from pin code.

Thanks to everybody!

• Please avoid PBKDF2 if possible. It requires a massive amount of iterations. Argon2id is the current recommendation for password-based key derivation. If you know passwords will be high in entropy, the parameters don't need to be that high. Why is the salt derived from a PIN? Can the user choose the PIN? What mode do you intend to use with AES? I'd also suggest 256-bit keys. Jan 21 at 15:43
• @samuel-lucas6 thanks for the link, I'll use argon then! User can choose the pin code and master password. Regarding AES mode I thought about using GCM or CBC mode. Jan 21 at 16:01
• @samuel-lucas6 I've edited the question to give a bit more context Jan 21 at 16:05
• It's extremely important that you use an authenticated mode/AEAD like AES-GCM to prevent an attacker from being able to tamper with the ciphertext. AES-CBC should only be used in legacy applications at this point as it's led to numerous attacks and better options are available. Jan 22 at 9:57

1. Salt is not secret. That's why it makes no sense to use PIN or any user input for this. Salt should be generated by some random number generator. The attacker will not get any advantage from knowing the salt.

2. It seems that you are going to use the same salt for many files. This destroys the effect of the salt. The purpose of the salt is to prevent brute-forcing of multiple targets (passwords, files) by the same process. For each file the attacker should be forced to use a separate brute-forcing process. That's why each salt should be used only once.

3. It seems you are going to store salt on the client. Keeping salt independent on files can be error prone. Since salt is not secret, better would be to store each salt together with the file where it was used. When user uploads encrypted file to the server, also the salt user for encryption of this file should be sent. The server should keep each file together with its specific salt. When user requests particular file, the server should return the file and the salt related to this file.

• So it basically means that I should generate a random salt for each encryption and send it over to the backend. Got it, I think I missed the point that keeping salt private doesn't give any advantage Jan 21 at 20:21
• updated my question keeping in mind your answer. Is there anything else that I got wrong? Jan 21 at 22:07
• @WardS: Use proper mode for AES, e.g. GCM. Jan 21 at 23:55
• Salts can be secret, which will improve security. That's just not common practice, with a pepper normally being applied separately if available. The bigger issue is how small the PIN is and that the user can choose it, meaning it's not guaranteed to be unique. Salts are normally 128 bits and random, although deterministic password managers often use someone's name as the salt. Kerberos does something similar. Jan 22 at 10:09
• @samuel-lucas6: 1) If it is secret, then it is not salt, but pepper. The author is asking about salt. 2) As I said in the answer, if PIN or any other user input is used to generate salt, the same salt will be used for all files of the same user, which destroys the effect of salt usage, because a single brute-forcing process can be used for multiple targets. Jan 22 at 10:15

I find it beyond bizarre that I can’t add a comment to a comment to my own answer, but whatever.

@mentallurg: He does not “clearly enumerate” that threat at all. For example, he doesn’t address the obvious question of whether the system should be secure against a malicious administrator - the most obvious and dangerous risk for any E2E encryption system. Do you seriously contend that the OP’s post provides a sufficient threat model against which to build a system?

———

I’m just an amateur too, but here’s how I see it.

You say that [part of] your goal is “to design an encryption scheme for the application so that the backend stores encrypted data and the whole process of encoding and decoding happens on the frontend”.

I would argue that that is not your goal at all!

When I go to the supermarket, my goal is not “to drive from here to there in a four-cylinder turbocharged vehicle”. It is instead, “to obtain some food that I can take back home and cook for dinner”. How I actually achieve that goal, is an entirely different thing: drive there in my own car, take an Uber, walk there on foot, ring them up and get them to deliver it, and so on.

In the case of cryptographic systems, as I understand it, goals are generally stated in the form of a “threat model”. A threat model is, in effect, a list of specific things that you do not want an attack to be able to do. You develop the threat model first, before you can choose an implementation to mitigate the threats described therein.

For example, your post says nothing about “integrity”, which (in my amateur definition) is the ability of someone receiving a ciphertext, to tell unequivocally whether that ciphertext has been altered in transit.

At least one mode of AES is “malleable”, meaning that an attacker can alter selected bits in the ciphertext, and that will alter just the corresponding bits in the decrypted plaintext - perhaps without the recipient being able to tell that! This can lead to nasty attacks, even when the attacker can not decrypt the data at all!

So one entry in your threat model might be: “The client must be able to tell unequivocably whether data received back from the server has been altered since it was sent to the server”, or somesuch.

As another example, what if an attacker intercepts a server response, and entirely replaces the ciphertext with one of their own choosing? Perhaps a previously intercepted, older version of the encrypted file that the client is trying to retrieve? Your threat model should probably say, “An attacker should not be able to replace a server response with one of their own choosing (without the client being able to see that)”.

As a final example, what if an attacker hacks the server, and modifies the encryption software that the server sends to the client? Now, when the client encrypts a file, the modified software sends a copy of the encryption key to the attacker! The attacker can now intercept the ciphertext and decrypt it - then even encrypt a plaintext of their own choice, and send that on to the server! What if a server admin does that (not an external attacker)? Should all that be in the threat model?

In conclusion: I suspect, with all due respect, that you haven’t thought about any of this. That means that any talk of AES, cipher modes, salts, who encrypts what/where, and so on, is entirely premature. There’s no point driving to the supermarket in your supercharged four-cylinder vehicle, if you don’t know what you want for dinner!

I suggest you develop a written threat model. Then others can help you to design a system to mitigate the threats therein.

Just my 2c 🙂

• The OP clearly formulates the threat and the goal: "if the backend database gets compromised the data is impossible to decrypt". Jan 22 at 10:21