Human readable way to represent PGP keys (Decentralized client authentication) - 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.

Related

How to store encryption key?

I look out many password managers like keeper, 1password, secret-in and I am following secret-in password manager to create my own project and trying to add same features, but got stuck at storing the data of users like his/her secrets, payment secrets in encrypted form. I read encryption model of keeper here but still didn't understand. Where to store a server side encryption key?
I have some data that is symmetrically encrypted with a single key in my database. Rather than hard coding it into my code, I am looking for a safer way to store the encryption key. Where can I safely store it?
The approach here is quite simple.
You only send encrypted data to the server for storage/backup.
The encrypted data received doesn't come with a key.
You need to ensure all encryption and decryption occurs locally on the users device. Thus the user needs to supply the key.
Users aren't good at providing high quality key material, so instead, require the user to provide a password, take that password and pass it through a hash-based key derivation function with parameters that make the function slow (high ops, high mem requirements). An algorithm like pbkdf2 with a strong PRF like HMAC-SHA-2 should be sufficient.
Update:
To answer your specific questions, you need to perform the following steps, you will need to use a cryptographic library that supports key derivation from password and symmetric encryption, like libsodium.
request password from user on first use
run this password through key derivation to derive a key from it: https://libsodium.gitbook.io/doc/key_derivation
execute encryption of user data with key: https://libsodium.gitbook.io/doc/secret-key_cryptography
destroy the key and send data to server for backup

what happens to JWT if someone gets my private and public key?

It seems to me that if my private and public key are compromised (which i use to sign and verify JWTs), that anyone can independently generate JWT tokens for themselves to use on my API?
Whereas on the other hand if I generated my own tokens myself, and stored a look-up table of 'one-way-hashed user id' => 'token', then if someone broke into my system, they would not be able to generate tokens to use on my API, and they would also not be able to use the tokens (because they would not know which token belonged to which user)
If someone breaks into your system and it is still secure, then you made a secure system; nothing to worry about.
with JWT, it appears to me that if someone breaks in, I do have something to worry about.
It seems to me that if my private and public key are compromised (which i use to sign and verify JWTs), that anyone can independently generate JWT tokens for themselves to use on my API?
Yes, that's correct.
Public keys are intended to be public and can be distributed.
On the other hand, private keys are supposed to be private and must be kept secure in your server. Anyone who has access to the private keys should be capable to issue tokens.
Disclosing your private key is a huge security breach.
It seems to me that if my private and public key are compromised (which i use to sign and verify JWTs), that anyone can independently generate JWT tokens for themselves to use on my API?
As also pointed out that you need to keep your Private Key Secure , the best way to keep it secure is to use an HSM for signing your data , in this case you can extend the JWT generator to sign the data through a crypto dll inside the HSM , this insures that the private key is never exposed outside the HSM
Whereas on the other hand if I generated my own tokens myself, and
stored a look-up table of 'one-way-hashed user id' => 'token',
Any one can generate your non-keyed hash. Secure hashes involved a private key which becomes a digital signature. Now we've come full circle, because that's exactly what a JWT token is.
Alternatively, you store them in a datastore, but now you must query this on every round trip. Most ticket(cookie)/token authentication systems use public key verification, which verifies the validity of the ticket/token without a database roundtrip.
If you store them in a datastore, now you must track expiration in the datastore as well. Tickets/tokens can have an expiration built into them. The nice thing about tickets/tokens is the client holds them. You can expire a session more quickly than the authentication. I.e. often you get a ticket that may allow you to be logged in for 2 hours, but the web server can expire your session in 10 minutes to reduce memory usage. When you access the web server in 15 minutes, it will see your ticket/token and see that it is still valid, and create a new session. This means at any point in time the server is tracking far fewer idle users.
JWT issuers are great for distributed systems, where authentication is shared. Rather than reimplement the authentication in every system, exposing multiple systems to the private key, as well as potential bugs in the authentication, we centralize it to one system. We can also leverage third party integrators that generate JWTs. All we need to do is get their public key for verifying the JWTs.
If someone breaks into your system and it is still secure, then you
made a secure system; nothing to worry about.
I have your list of nonces you were saving in your database now, and can login as anyone. I also likely have your connection strings, even if you're encrypting your application config, if I have root access then I can access the same key store that's used by the application to decrypt them. Now I get your username/passwords from your database and can login as anyone, regardless of what authentication scheme you use.
You'll be hard pressed to find a system that can still be secure after someone's gained root or physical access to the machine.
There's a small handful of systems that have purpose built hardware for storing keys and handle requests for encryption operations through an interface, thus ensuring the keys are protected at a hardware level and never accessed directly from software:
https://en.wikipedia.org/wiki/Hardware_security_module

Why is public key cryptography used in sites like Google, Facebook (what is the need to encode data in these sites)?

The RSA algorithm is used for encryption (plain text to cipher text) and decryption (cipher text to plain text) of data. What is the need for using public keys in these sites; why is data encrypted as everything is viewed by everyone?
Why do we need to use public key cryptography in Google; how does it provide security?
What is the need for using public keys in these sites?
It is required to set up a shared secret (a big random number) that is used for further symmetric crypto. Public-private key crypto allows one to share a secret message (symmetric key material) even when each and every message is monitored and eavesdropped. See Hot does SSL works? for more info.
The problem with public-private key crypto is that it is dead slow, whereas symmetric crypto is dead fast. The benefit is that public-private key crypto uses two keys for encryption and decryption and this is what allows to securely share a secret through the insecure channel, whereas symmetric crypto uses a shared key for both operations and you need both parties to have the same shared key.
Why is data is encrypted as everything is viewed by everyone?
When data is encrypted all that an observer can see is pure random noise. An observer cannot understand anything from the encrypted communication. Unless storing encrypted communication, like NSA does, and later asking Google and other companies for their private key. In this way they can decrypt old communication.
Why do we need to use public key cryptography in Google; how does it provide security?
Many agencies would like to know what people search for: "how to make a bomb", political disputes, etc. Advertisers would like to know what people interested in so that they can bring relevant ads. If something is provided to you for free, you are the product. You sell your information (your interests) and when this is done on a global scale suddenly huge money become involved.
Public-private key crypto in this sense provides privacy. Only you and the server can understand the traffic, but no one else: no intermediate hubs, your ISP or government body.
Before Facebook switched to SSL-by-default, all traffic was indeed plain text. This made it possible to build a graph of connections on a truly global scale. The rational I guess was to possibly aid anti-terrorist forces to catch the bad guys. From the other side all population's activities were tracked. See PRISM for more info.

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.

Would there be any problems using private/public key encryption for saving a password?

Using hashing algorithms like md5 we suffer from a limited entropy which means that very long passwords might result in hashes that can be regenerated by a shorter password.
I was thus wondering if it would be a good idea to store a password encrypted with the public key of public/private key encryption on the server. As decrypting is not needed, one could just throw away the secret key to avoid losing passwords when the server is compromised.
However, this method does not seem to be used widely. So are there drawbacks? If yes, then which?
There are several drawbacks. Among them:
You now have a token which must be protected. If someone gets your secret key, they have every password that was encrypted with that key. Asymmetric encryption is less of an issue if you "lose" the private key, but you better pray all copies of it are gone. Hashes can't be decrypted, period.
An encrypted password can be pretty much any length, and thus would require a pretty large field in the database (or length limits for the plaintext) in order to be stored. Hashes have a known length.
If you can decrypt the password, you know it. If ever there was a problem with someone using that password to break into something else, everyone who knew that password belonged to that user is a suspect. That now means you. Even if you use one-way encryption as a hash, you'd better be able to prove you can't decrypt it -- and then, if you don't want to decrypt it, why encrypt?
Generally, you'd only choose encryption over hashing when you have to know the password for something else -- like, say, when you're using it to log in to another system on behalf of the user. And ideally, you'd exhaust all other possibilities first.
Well there is always the drawback that computing a cryptographic hash is much less costly than encrypting a tiny password with a public-key encryption algorithm.
Secondly, you still suffer from limited entropy with public-key encryption, your bit string will still be limited. If you need more bits, use a hash with a bigger internal state (SHA-512, Whirlpool, etc...)
Third, you would need to store the public key along with the password, which results in a pretty hefty storage cost (considering how big public keys are), and if you're thinking of using the same public key for all passwords, don't - if that key is compromised it's over.
Also another consideration: without a password size limit there's a chance even padded block encryption will result in different storage sizes for different passwords, which can make database indexing a hell of a lot more difficult (probably not a huge concern but to keep in mind).
And finally, the biggie - hashes are meant to unequivocally destroy all structure in the input data, which is exactly what you want when storing passwords for verification. Encryption algorithms don't do that - they transform the data to make it unintelligible without the proper key, which sort of goes against what you're trying to use it for.
So, no, this method should not be used because it is self-defeating. Use a hash with a bigger internal state.