Skip to main content
gamedev.net
🔒 Locked

Authentication Algorithm

Started by WebsiteWill 19 replies 4k views
Original Post
WebsiteWill
WebsiteWill
Hello all: I've read the Authentication doc and many forums/websites regarding authentication and now I have a few questions. I'm working on a chat client/server system and have a few questions. Should I really be concerned with man-in-the-middle attacks? The server is designed from a client request (not demand) point of view, all client input is validated and the server determines what is legal and what isn't. Given the relative difficulty of MITM, should I even worry about it? My main concern would be client login and account creation. My algorithm would be something like this. Server listens on UDP port for incoming messages. Client starts which sends a AUTH_INITIALIZE packet to the server (basically an empty packet as I think all I need at this point is client IP and Port). Server calculates a random Diffie-Hellman key pair and sends P,G to the client and calculates it's public/private key pair. Client uses P,G to generate it's public/private key pair. Maybe do something here to validate that client and server agree on keys. Now client and server know about each other and agree on keys. Client would either LOGIN or CREATE_ACCOUNT. Either way I send a message to server with USERNAME and PASSWORD encrypted with public key. Server decrypts and validates. If USERNAME/PASSWORD are valid and accepted the server then creates another Diffie-Hellman that takes the password and username into account. Encrypts this new DH pair with the original DH key and sends it to the client. From then on the server expects all communication from that client to use the newly generated DH key. Client likewise decrypts and computes new keys to communicate with. I think I'll also implement a sliding validation time so that keys expire every so often (maybe on a randomly chosen interval) just to help prevent decryption attempts. Also, something I've considered would be to simply include a public key to the client that everyone knows about and have the server keep a strong private key. All clients would encrypt all initial (pre Diffie-Hellman trafic) with this public key just to stop those initial packets from getting read. I might be going overboard with this. Please give me your thoughts. Thanks, Webby
hplus0603
hplus0603
If you're concerned about security, then using HTTPS or lower-level SSL for your transport is the easiest choice. It already provides working security, designed and implemented by some of the best. (Try the OpenSSL library, under the BSD license, for example)

Note that security and authentication are separate concepts. If what you really want is an authentication/ID solution, X.509 might be what you're looking for.

And if you're doing this just for fun, not to put real money and real data into, then you should only worry about it as much as you feel like :-)
enum Bool { True, False, FileNotFound };
WebsiteWill
WebsiteWill
I guess I left out a bit of critical information.
This is going to work over UDP and not TCP so if my understanding holds true I can't use HTTPS or SSL.

I'm basically following your (hplus) article on Authentication for Games. Right now this is just being used for the chat server aspect but the same thing will occur in the context of other server types.

In fact I'm designing it so that clients go through an Auth server which will then hand them off to the chat server and eventually other types of servers.

Thanks,
Webby
Prefect
Prefect
You might want to do everything related to account management and whatnot over SSL, and if some part of your game seriously needs UDP (to reduce latency in the face of occasional packet drops), the first question you need to ask yourself is: Is protection against MitM that important for that low-latency stuff?

So what if an eavesdropper can sniff which direction the player is walking in.
So what even if somebody can mess with the players' input - in practice it won't happen, and if it does, the player can complain to their ISP.

On the other hand, if you really do want to secure this as well, you should look into MACs (message authentication codes) and symmetric encryption for the packets. In fact, I thought openssl provides such functionality as well. You can use the SSL session to establish keys for MAC and symmetric ciphers for the UDP "session".
Widelands - laid back, free software strategy
hplus0603
hplus0603
If you have a trusted channel for authentication, then all you have to do is issue a random session key for use in the UDP packets, and there is no MitM attack possible. You can still have a compromised client, of course. Also, you have to make sure the channel is actually trusted; typically using a PKI of some sort.
enum Bool { True, False, FileNotFound };
WebsiteWill
WebsiteWill
Thanks guys. I've actually stumbled upon a new issue here.

I've got all of my Diffie-Hellman exchange working between the client and server. My intention was to use those keys with something like RSA to actually encrypt and transmit a symmetric key generated by the server.

However, as you all might know, the .NET implementation of RSA doesn't let you initialize with your own keys. I also don't like the way it uses files to do it's work, it just all seems silly.

So, what would you guys recommend for Asymmetric encryption using public/private keys generated with Diffie-Hellman?

Thanks,
Will

P.S. Should I open this as a new topic?
btower
btower
Quote:
Original post by WebsiteWill
However, as you all might know, the .NET implementation of RSA doesn't let you initialize with your own keys.


Sure it does!

Dim crypter As New RSACryptoServiceProvidercrypter.FromXmlString(publicKeyString)


This is from XML format. There are also ways to do this based on other formats (X509 is supported for example).

If you can tell us which format of key you use, would be useful.
WebsiteWill
WebsiteWill
Well, I've got an implementation of the Diffie-Hellman algorithm up and running between the client and server. To be honest, I'm not sure what format that would be in other than two agreed upon numbers that are mathmatically related in some very obsure and hard to decipher format.

I had thought about trying to write my keys to an in-memory xml and feed that into the RSA object but I wasn't sure it would work. I've got a public and private key (also have P and G from Diffie-Hellman exchange). The RSA object seems to want an xml file with a lot more data than I have on hand.

If it's that simple I can give it a shot, I just had my doubts that it would even work.

Webby
WebsiteWill
WebsiteWill
Here is more information.
For generating the Diffie-Hellman the code I use generates
1 byte for G (8 bit)
128 bytes for P (1024 bit)
128 bytes public key (1024 bit)
128 bytes private key (1024 bit)

Are these values something I can then provide to the .NET RSA provider?

Thanks,
Webby
WebsiteWill
WebsiteWill
Ok, so maybe I was going about this all wrong.
Turns out, it seems that the way to do this would be to have the client create it's public and private key using the RSACryptoServiceProvider and send the public key to the server.

The server sees this message and generates it's own public and private key with RSACryptoServiceProvider and sends public key to client.

At this point the server can generate a symmetric key to use for encryption, encrypt it with RSA and send it to the client.

From that point on the client and server communicate and encrypt/decrypt with the shared symmetric key.

For added security, I can periodically generate a new symmetric key and send it to the client with RSA. I can even renew the RSA keys between client and server periodically if necessary.

So, now I'm wondering how I got down the track of Diffie-Hellman in the first place. Generating the shared keys was a piece of cake but figuring out how to effectively use them after was a pain in the rear.

This seems to work now. Thoughts?

Thanks,
Webby
hplus0603
hplus0603
How do you know it's the server, and not a man-in-the-middle, that you are sending your public key to? A MitM could easily snarf your key, and send another key that it generates on to the server. Similarly, it could intercept and translate the server response, and provide a decrypted point in the middle of two streams.

Or, stated a different way: What specific attack vectors are you trying to eliminate?
enum Bool { True, False, FileNotFound };
WebsiteWill
WebsiteWill
Trying to eliminate man in the middle.
Aside from that, symmetric encryption will be fine for everything else I do. In fact, most things won't even be encrypted. At the time of authentication or account maintenance I will do encryption but for general messages I won't be.

MITM is only a real threat initially, like when a user is first creating an account (since there is currently no shared key). At that time the server knows nothing about the user so potentially a MITM could intercept the message and cause harm. The key place for harm would be the message when the user sends their username and password to the server the first time.

Once that information is securely on the server I think I'm reasonably safe from MITM as there is now a key known to both the server and the client which can be used with an HMAC to verify messages.

I'm not even that sure I need to worry about MITM as, how common/feasible is it really, and to what extent would someone bother in a chat or game application? Though I do want to take as many precautions as possible.

Do you have a workable solution? I've read your document quite a few times and it covers well how to authenticate client/server but it assumes there is already a shared key between the two. How to you secure a shared key?

Webby
WebsiteWill
WebsiteWill
And now I'm off on another tangent.

I cam across another topic that you (hplus) took part in and highly defended SSL. The reason I was trying to stay away from SSL was due to it's connected nature. But on thinking and reading how about something like this.

Auth Server is running and waiting asynchronously for SSL connections
Client sends a generic message to the server requesting a connection.
Server responds with an available port (since it's connected we're limited).
Client connect SSL to the given port.
Server certifies itself with the client.
Do I need to have client certify itself with the server? Seems unnecessary.
Client "authenticates" by providing username and password.
If success, server generates shared symmetric key and sends it to the client.
Server disconnects.
Client can then freely communicate with server as necessary (encrypting when necessary using the shared key).
Server can periodicaly update shared key by sending it encrypted to the client when necessary (just as added protection).

Things like account creation (or anything involving credit cards, etc could be done over SSL OR using the shared key generated during the SSL connection.
Do you think it necessary to use SSL for that once we have a safe shared key just to be safe?

I'd like to do as much over UDP as possibly for its scalability.

Thanks for keeping up with this post,
Webby
Drew_Benton
Drew_Benton
Quote:
I'm working on a chat client/server system and have a few questions


What existing program best models what you are trying to create? Aim, Msn, some e-commerce chat, IRC, etc...

Quote:
My main concern would be client login and account creation.
...
MITM is only a real threat initially, like when a user is first creating an account (since there is currently no shared key).


If you think MITM is the real threat here, then account creation should be handled through a secured website, not the client. Problem solved [smile] In my opinion, clients should never have such capabilities of being able to directly create accounts or modify account data; only authenticate to use a service. Your authentication protocol will be reversed and hacked to bits. As soon as that happens, there won't be anything that will stop people form being able to launch hacking attacks to your service from your own client.

As for the login process, which this will help protect against your MITM attack fears, you never, ever send the password. Ever! Not in plain text nor in an encrypted format. The server knows the user password, the person using the client should know the correct password. Because of that, you can use a modified login progress than you described to solve the problem. This method can be done over UDP or TCP and does not require SSL. It's a method I've seen used in numerous games.

1. Client connects to server and waits for a reply (TCP) or Client starts which sends a AUTH_INITIALIZE packet to the server (UDP)

2. Server calculates a random Diffie-Hellman key pair and sends P,G to the client and calculates it's public/private key pair.

3. Client uses P,G to generate it's public/private key pair.

4. [Maybe do something here to validate that client and server agree on keys.] Server sends client a unique session ID hash to use for login.

5. Client decrypts session ID hash and stores it for use in login. If anything goes wrong here, client will simply fail to authenticate, perfect!

6. Client sends LOGIN packet. To compose the login packet you will (well, this is an example as if you actually used this everyone reading this would know how it'd work [wink]):

[edit]Just realize, you shouldn't actually hash the username as the server won't know who's connecting. I've got too much written to reedit it all, so keep that in mind [lol][/edit]

Quote:

0. Start with a big packet buffer
1. Append username
2. Append session ID hash
3. Take some private hash of the result and store in Var[1]
4. Clear out packet buffer
5. Append password
6. Append session ID hash
7. Take some private hash of the result and store in Var[2]
8. Clear out packet buffer
9. Append Packet header, Var[1], Var[2], and then any additional information needed in the login packet.
10. Send the final packet encrypted using public pair


7. Server decrypts and validates by performing the same process. No username or password is actually sent! Only hashes so anyone that does MITM has nothing as the unique session ID changes each login. No more worries about MITM now, yay!

8. If success, then you can continue to do whatever you want, generate a new DH key pair and send that to the client to use, I won't go on from here as what you are having trouble with was step 6 and 7.


That's how you do it. No account name or account password is ever sent in a format that could ever be decrypted by modern day technology. You will want to use a strong hash function though as users will be able to reverse engineer your client and get that hash function. If it's a good hash function though, then that won't matter as they can't decrypt a hash anyways.

The real problem you have to worry about though is client impersonations through hacked clients or local MITM attacks in which users MITM their own connections to sniff, modify, drop/add packets in their own packet streams (very fun to do I might add). Because of this, you cannot trust anything the client sends you, which I think you have covers since you mentioned the server will validate everything. It's important to operate under the assumption the client is compromised at all times!

As long as you take those steps above, or some process of where you never send the real account id and account password, and rather a useless unique hash, then you have nothing to worry about data wise from a MITM attack. Packet replying is not possible as the session id hash always changes and is not "predicable" from a hackers point of view since it's done on the server (very important not to have something that is predicable) Once the client is connected and happily sending data to and fro, you just need to validate the commands send as well as performing server side logic to control spam or any bypassed client restrictions.

Hope that helps!
hplus0603
hplus0603
If you cannot secure the infrastructure, you fundamentally cannot protect against the man in the middle. You need a public key infrastructure to do that.

Luckily, HTTPS has already solved that, by shipping root certificates from Verisign et al, and establishing a chain of trust. You can also solve it for a specific application by providing your own certificates, and locally trust your own certificate -- the client would have to be compromised and the certificate swapped out for an attack to work out in that case.

Of course, certain signature companies will sell a certificate to anyone willing to pony up $395 and answer a phone call. In fact, several years ago, someone managed to convince Verisign that he represented Microsoft, and got a few ceritifactes issued to himself signed "Microsoft Corporation."

Web security: Yee-haw!
enum Bool { True, False, FileNotFound };
WebsiteWill
WebsiteWill
Thanks guys.
Drew: Yes, the sending password stuff as a hash (of hashes or other garbled method) was definitely my intention there. Any (sensitive information) will be handled that way.
You are back to Diffie-Hellman which I've got implemented and working but honestly couldn't figure out a good way to use them.
I was trying to use them as the actual public\private keys in RSA (or other asymmetric algorithm) to encrypt the data, which isn't possible -- with .NETs RSA implementation at least.
However, using those agreed upon numbers as part of an HMAC calculation would work pretty well wouldn't? Since they're values only the client and the server know about?

Now, if I perform all of that over SSL then it seems like it should be pretty tightly wrapped up. It's a good bit of overhead but definitely worth it and it's something each client will only do once per session.

I'm not opposed to getting a certificate from a CA but for now I don't want to put out the cash. It seems like creating my own certificates is possible as hplus alludes to.

I'm also not opposed to handling account creation over a secured website, that might actually be the best option. Since once that's done I can guarantee that the client and server have some secured information they both agree on and the rest of the process becomes a whole lot easier, not to mention takes a lot of burden away from the authentication server.

Thanks guys,
Webby
hplus0603
hplus0603
Quote:
Since they're values only the client and the server know about?


Again, a MitM that can insert itself into infrastructure (say, on a router), can accept a connection on behalf of the server, and then create a second connection from himself to the real server, and run the protocol both ways. That way, the Diffie-Hellman will protect the transmission between your client and the MitM, and (with a different key) between the MitM and the server, but the MitM still has access to your decrypted data.

This is a very important concept about advanced MitM attacks to grasp.
enum Bool { True, False, FileNotFound };
WebsiteWill
WebsiteWill
So, 24 hours, one fried HP, and one one new Gateway FX6800-01e later I can finally ask:

So, other than certificates there doesn't really seem to be any way to prevent MITM, right?

So I need to set up a certificate on my server that the client can validate with. From what I read it doesn't seem necessary for me to have a certificate on each client right? I mean, I don't even think I could being that just anyone will be able to install this.

And, now for a question I probably should have asked first. :)
Any good tutorials showing all the steps necessary to set up a Client/Server system stating some (or THE) best way to initialize a connection between a client and a server?

I definitely like the idea of using a secure website for account creation/maintenance, it just seems odd as I've never seen that approach used before in other games or systems.

Thanks for all the input,
Webby
Antheus
Antheus
Quote:
Original post by WebsiteWill
I definitely like the idea of using a secure website for account creation/maintenance, it just seems odd as I've never seen that approach used before in other games or systems.


For MitM one needs to attack the infrastructure with fairly sophisticated tools.

To steal someone's account data, one merely needs to post a page with "hacks" and "gold" in title that installs a cookie-cutter keylogger to user. There's other ways as well.

This is the biggest problem with security. It is always measured in relative terms, unlike algorithms, which can be designed to spec (will handle n items in m time).


But as far as practical approaches to security go, that RNG dongle ranks pretty high, since it's brings security close to one time pad, and also addresses problem of compromised client. Physical attacks aimed at stealing the dongle aren't really a vector in this case, not even when it comes to banking.

Depending on sensitivity, banks often provide other systems in combination with this, digital certificates + one time pad + card of sorts + one or more secrets + "turing test" a.k.a. captha.
hplus0603
hplus0603
Quote:
So I need to set up a certificate on my server that the client can validate with. From what I read it doesn't seem necessary for me to have a certificate on each client right? I mean, I don't even think I could being that just anyone will be able to install this.


You need a private key on the serer, and a public key on each of the clients. Baking the public key into each client means that someone would have to compromise the client to make it connect to some man in the middle, and at that point, it's out of your hands.

When it comes to keyloggers, I've always thought Maple Story is pretty smart. You have to enter a security PIN by clicking on a virtual keyboard. The trick is that the numbers scramble each time you enter them, so an attacker with a key- and mouse-logger won't get the pin. (A really sophisticated logger would take a screen shot at each click, but then the upload amount becomes prohibitive quickly, and the logger more likely to be found)

My online savings account also uses a mouse-clicked keyboard for a second password, but the keyboard is the same for every click, so a smart logger can still get it. Meanwhile, my old bank actually had a digital key (in 1993!) (like a credit card calculator) that could sign my log-in and transactions; that felt a lot more secure. My current bank wants me to *pay* for such a key. Shhyeeah, right...

The three factors: Something you know (password/pin), something you have (key/dongle), something you are (thumbprint/retinal scan. While you're supposed to do two-factor authentication by picking two of those three, most banks actually choose the cheap way: using something you know (password), and something you know (pin)...

End rant :-)
enum Bool { True, False, FileNotFound };

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.