Examples (iOS)
Examples (Android)

 

Since 2.10

» Protocol Cryptography

Starting from version 2.10 SmartFoxServer 2X supports connection cryptography which allows to protect all communications with standard TLS protocol.

In this article we're going to discuss the basics of how encrypted traffic works in SmartFoxServer, how to setup an X.509 certificate on your server, how to test your connection and some platform specific notes.

NOTE: SSL for websocket clients is already supported since version 2.9.x, in this article we are discussing only SSL TCP sockets only. For websockets please refer to this article instead.

» How it works, in a nutshell

Adding full blown encryption to the client's session only requires one call after the connection event. The diagram below exemplifies the process:

crypto-flow

First, a persistent connection is established with the server. Then the new InitCrypto() method is called to perform the cryptography handshake. If the the request is successful the client and server have correctly agreed on a private key that will be used to encrypt the messages.

From this point all communications are protected by 128 bit symmetric encryption.

» Under the hood

The SmartFox.InitCrypto() call works in conjunction with the embedded Jetty web-server to exchange a unique and secure token over HTTPS. By using an already secure channel for the exchange we can make sure the server is running on a domain with valid SSL certificate, to avoid man-in-the-middle attacks.

The SFSEvent.CRYPTO_INIT is used to signal the response from the server with a boolean value representing the success of the operation.

Once the private key is acquired the rest of the communication will be transparently encrypted by the API, using AES 128 bit cryptography.

» Server setup

1) Enable HTTPS

To activate cryptography in SmartFoxServer 2.10 and higher the first step is activating HTTPS under the ServerSettings > Web server of the AdminTool.

https

The default HTTPS port is 8443. Whether you keep this value or you customize it, always make sure that you don't have a firewall blocking the communication.

Additionally, if it's a production server, you will need a valid SSL certificate installed in SmartFoxServer.

2) Configure your Zone's encryption settings

Under the AdminTool > ZoneConfigurator choose your working Zone. Under the first tab you will find this:

crypto-zone

Turn on the Use Encryption flag and restart the server to activate the changes.

» SSL Certificates

SmartFoxServer 2X is installed by default with a self-signed certificate that can be used to test your games locally. This, however, won't work for a production server. For a live server a signed security certificate is necessary.

» Local testing

The simplest way for testing without incurring in security woes is to disable encryption in the dev environment and just test the encryption on the production server, where it is really required. A simple way to do this is by organizing your connection code as in this example:

public class BasicClientExample implements IEventListener
{
	// Use this to turn Cryptography ON and OFF
	private boolean useCrypto = false;
	
	private SmartFox sfs;
	
	
	public BasicClientExample()
	{
		sfs = new SmartFox();
		
		sfs.addEventListener(SFSEvent.CONNECTION, evtListener);
		sfs.addEventListener(SFSEvent.CRYPTO_INIT, evtListener);
		sfs.addEventListener(SFSEvent.LOGIN, evtListener);
		
		ConfigData cfg = new ConfigData();
		cfg.setHost("localhost");
		cfg.setZone("BasicExamples");
		cfg.setDebug(false);

		sfs.connect(cfg);
	}
	
	private void sendLogin()
	{
		sfs.send(new LoginRequest("", "", sfs.getCurrentZone()));
	}
	
	
	@Override
	public void dispatch(BaseEvent event)
	{
		if (event.getType().equals(SFSEvent.CONNECTION))
	    {
	    	boolean success = (Boolean) event.getArguments().get("success");
	    	
	    	if (success)
	    	{
	    		if (useCrypto)
		    		sfs.initCrypto();
		    	else
		    		sendLogin();
	    	}	
	    }
	    
	    else if (event.getType().equals(SFSEvent.CRYPTO_INIT))
	    {
	    	boolean success = (Boolean) event.getArguments().get("success");
	    	
	    	if (success)
	    		sendLogin();
	    	else
	    		System.err.println(">>> CRYPTO INIT FAIL: " + event.getArguments().get("errorMsg"));
	    }
	    
	    else if (event.getType().equals(SFSEvent.LOGIN))
	    {
	    	System.out.println("Logged In: " + sfs.getMySelf().getName());
	    }
	}
}

With the use of a private boolean flag (useCrypto), we can make it very simple to switch the cryptography on and off for the local environment vs production.

» Local testing with a self-signed certificate

In general we don't recommend to test locally with the default self-signed certificate. Since it isn't signed by an authority every runtime (browser, OS, device, etc) will complain in one way or another, and stop your application. There may or may not be ways to force the system to use a non signed certificate but it can be a tricky process.

We highly recommend instead of testing locally without encryption, and testing online with a regular, signed certificate.

If you still want to run local tests with cryptography, we recommend it only if you really understand how the security of your runtime works.

For browser-plugin environments, this is the equivalent of connecting to an HTTPS website with an invalid certificate. The browser will stop the navigation and show a prominent warning. The user is then able to leave or override the warning and continue, ignoring the security risk.

alert

This however will not show up, because the connection is done inside the plugin, so the error may go undetected.

Here are a few tips that will help local testing:

» Online testing with authentic SSL certificate

For production servers a valid SSL certificate is mandatory. You can acquire one from many different providers or use an existing one and import it into SmartFoxServer.

Certificates comes in several different file formats. Typically you will get 2 or 3 files:

Via an online tool such as this we can create a .pfx (or p12) file which can then be imported into a keystore via the JDK's keytool utility.

keytool -importkeystore -srckeystore cert.pfx -srcstoretype pkcs12 -destkeystore 
key-store-name.jks -deststoretype JKS

where:

The keystore file is the one we're going to deploy in SmartFoxServer 2X, with these steps:

This is an example of the ssl.ini

#
# Initialize module ssl
#
--module=ssl
## SSL Keystore Configuration
# define the port to use for secure redirection
jetty.secure.port=8443

# Setup a demonstration keystore and truststore
jetty.keystore=etc/myCertificate.jks
jetty.truststore=etc/myCertificate.jks

# Set the demonstration passwords.
# Note that OBF passwords are not secure, just protected from casual observation
# See http://www.eclipse.org/jetty/documentation/current/configuring-security-secure-passwords.html
jetty.keystore.password=myPassword
jetty.keymanager.password=myPassword
jetty.truststore.password=myPassword

Since this file contains a password that is critical for the security of the system we recommend to make sure it is protected by adequate file permissions. The link in the comments provide additional information on how to obscure the password, if required.

Finally, to verify that the SSL certificate is working correctly, you can point your browser to https//:<your-host>:<ssl-port> and verify that your browser reports a successful connection (e.g. the green lock below).

cert-ok

» Platform specific notes

» Adobe Flash

The Flash IDE will always fail connecting with encryption to a local SmartFoxServer with a self-signed certificate. Similarly does the standalone Flash Player. The only way to test in such setup is to use the browser by pre-authorizing the domain, as explained previously in the article.

» Unity

In Unity the SmartFox.InitCrypto method must be executed as a coroutine, hence using MonoBehaviour.StartCoroutine method. As this is not supported in Windows Store (SDK 8.1, Phone 8.1, Universal 8.1) applications, when building for this platform a conditional statement is required as in the following example:

// Initialize encrypted connection
#if UNITY_WINRT && !UNITY_EDITOR
sfs.InitCrypto();
#else
StartCoroutine(sfs.InitCrypto());
#endif

For Windows Store IL2CPP builds, change the conditional compilation above as described in this post.

» Unity WebPlayer

Do not use Socket.PrefetchPolicy in your code.
It forces to use an IP address instead of a domain name, which is needed if you want to use SSL, since the certificate is (typically) bound to the domain name.

Instead you can let the WebPlayer auto-fetch the cross-domain policy from the default TCP port 843. In order to do this you will need to add a listener for such port in the SFS2X AdminTool > Server Configurator.

For Linux / Mac OS X users, this requires running the server as root, since port 843 is within the 0-1024 range.
This method is not available when building for WebGL: use WSS connection instead.

» Unity WebGL

The SmartFox.InitCrypto method is not available when building for WebGL: use WSS connection instead (see SmartFox(UseWebSocket useWebSocket) constructor API documentation).