Share encrypted secrets between users without server-side decription - security

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.

Related

How does a server verify a JWT? Where does the Public Key come from?

I am looking at the examples of JWT tokens in Node.js, and the verify function. My question is, where does this publicKey come from in verify(token, publicKey)? What is the flow?
The client (one of my users) has a client library installed on their computer/server, for making requests to my app myapp.com. In the myapp.com server, I call verify(token, publicKey). In the client library I generate the token using privateKey. The question is, how does the client get this private key generally? (i.e. is heroku login downloading a private key under the hood for making JWT requests, sort of thing?). And how do you fetch the public key? My understanding is, the client would download a private key, and our server would store the public key. Then given you have the public key and token, just call verify(token, publicKey). But how do you get the public key for the token on the server generally? Is the server storing one public key per private key disseminated to the client installed libraries?
The way I've usually seen JWTs used, there is only a very small number of trusted issuers, often only one, and the tokens are used as bearer tokens. In many cases, the issuer and the verifier are the same. In other cases, the verifier trusts one identity provider (e.g. Google) and fetches the public key from a https URL (example).
In your case, you could act as both the issuer and verifier:
You (the server) would generate one key pair.
Your API servers would trust JWTs signed by this key (and they'd only have the public key, since they only need to verify them).
An authentication/management server would have the private key, would authenticate your user, and issue them a JWT.
The client would never handle any keys, they'd simply store the signed JWT, and pass it as a bearer token when making a client request.
This is e.g. the approach described here as the approach used by GitHub. In this case, the issuer and verifier both belong to you. This approach is the easiest for both you (you can trust the content of the JWTs once you've verified the signature), and the client (they're just dealing with an opaque API key and don't need to deal with the complexities of JWTs at all).
A possible alternative approach could be:
A key pair is generated and the public key is associated with the account. This can be done in multiple ways (see below), but the end result is the same: The client has a private key, and your server knows the corresponding public key and which user it is associated with
When making a request, the client creates a JWT, signs it with its private key, and includes their user name in the token (e.g. in the iss and or sub field).
Your server takes the token, extracts the user name, looks up the public key associated with the account in the database, and validates the token.
This approach is used e.g. by Google Cloud for service account authentication.
Step 1 above can be done in two ways:
You authenticate the user, generate a key pair, associate the public key with the account, and let the user download their private key (via https of course). While it's generally considered somewhat bad form to generate keys for someone else (because you get to see a key that you don't need to know and you have to send it over the network), it's a lot easier, and Google is doing just this.
The user generates and stores the key pair. You authenticate the user, the user uploads the public key, you associate it with the account.
Either way, if you go with the "user signs a JWT" approach, you likely will want to provide client libraries, or at least code examples. Note also Google's requirement that the tokens must be short-lived, enforced by treating long-lived tokens as invalid. Without this rule and enforcement, what will happen is that many client developers will be annoyed about your complicated solution, manually sign a token that is valid forever on his laptop, and then use it as a bearer token.
heroku login actually doesn't use JWTs at all. It retrieves and stores an OAuth Bearer Token. This is most comparable to the first approach (client never handles any private keys, just gets an opaque blob, which happens to be a JWT that you can verify). The difference between a non-JWT token and a long-lived JWT is that your API servers have to look up the meaning and validity of the regular token in a database, whereas the JWT directly tells you the user identity, and possibly permissions and other attributes that you included when issuing it.

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.

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.

Securing a Temporary Access Key for Encrypted Data

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?

How to validate a SAML signature value

I have a customer who is sending a Security key. The encryption they are using is triple DES. Every Assertion they send has a signature value which needs to be validated to give them necessary privileges. Can you give me a sample code which does this?
Encryption and signing are two different animals. Triple DES is a symmetric key method (same key used for encryption and decryption). Digital signatures, on the other hand, use asymmetric keys (private/public key pair), where the signature is computed using the private key, and can be validated using the public key. So if your customer wants to include signatures in XML they send you, then they need to provide you with their public key.
For encryption, what is typical in SAML is to use XMLEncryption, which defines an XML format for including encryption key information and encrypted data in your SAML messages. Since exchange of a static symmetric key is problematic -- if it's intercepted, the interceptor can both encrypt and decrypt any messages -- what can be done instead is to use a dynamic symmetric key that gets generated anew for each message, encrypt the message using the key, then encrypt that key with the public key of a private/public encryption key pair and send it along with the message. The encrypted symmetric key can only be decrypted using the private half of the key pair used to encrypt it.
So the most significant difference here, from a key perspective, is that for signing, the customer holds the private key and must share the public key with you, while for encryption, you hold the private key and must share the public key with the customer.
If you want to validate the signature on the SAML Assertion or any of the Signable XML Objects, the OpenSAML WIKI has more information:
https://wiki.shibboleth.net/confluence/plugins/viewsource/viewpagesrc.action?pageId=3277047
You can look for 'Signature Verification Examples'.
This blog post also has an example as well:
https://blog.samlsecurity.com/2012/11/verifying-signatures-with-opensaml.html
To obtain a 'credential' for validation, see here:
https://blog.samlsecurity.com/2011/03/getting-credentials-in-opensaml.html
For info on how to unmarshal XML into an Open SAML object, see here:
https://wiki.shibboleth.net/confluence/display/OpenSAML/OSTwoUsrManJavaCreateFromXML

Resources