• Examples (HTML5)
• Examples (iOS)
• Examples (Android)
• Examples (C++)
Server API Documentation

 

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.

The provided instructions may differ depending on the connection type. Specifically we will distinguish between regular TCP socket connections, used by most client technologies, and websocket connections (WS/WSS), used by Unity's WebGL builds and native JavaScript clients. More information can be found in the protocol overview document.

» Server setup

Configure SmartFoxServer following these steps. Additionally, if it's a production server, you will need a valid SSL certificate, as described in the next section.

1) Enable HTTPS

To activate the cryptography in SmartFoxServer, the first step is activating HTTPS/WSS under the Web server tab of the Administration Tool's Server Configurator module. If you are using a websocket client, of course the "Enable WS/WSS" check should already be on.

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.

2) Configure your Zone's encryption settings

Under the AdminTool's Zone Configurator module choose your working Zone. Under the General tab Turn on the Use encryption flag and restart the server to activate the changes.

crypto-zone

This setting is irrelevant if the Zone serves websocket clients only.

» 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 mandatory.

» Production environment

You can acquire a valid SSL certificate from many different Certificate Authorities (such as Symantec, Thawte, CACert, etc) or use an existing one and import it into SmartFoxServer.

Certificates comes in several different file formats. Typically you will get two or three files:

Via an online tool such as SSL Converter you can create a .pfx (or p12) file which can then be imported into a keystore using the JDK's keytool utility in a Terminal/Console window.

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

Where:

The keystore file is the one you are going to deploy in SmartFoxServer 2X, by following these steps:

This is an example of the ssl.ini file:

#
# 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 in the picture below).

cert-ok

» Development environment

The simplest way to test your game/application without incurring in security woes is to disable encryption and just test the encryption on the production server, where it is actually required. A simple way to do this is by organizing your connection code appropriately: with the use of a boolean flag (useEncryption for instance), you can make it very simple to switch the cryptography on and off for the development environment vs production.
An example of this approach is provided in the client code examples in the next section of this document.

» Local testing with the 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. The same happens with a Websocket Secure (WSS) connection: the browser will not show a friendly warning screen; instead it will just prevent the connection to happen.

Here are a few tips that will help testing your application locally.

» Client code

This section will show how to write your base connection code to enable the protocol encryption. The provided examples will use the default ports and also feature a useEncryption flag to easily enable/disable encryption as mentioned before.

» Non-websocket clients

All clients connected over regular TCP socket require a call to the SmartFox.InitCrypto() method after the connection event to add full blown encryption, like in the examples below. But before getting started...

How it works, in a nutshellcrypto-flow

First, a persistent connection is established with the server. Then the 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.

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 event 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.

In this Java example we initialize the protocol cryptography as soon as a successful connection is established.

public class ConnectionExample implements IEventListener
{
	private SmartFox sfs;
	
	// Use a flag to easily switch cryptography on and off
	private boolean useEncryption = false;
	
	public ConnectionExample()
	{
		// Create the SmartFox client instance
		sfs = new SmartFox();
		
		// Add event listeners
		sfs.addEventListener(SFSEvent.CONNECTION, this);
		sfs.addEventListener(SFSEvent.CRYPTO_INIT, this);
		sfs.addEventListener(SFSEvent.LOGIN, this);
		
		// Create configuration object
		ConfigData config = new ConfigData();
		config.setHost("mydomain.com");
		config.setPort(useEncryption ? 8443 : 8080);
		config.setZone("BasicExamples");
		
		// Connect to SmartFoxServer 2X
		sfs.connect(config);
	}
	
	// Send a login request
	private void doLogin()
	{
		sfs.send(new LoginRequest("Fozzie"));
	}
	
	@Override
	public void dispatch(BaseEvent event)
	{
		// Handle connection event
		if (event.getType().equals(SFSEvent.CONNECTION))
	    {
	    	boolean success = (Boolean) event.getArguments().get("success");
	    	
	    	if (success)
	    	{
		    	// Initialize protocol cryptography if needed, otherwise send a login request
	    		if (useEncryption)
		    		sfs.initCrypto();
		    	else
		    		doLogin();
	    	}	
	    }
	    
	    // Handle encryption initialization event
	    else if (event.getType().equals(SFSEvent.CRYPTO_INIT))
	    {
	    	boolean success = (Boolean) event.getArguments().get("success");
	    	
	    	if (success)
	    	{
		    	// Send a login request
	    		doLogin();
	    	}
	    }
	    
	    // Handle login event
	    else if (event.getType().equals(SFSEvent.LOGIN))
	    {
	    	System.out.println("Logged in");
	    }
	}
}

Also in this Unity standalone example we initialize the protocol cryptography as soon as a successful connection is established. This is the same for all Unity's target platforms (except WebGL — see next section), but some caveat may apply. See the Platform specific notes chapter below for more information.

public class ConnectionExample : MonoBehaviour
{
	private SmartFox sfs;
	
	// Use a flag to easily switch cryptography on and off
	private bool useEncryption = true;
	
	void Start()
	{
		// Create the SmartFox client instance
		sfs = new SmartFox();
		
		// Add event listeners
		sfs.AddEventListener(SFSEvent.CONNECTION, OnConnection);
		sfs.AddEventListener(SFSEvent.CRYPTO_INIT, OnCryptoInit);
		sfs.AddEventListener(SFSEvent.LOGIN, OnLogin);
		
		// Create configuration object
		ConfigData config = new ConfigData();
		config.host = "mydomain.com";
		config.port = useEncryption ? 8443 : 8080;
		config.zone = "BasicExamples";
		
		// Connect
		sfs.Connect(config);
	}
	
	// Send a login request
	private void DoLogin()
	{
		sfs.Send(new LoginRequest("Fozzie"));
	}
	
	// Handle connection event
	private void OnConnection(BaseEvent evt)
	{
		if ((bool)evt.Params["success"])
		{
			// Initialize protocol cryptography if needed, otherwise send a login request
    		if (useEncryption)
	    		StartCoroutine(sfs.InitCrypto());
	    	else
	    		DoLogin();
		}
	}
	
	// Handle encryption initialization event
	private void OnCryptoInit(BaseEvent evt)
	{
		if ((bool) evt.Params["success"])
		{
			// Send a login request
	    	DoLogin();
		}
	}
	
	// Handle login event
	private void OnLogin(BaseEvent evt)
	{
		Debug.Log("Logged in");
	}
}

For a full connection example in Unity, featuring conditional compilation for multiple platforms support, encryption activation and more, please check this tutorial.

» Websocket clients

All clients connected over websocket do not require a specific cryptography handshake. You just need to set the proper connection port and protocol (WS or WSS), like in the following examples.

Using the JavaScript native API, the choice between the encrypted (WS) and non-encrypted (WSS) connection is made in the configuration object passed to the SmartFox class constructor.

(function () {
	// Use a flag to easily switch cryptography on and off
	var useEncryption = true;
	
	// Create configuration object
	var config = {};
	config.host = "mydomain.com";
	config.port = useEncryption ? 8443 : 8080;
	config.useSSL = useEncryption;
	config.zone = "BasicExamples";
	
	// Create the SmartFox client instance
	var sfs = new SFS2X.SmartFox(config);
	
	// Add connection event listener
	sfs.addEventListener(SFS2X.SFSEvent.CONNECTION, onConnection, this);
	
	// Connect to SmartFoxServer 2X
	sfs.connect();
	
	// Handle connection event
	function onConnection(evtParams)
	{
		console.log(evtParams.success);
	}
})();

In Unity WebGL the choice between the encrypted (WS) and non-encrypted (WSS) connection is based on a boolean passed to the SmartFox class constructor.

public class ConnectionExample : MonoBehaviour
{
	private SmartFox sfs;
	
	// Use a flag to easily switch cryptography on and off
	private bool useEncryption = true;
	
	void Start()
	{
		// Create the SmartFox client instance
		sfs = new SmartFox(useEncryption ? UseWebSocket.WSS : UseWebSocket.WS);
		
		// Add connection event listener
		sfs.AddEventListener(SFSEvent.CONNECTION, OnConnection);
		
		// Create configuration object
		ConfigData config = new ConfigData();
		config.host = "mydomain.com";
		config.port = useEncryption ? 8443 : 8080;
		config.zone = "BasicExamples";
		
		// Connect
		sfs.Connect(config);
	}
	
	// Handle connection event
	private void OnConnection(BaseEvent evt)
	{
		Debug.Log(evt.Params["success"]);
	}
}

For a full connection example in Unity, featuring conditional compilation for multiple platforms support, encryption activation and more, please check this tutorial.

» 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 AdminTool's Server Configurator module.

For Linux / macOS users, this requires running the server as root, since port 843 is within the 0-1024 range.

» Unity WebGL

The SmartFox.InitCrypto method is not available when building for WebGL: use WSS connection as discussed before.