Solution 1:

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.

Solution 2:

Secret key cryptography relies on using the same key to encode and then later decode a message. Thus, only those who know the "secret" can read the message.

RSA security is based on 2 matching keys. There is a public key for each user, and everybody can (should) know it. There is also a private key that only the user should know. A message encrypted by the public key can only be decrypted by the private key, and visa versa.

Thus, if I want to send you a message that only you can read, I get (from the network) your public key, encrypt the message with that key and you are the only person who can decrypt it.

Or, if I want to prove to you that I sent a message, I can encrypt the message with my private key, tell you (in open text or in another message) how it was encrypted. Then you could decrypt the message with my public key, and if it becomes readable, you know it came from me.

This form of encryption is fairly computer intensive, so what sometimes done is, to encrypt a one-time "secret key" with RSA technology is used, then encrypt the rest of the message with the secret key, then encrypt my signature in the second fashion. You then reverse this process, so if the message and the signature are readable, you and only you can read it and you are ensured that I sent the message.

OR

you can visit this link for more detailed explanation.

How do API Keys and Secret Keys work?

Solution 3:

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.

Solution 4:

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:

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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.