JWT, is it safe to use the same key pair to sign from server-side and encrypt from client-side? - authentication

My private key is server-side and the public one are client-side. I use them to sign JWT from my server and sent to my clients, for authorisation. I have now to also encrypt the user password client-side during the authentication using JWE and verify it from server-side.
This two use case have the same requirements: private key is server-side, public key are client-side, and encryption algorithms can be the same. This is why I am thinking to use the same key pair but I am afraid to miss something about security and I would like to have confirmation, is it safe?

As best practice, you should not re-use the same key pair for different purposes. Just have two distinct key pairs, one for digital signatures, the other for public key encryption.

Related

Human readable way to represent PGP keys (Decentralized client authentication)

I'm working on a distributed application, and we need a way to authorize clients. Every client has a PGP keypair associated with them, and we require them to enter their private key (which is not stored) through which their pubkey is derived and used to identify clients and modify their fields on the distributed database.
Now, considering user experience, entering a private key on a website whenever you need to do something is troublesome. But we also cannot maintain a central database for username/password based authentication as that creates a single failure point (not what the distributed application is meant to do)
I am hoping there is some way to get an easier to remember human readable descriptor of the private key which can be used to authenticate if something like that exists. Any other ideas are appreciated too.
I'll throw a bunch of ideas to clarify the question:
Are you certain that PGP is suited for your needs?
I feel like you should provide some more details to be sure:
- How are the private and public keys used exactly? I understand the following : user inputs its private key, information is decrypted and modified, public key is deduced from private and used to encrypt the updated information.
- How is this different from using a regular password and being able to authenticate the user and encrypt data?
- You seems to send private keys on the network, and they should remain private.
How you could use a regular password:
User has a password, your application uses a function (e.g sha256, KDF,...) to make it usable by classical encryption algorithms (e.g AES). With the same (not stored) key, you can then encrypt and decrypt datas. You just have to make sure that decryption is valid, by adding a known value at the beginning of the data (e.g a part of the key).
Quick example:
password: "WeakPassword"
key: sha256("WeakPassword"+"MySalt") = 493e3ae...b2eec8ef
Decrypt(data,key)
clearData = "493e3ae{123;456}" //valid, because you can check the beginning
Encrypt(clearData,key)
Advantages: usable passwords, faster symmetric encryption
Use a QR code
If you stick to PGP and have a camera available it is pretty handy.
You could also use hexadecimal, base64, ... but for a 2048 bits RSA key, that still gets you hundreds of characters.

Do public keys HAVE to be used used to encrypt?

My question is: Does the public key in a asymmetric key have to be used to encrypt data or can it go either way (be used to decrypt)?
In RSA the public and private key technically fulfill the same role, one can decrypt what the other encrypted. The only difference is that one is made available to all parties.
Public keys can only be used to encrypt data, and private keys can only be used to decrypt data.
If you could decrypt data using a public key, that defeats the purpose of encryption.
Imagine you put your public key on your Facebook profile so that people can encrypt emails to you if they wish. If public keys could decrypt, then anyone that viewed your profile would have the key to all your emails (that were encrypted using that key pair).

Authentication/Decryption using a subset of Key

Is there a cryptographic system where a user(s) can be authenticated (or they can unlock a document) only if they present a subset, of more than one, the of valid keys?
Thanks in advance.
Non-anonymous authentication
If you don't require the users contributing to the successful authentication to remain anonymous, it's easy: The server generates a random nonce and sends it to the subset of users. Each user signs the nonce with his/her private signature key and sends the signature to the server. The server verifies each signature and if enough of them are present then the subset has successfully authenticated.
(Anonymous) Decryption
Someone else here might know of an RFC or a library for that purpose, but If there is none, I would design it like this: Split the secret into n parts where k of them are necessary to recreate the secret using Shamir's Secret Sharing. For each of the n users encrypt a different part of the split up secret with his/her public encryption key. When k of them decrypt their part of the split up secret, they can recreate the secret.
If the public key encryption is deterministic you can even make it anonymous in the sense that if you can get to the secret you can check that each other subset of k users would also be able to get the secret: In preparation of the protocol run you also have to designate a fixed x-coordinate for each user in addition to the public encryption key. When a subset of users successfully recreated the secret and thus the polynomial, they can evaluate it at each of the users x-coordinate and encrypt it with their public key. If the result is identical to those generated by the server, every subset of k users can decrypt the secret.
(Note that deterministic encryption has some caveats. For example, if the plaintext space is small, an attacker can just encrypt each plaintext and compare the result to the given ciphertext.)
Corollary: Anonymous authentication
Using the anonymous decryption you can create an anonymous authentication protocol by having the server encrypt a random nonce for k out of n people in the way described above and send it to the subset of users. They decrypt the nonce, check that each subset of k users would also be able to decrypt it and send the nonce back to the server.

Why use an API key and secret?

I came across many APIs that give the user both an API key and a secret. But my question is: what is the difference between both?
In my eyes, one key can be enough. Say I have a key and only I and the server know it. I create a HMAC hash with this key and do an API call. On the server, we create the HMAC hash again and compare it with the sent hash. If it's the same, the call is authenticated.
So why use two keys?
Edit: or is that API key used to lookup the API secret?
You need two separate keys, one that tells them who you are, and the other one that proves you are who you say you are.
The "key" is your user ID, and the "secret" is your password. They just use the "key" and "secret" terms because that's how they've implemented it.
Simple answer, if I understood it correctly...
If you use your API key for encryption, how will the service know who is contacting them? How will they decrypt that message?
You use API key to state who you are, this is what you are sending in plain text.
The SECRET key you do not send to anyone. You simply use it for encryption. Then you send the encrypted message. You do not send the key that was used for encryption, that would defeat the purpose.
One thing that I did not see mentioned here, although it is an extension of Marcus Adams's answer, is that you should not be using a single piece of information to both identify and authenticate a user if there is a possibility of timing attacks, which can use the differences in response times to guess how far a string comparison got.
If you are using a system which uses a "key" to look up the user or credential, that piece of information could be incrementally guessed over time by sending thousands of requests and examining the time that it takes for your database to find (or not find) a record. This is especially true if the "key" is stored in plaintext instead of a one-way hash of the key. You would want to store users's keys in a plaintext or symmetrically-encrypted for if you need to be able to display the key to the user again.
By having a second piece of information, or "secret", you can first look up the user or credential using the "key", which could be vulnerable to a timing attack, then use a timing-safe compare function to check the value of the "secret".
Here is Python's implementation of that function:
https://github.com/python/cpython/blob/cd8295ff758891f21084a6a5ad3403d35dda38f7/Modules/_operator.c#L727
And it is exposed in the hmac lib (and probably others):
https://docs.python.org/3/library/hmac.html#hmac.compare_digest
One thing to note here is that I don't think that this kind of attack will work on values that are hashed or encrypted before lookup, because the values that are being compared change randomly each time a character in the input string changes. I found a good explanation of this here.
Solutions for storing API keys would then be:
Use a separate key and secret, use the key to look up the record, and use a timing-safe compare to check the secret. This allows you to show the user the key and secret to a user again.
Use a separate key and secret, use symmetrical, deterministic encryption on the secret, and do a normal comparison of encrypted secrets. This allows you to show the user the key and secret again, and could save you from having to implement a timing-safe comparison.
Use a separate key and secret, display the secret, hash and store it, then do a normal comparison of the hashed secret. This removes the necessity to use two-way encryption, and has the added benefit of keeping your secret secure if the system is compromised. It has the downside that you cannot show the secret to the user again.
Use a single key, show it to the user once, hash it, then do a normal lookup of the hashed or encrypted key. This uses a single key, but it is not able to be shown to the user again. Has the benefit of keeping keys secure if the system is compromised.
Use a single key, show it to the user once, encrypt it, and do a normal lookup of the encrypted secret. Can be shown to the user again, but at the cost of having keys vulnerable if they system is compromised.
Of these, I think that 3 is the best balance of security and convenience. I have seen this implemented on many websites when getting keys issued.
Also, I invite any actual security experts to critique this answer. I just wanted to get this out there as another discussion point.
There are answers explaining what the secret and (public) key is. It's a public-private key pair that they give confusing names to. But nobody says why the APIs require both, and many APIs only give you one secret! I've also never seen any API's docs explain why they have two keys, so the best I can do is speculate...
It's best to put only your public key in your request and sign the request locally with your private key; sending anything more shouldn't be needed. But some get away with just having the secret in the request. Ok, any good API will use some transport security like TLS (usually over HTTPS). But you're still exposing your private key to the server that way, increasing the risk of them somehow mishandling it (see: GitHub and Twitter's password logging bug recently discovered). And HTTPS is theoretically just as secure, but there are always implementation flaws out there.
But many – actually most it seems – APIs have you send both keys in requests since that's easier than making people do their own signatures; can't have pure cURL examples otherwise! In that case, it's pointless to have them separate. I guess the separate keys are just for in case they change the API later to take advantage of them. Or some have a client library that might do it the more secure way.

Public key fingerprint vs Digital Signature

How do the Public key fingerprint and Digital Signature differs ? Or both are same ?
if they are different, what is the application of public key fingerprint ?
Thanks
a public key fingerprint is a short sequence of bytes used to authenticate or look up a longer public key. Fingerprints are created by applying a cryptographic hash function to a public key. Since fingerprints are shorter than the keys they refer to, they can be used to simplify certain key management tasks
A digital signature is a mathematical scheme for demonstrating the authenticity of a digital message or document. A valid digital signature gives a recipient reason to believe that the message was created by a known sender, and that it was not altered in transit. Digital signatures are commonly used for software distribution, financial transactions, and in other cases where it is important to detect forgery or tampering
A public key fingerprint is a short version of a public key which is used to authenticate a longer public key, if they do not match that means that the longer public key has been tampered with. So basically a digital signature is something that is signed by a user which only that user can sign so you can be sure that it is coming from that user.
So a public key fingerprint is used by a client and the digital signature is used by the server
The fingerprint is the hash of a key. A digital signature is tied to some message, and is typically a one-way encrypted hash of the message.
The two serve different purposes: You can put the public key fingerprint on your card or, if you recognize the other person on the phone, use it to verify you got the right public key(s). It doesn't say anything by itself. The digital signature, on the other hand, says that the message was signed with that key over there, and you don't need any other channel for verification of that fact.