Securing a Temporary Access Key for Encrypted Data - security

I am building a secure data store that can share secure information between a number of authenticated users, as well as letting unauthenticated users check data into the secure data store without making it public or divulging its contents.
Currently, the data is encrypted with a 1024-bit key, and has an associated RSA (2048-bit) Key Pair (with the Private Key being encrypted by the 1024-bit key). This means that if people want to check data in, then can use the RSA keys.
The 1024-bit key is also encrypted using User Secrets that are specific to each user, completely private, and randomly generated at the onset (or reset when requested). This means that the users can access the data without the key being public.
The final bit is storing the Users Secret. The secret itself is encrypted using another RSA (also with a 2048-bit key) Key Pair. The Public Key is associated with the user, and the Private Key is encrypted using their login Password.
When it comes to actually logging in, the user's username and password is validated, then a unique token is returned to the browser that will authorize it as a specific user.
At the login point, if it's valid, the password will be used to decrypt the RSA private key, so that the User Secret can be recovered.
But the user's password is only available to the system at one time, so I was going to use that moment to get the Users Secret and store it somewhere where it is available to the current login session, but no-one else.
Although I could store it in a separate database that would encrypt it (lets say with the Access Token) that would be lost when the user signs out, my worry is that if someone tries to break into the system when someone is logged in, they could recover the secret, and therefore, the rest of the data.
Does anyone have any ideas or references to implementations that can protect the User Secret from access by everyone except for the Session?

Related

Most secure way to temporarily store a password

I have the following use case:
My web application is used for creating prescriptions. When I send the prescription creation request to the government API it is signed with the current user's certificate. The certificate is stored on the application server and is encrypted with a password which only the user knows.
Users want to be able to store their password in my app temporarily so that they don't need to paste it in for each prescription they create.
What would be the most secure way to store this password? Couple of ideas:
Local storage in the browser.
Bad because anyone with an access to the user's device can see the
password even if they're not logged in. Also if the app is not running I have no way to clear the password if the desired storage time expires.
Frontend app memory.
Bad because if user refreshes the page or opens another tab the stored password is gone.
Backend, in database
This sounds like the best option because I can encrypt the password. Is it even worth encrypting though? I would have to encrypt it with some key stored on the same machine so if someone gains access to this machine the encryption doesn't matter because they would be able to decrypt it quite easily.
Separate the password encryption key and the encrypted password:
Generate and store a random key (and nonce / salt)
Encrypt the password (e.g. AES-256-GCM) with the random key
Store the encrypted password on your backend
Send the random key with the request to temporarily decrypt the password
Delete the encrypted password on the backend when the session expires
That way:
The random key stored in the browser can only be used within the current user session and is useless on its own
The encrypted password on your backed can only be used with the random key stored in the browser and is useless on its own

Share encrypted secrets between users without server-side decription

Is it possible to share encrypted data between a few (dynamic count) users without decryption on the server side?
For example:
We have secrets managing back-end
User A creates a secret, encrypt it somehow and send to the server for storing
User A wants to give access to this secret to the user B
User B now can get secret from the server, but ...
how can they decrypt this secret?
Here is an idea I have now:
Make 2 back-ends:
One for storing encrypted data and manage access between users
Another one for storing public key for decryption data
Here is what I'm concerned about here:
Server-owners can get a public key, get encrypted data and decrypt that data. I don't see any way to manage (include sharing public keys) between users when the server doesn't know which key decrypts data.
Perhaps anybody knows how lastpass, passbolt or any others services solved this problem?
You seem to have a misunderstanding of how public and private keys work.
For a given public/private key pair, anyone can encrypt data using the public key, but only the owner of the private key can decrypt the data.
So to pass data between users, each user should first:
create a public/private key pair
upload their public key to the server
If user A wants to send data to user B, they would do the following:
pull user B's public key from the server
encrypt the data using B's public key
upload the encrypted data to the server.
The server now holds the encrypted data, but it cannot decrypt it because it does not have B's private key, but only the public one.
User B can now pull the encrypted data from the server and decrypt it with their private key.
Note that this only deals with encryption. It does not address issues of authentication, i.e. ensuring that data comes from a known source.
This scheme can be made more secure by issuing certificates on each user's public key from a trusted authority and storing each user's certificate on the server, and by having users apply a digital signature to messages they encrypt by using their private key. The receiver of a message can then use the sender's public key and certificate to verify the signature.

How to store encrypted confidential user information in the database, which will need to be decrypted at runtime?

I am creating an application where I need to store client's information(Like their API Keys and API Secret to access my service, along with other confidential information).
Now, in the database, I want to store these in the encrypted format. In this regard, I decided to with symmetric key cryptography, AES in specific to encrypt the details.
However, for security purposes I want to use a different AES encryption key on a per client basis, so that even if the DB is compromised, all the data cannot be decrypted using a single key.
However, due to obvious reasons, I do not want to store my private keys in the DB with the encrypted informations.
So, I cannot seem to decide how to store my keys, especially since I need to have a binding that which key belongs to which client.
How can I achieve this, and which is the best approach in scenarios like this?
Use a KDF to derive an encryption key from the users password and then use this key to encrypt their private information.
When any action is to be taken that requires their API secret or whatever other private data you are storing, simply request the users password and use it to derive the key again and use the key to decrypt.
If you want users to be able to change their password, add an intermediary random key for each user and use this key to encrypt their data. Use the key derived from their password to encrypt the random key. Then when changing the users password, you only need to decrypt and re-encrypt the random key.

How to add a forgot password feature for the described system without compromising its security?

I created a security system that uses the users password to encrypt the users private key which is then stored on the database. So a user can only retrieve the private key if he enters the correct password which is then used to decrypt the private key stored on the database.
This system has some admirable security features but has the flaw that it is hard to do a 'forgotten password' option. The only way I could imagine is by storing a copy of all private keys somewhere else and encrypt them with a master server password and when a user forgets his password the server allows him to re encrypt his private key with the new password.
The problem with this method is that if the master server password where somehow compromised all account information would also be compromised with it. Is there a way of adding a reset password method without having to change the system to much or compromising its security?
If you escrow the private keys you need to have them on another server that is not directly connected to the Internet. Then rate limit and alarm all accesses to the escrowed keys. Also consider an HSM.

Storing private keys in database

I have the need to store private keys for multiple users, so that my server application can sign files on their behalf.
I want to store the private keys securely, but I couldn't find best practices around this. If I was storing a password I would salt+hash the password to make a hash that can't be easily turned back into the password. However, with a private key I need to store it in a way I can later retrieve it.
I was thinking I would encrypt the private key and then store it in my database. I originally thought each key would be encrypted with a different password (based on some properties of the user). However, those properties would most likely be stored in the database, so if my database got leaked then the attacker has everything.
I could encrypt all private keys with a single password that is only known to my application. Then an attacker would have to steal my database, and my application to do any harm.
Is there a technique/best practice I'm missing?
You could encrypt the private key with a symmetric key based on the users password. Simply store an additional salt and perform the password "hash" to get a separate key. Then use that as key for encrypting the private key. Note that it is required to use a Password Based Key Derivation Function (PBKDF) such as PBKDF2, bcrypt or scrypt to create a secure password hash (given the normal security level of a password).
If the user is not online at the time that a signature needs to be generated, then you should indeed protect the passwords in a sense that only you / our backoffice can decrypt the keys. You can use some user ID + your own secret key to calculate an encryption/decryption key. You may even want to generate a separate RSA key pair to perform hybrid encryption decryption.
Storing private keys on behalf of users is a very dangerous practice. There are a lot of ways for the private key to become exposed (e.g. side channel attacks). To do it professionally you should really be using an HSM somewhere in the process. If this is for any serious data, please consult a professional and a lawyer.

Resources