Version: 2019.3
NetworkServerSimple
UnityWebRequest

Multiplayer Encryption Plug-ins

Unity Multiplayer can make use of an encryption Plug-in, so that all data you send over the network passes through the encryption plug-in before being sent. This allows you to protect your game against cheating by packet manipulation and attacks on your dedicated game servers.

Unity Multiplayer does not have a built-in encryption plug-in, so you must provide your own plug-in that implements an encryption algorithm, and which implements the mandatory functions listed further below.

The following diagram illustrates how Unity Multiplayer uses your encryption Plug-in, if you provide one.

The data flow when using an encryption plug-in with Unity Multiplayer
The data flow when using an encryption plug-in with Unity Multiplayer

How to use an Encryption Plug-in

To instruct your game or app to use an encryption Plug-in, you must call UnityEngine.Networking.NetworkTransport.LoadEncryptionLibrary(path) where path is the path to your compiled plugin. Typically on Windows it will be string.Format("{0}/Plugins/UnetEncryption.dll", Application.dataPath).

When you call this function, Unity checks the file exists, and that it implements all the mandatory functions (listed below). These are the functions that Unity’s multiplayer system itself will call. If you create your own encryption plugin, you will likely need to add more functions that you call from your C# code. For example, to initialise your algorithm or to provide your plug-in with key values. You can do this in the usual way for native plugins callable from C#.

Note: The location of a plugin in the built version of your game is not necessarily the same as in your Assets folder, and it may differ between target platforms. You may need to write code that detects the current runtime environment and select the correct path based on that.

You can get a sample encryption plugin and a sample Unity project using it from Unity’s GitHub. This is provided to illustrate a starting point for implementing your own Plug-in.

Mandatory Functions

Any encryption Plug-in you create or use must provide the following functions. Unity will fail to load the plug-in if it does not define these. These are the functions that will be called by the Unity runtime itself. Plugins will typically provide additional functions to be called from the user’s C# code, for example for registering keys.

To Encrypt Data

int UNetEncryptionLib_Encrypt(
    void * payload,
    int payload_len,
    void * dest,
    int & dest_len,
    int connection_id,
    bool isConnect);

This function performs the encryption. This is called by Unity’s networking whenever a packet is to be sent over the network.

Parameters

  • payload is the data to be encrypted.
  • payload_len is the length of the payload buffer, in bytes.
  • dest is the buffer into which the plugin should write the encrypted data.
  • dest_len is the capacity in bytes of the dest buffer. The plugin must replace this value with the number of bytes actually written into dest.
  • connection_id is the local identifier of the connection.
  • isConnect is true if this packet is a connection request. When this is true, the plugin must have been told ahead of time (by game code) which key to use. When this is false, it is expected that the plugin already has a mapping from this value to a key to use. See the example plugin for an implementation.

Return value

Encrypt must return zero on success. On any other return value, the runtime will drop the packet without sending it.

To Decrypt Data

int UNetEncryptionLib_Decrypt(
    void * payload,
    int payload_len,
    void * dest,
    int & dest_len,
    int & key_id);

This function performs the decryption. This is called by Unity networking whenever a packet is received from the network.

Parameters

  • payload is the received packet.
  • payload_len is the length in bytes of the payload buffer.
  • dest is the buffer into which the plugin should write the decrypted data.
  • dest_len is the capacity in bytes of the dest buffer. The plugin must replace this value with the number of bytes actually written into dest.
  • key_id is an integer identifier. The plugin should write a value that uniquely identifies the decryption key used. On the server this value will be passed back into ConnectionIdAssigned if a new connection is accepted.

Return value

Decrypt must return zero on success. On any other return value, the packet is dropped without being processed further.

SafeMaxPacketSize

unsigned short UNetEncryptionLib_SafeMaxPacketSize(
    unsigned short mtu);

You should call this function from your game to modify ConnectionConfig.PacketSize (also known as the maximum transmission unit, or MTU) before calling NetworkTransport.AddHost.

For example, your game might normally use an MTU of 1000 bytes. If ConnectionConfig.PacketSize is set to 1000 bytes before passing it into NetworkTransport.AddHost (via HostConfig.DefaultConfig), then the NetworkTransport layer will send no more than 1000 bytes of cleartext in a single packet.

An encryption plugin will typically add some overhead due to header information placed before the payload, as well as rounding-up the payload to an encryption block size. For example, if you are sending 18 bytes of cleartext, and the plug-in needs to add 49 bytes of header and using AES to encrypt data with a block size of 16 bytes, then the algorithm would produce a packet of 81 bytes (18 bytes of cleartext rounds up to 32 bytes of ciphertext, and then an additional 49 bytes of header).

Unity calls this function to ensure that packets that are about to be sent do not go over the limit of what’s possible to send, given the network MTU and your encryption algorithm’s ciphertext expansion and padding.

Parameters

  • mtu is the maximum transmission unit. The largest packet size that you want the plugin to generate.

Return value

The maximum amount of cleartext that should be provided to a single call to Encrypt, in order for the plugin to generate packets not larger than the MTU.

You must set the maximum packet size in your connection config to tell Unity Multiplayer to split data up so that it fits your encryption requirements. If you notice that some of your messages do not successfully transmit over the network, it could be because they were dropped due to exceeding the maximum packet size.

ConnectionIdAssigned

void UNetEncryptionLib_ConnectionIdAssigned(
    int key_id,
    unsigned short connection_id);

This is called on the server when a new connection has been accepted and an ID assigned to it.

Parameters

  • key_id The key identifier, which was written by the corresponding previous call to Decrypt for this packet.
  • connection_id The connection id that will be used from this point forth. In particular, as a parameter to subsequent Encrypt calls when sending packets back to the client.
NetworkServerSimple
UnityWebRequest