[solved] [Kryonet] Register and login with username/password

I’m working on a small multiplayer game with Kryonet that would require a login with a username and password. I’m wondering what a safe way to handle this would be.

Obviously I won’t be storing plain text passwords on the server database, most likely they will be encrypted with a salt (this article seems useful). If I let the server do the encryption it means I’m sending plain text passwords over the network. Would letting the client encrypt passwords be better? Are they any issues with this method?

You could use public key (assymetric) encryption to send the critical data.
Or use public key encryption to send a key for symmetric encryption so that you don’t have to as much computation on your server, public key encryption is damn slow.

You cannot use symmetric encryption right away, because you need to have a shared key between server and client, if this key is stored in your code than it’s not safe at all.

Shameless plug: http://www.java-gaming.org/topics/thread-safe-rsa-de-encryption-utility-for-byte-arrays/37770/view.html
This is proven to work with Kryonet easily.

However you do it, you should definitely encrypt your user data traffic.

Thanks! Just so I understand this, will the server generate the public/private keypair, send the public key to clients, clients use the public key to encrypt the data and send it to the server, the server then decrypts the data?

Exactly :wink: this can be done for both server->client and client->server.
But it’s best to just transmit a shared-key for symmetric encryption via this method if you want to transmit more than just login data.

Thanks for your help! I think I’ve figured a system out.

When a player connects, the server generates a public private key for that user. When the player enters a password it is encrypted with the public key and sent to the server. The server then decrypts the password and hashes it with a salt, then stores the hashed password + salt in the database.

When a player wants to login, the server hashes the password sent from the login request with the users salt and compares it to the original hashed password.

Hopefully this is decent enough.

That certainly works, though you might want the client to hash his password himself for login/register, not on the server, or else a fake server can easily grab a users plain-text password. This is bad because many just reuse passwords, you don’t want to leak that.

Sounds good to me otherwise.

Ah so you’d recommend hashing on the client. I’m guessing the hashing of the password + salt would happen before then encryption?

Would it be wise to send the client their salt? The salt is generated by the client the first time they register, when the player wants to login again they will need the same salt to hash their password. Would I need to send the player the salt, to hash the login password, to send to the server, to compare to the stored hashed password?

Yes, the salt doesn’t need to be secret in your case, you can safely send it to the user on request, just like you described.

I’m suggesting this clumsy mess because you’re likely not using SSL, so your client never knows if it’s really the server, it’s better to just lose your hash+salt to a faked server than to lose the password, which can be reused to attack other accounts the user has elsewhere.

Okay, that seems to work fine! Yeah it’s not SSL, I’m not sure how to implement SSL with kryonet, and the testing server I bought can’t do Https as it’s an IP I connect to, not a domain name.

Thanks for your help!

Just fyi: There is a fantastic class in Java, the SSLEngine, which allows you to integrate SSL into any underlying transport mechanism. It provide a very thorough documentation and acts as a “black box” which you pump sent packets into and pop received packets out of. You just need to provide it certificates in order to verify at least the server (in order to avoid man-in-the-middle attacks). You don’t need to have a server URL or anything. The private and public certificate keys only must match and be trusted (the trust store can be configured on the SSLContext of the SSLEngine).
See this example: https://docs.oracle.com/javase/7/docs/technotes/guides/security/jsse/samples/sslengine/SSLEngineSimpleDemo.java

I’ve integrated this in a project in the past implementing secure RTSP and RTP over a reliable UDP protocol using Netty to provide the transport mechanism and integrating the SSLEngine into Netty’s pipeline/upstream/downstream architecture, making it completely transparent to any upper OSI application layer.

ISAAC Cipher is what RuneScape uses