INITIAL NOTE: This is just for a personal tinkering project; I'm not writing enterprise security here, and if I were, I'd know better than to try to write my own scheme. :-D
EDIT: To stress the above point, I tried to tag this under "iKnowThisWouldBeABadIdeaInRealLife", but SO wouldn't accept it because it was >25 chars. Just be aware that I KNOW it's not commercial grade!
I need a way to authenticate a user over HTTP (can't use HTTPS in this case). I need to know that the person on the other end really is who they say they are (to some reasonably high degree of confidence). Once I'm sure the user is legit, I do not care if the content between the client and the server are sent as plaintext.
Here's the scheme I'm thinking about:
(suppose A and A' represent the private and public keys, respectively; also, enc(text, key) and dec(cyphertext, key) represent the encryption/decryption functions)
| SERVER | CLIENT |
(1) | t = randomToken() | |
(2) | enc(t, A) --------> c |
(3) | | A' = getKeyFromUser() |
(4) | p <-------- p=dec(c, A') |
(5) | if (t==p) | |
| allowAccess() | |
| else | |
| denyAccess() | |
One weakness I see in this is that the BAD GUY who was listening to the exchange, while he doesn't have A, now has a known ciphertext/plaintext combo, which I remember from crypto class is a BAD IDEA. I figure some salting could alleviate this somehow?
So here are my [two] questions:
EDIT: Thanks for all the discussion! Just to clarify:
Here was my thought-process for the scheme: (I know I'm not quite using public vs. private keys properly, but bear with me for a sec)
Bob walks up to Alice and says, "Hey, I'm Bob."
Alice says, "Okay. I know Bob's 'private key'. If you're really Bob, take this secret message I just encrypted (with Bob's private key), and decrypt it for me."
Bob replies with the correct message, and Alice is happy.
You basically want to implement SSL on HTTP; which is somewhat feasible, but will never be as good as the real thing.
Being able to send encrypted data back and forth is only half the problem. Another part of the problem is ensuring you are actually talking to the server (think of man in the middle attacks).
I am not really sure how the SSL works, but that is the way to go. You should read up on that. From the looks of your scheme, it seems totally pointless however. Why are you sending plaintext back to the server? That defeats the purpose of having this set up.
Here's how I would do this:
enc(comb(username, password, token), pubKey)back to the server, where
comb()is some function that combines the username, password and the random token.
decomb()is the inverse of
If the generated tokens are never repeated, an attacker can't just re-send the same encrypted message, nor can they decrypt the message to find out what everything was.
You could use HTTP Digest Authentication. That's already supported by most browsers, servers and various libraries.
If you really want to use some public key cryptography without SSL/TLS, you could have a look at HTTPsec
If you really want to invent your own authentication scheme, you should note that you got the encryption/decryption wrong with your labels (not sure if it's a typo, or maybe I'm not reading the diagram properly, it looks like you're doing enc(t,A) on the server side):
In your scheme, you'd need the server to publish its public key and have the client encrypt its answer using that, to send it to the server, which would then be able to decrypt it with its private key. The difficulty then is to make sure that the public key is indeed that of the legitimate server and that it hasn't been intercepted and replaced by an attacker in the middle: that's where PKIs and certificates come into action with TLS (and HTTPS).
If you use RSA with a proper padding mechanism, like OAEP, it's not vulnerable to known-plaintext attacks. So there's no need to get around that.
A stranger walks up and claims to be Bob. To prove it, they prove that they know a secret only the real Bob knows. In public key cryptography, the secret is the private key.
In your proposal, you first have to get Bob's public key, and make sure it's really Bob's, so that later you can use it to encrypt challenges. How do you bootstrap this process?
Now "Bob" responds to your challenge correctly, and tacks some instructions to his request. How do you know that the woman-in-the-middle, Eve, didn't chop off Bob's real instructions and substitute her own?
This is a bad scheme, and doesn't come close to providing security.
If you are going to pursue this at all, you should be looking at ways to digitally sign an request. For example, POST a digitally signed chunk of data. All of the HTTP-level information is discarded as untrustworthy, and only the content of the digitally-signed message is acted on.
Assuming that your client and server exchange a public key before this exchange begins, you could do something like:
The URL is included to prevent replay attacks against a different resource. More security against replays can be obtained by including a timestamp in the encrypted data.
If you use a quality encryption scheme, known plaintext attacks are not a large concern.
EDIT: removed mention of AES128.
Like Bruno said what you describe is along the lines of HTTP digest, which is pretty secure. But if you read up on it there are loop holes. Not big. Someone would really have to be listening to wait to pick up the keys in the handshake to be able to break in. If security is an issue you have to use https and make way for it. That is why its there. https has certificates to make the handshake resistant to eavesdroppers in the start.
First of all HTTPS does more than just encryption. It also prevents active MTIM attacksand protects your session id. The password is meaningless if you just spill the session id. This is part of OWASP A9.